Customizing systemd Services Without Forking: The Drop-in Snippet Pattern
Stop forking vendor systemd units. Drop-in snippets in /etc/systemd/system/<unit>.d/ let you override settings cleanly, survive package updates, and stay auditable with systemd-delta. Includes a worked sshd.example and the ExecStart= gotcha.
18 Sept 2025, 18:25 UTC

The Problem: Package Updates Eat Your Customizations
You've tuned sshd.service with a longer LoginGraceTime and a custom Environment variable. Then a routine apt upgrade or dnf update replaces /usr/lib/systemd/system/sshd.service and your changes vanish. The traditional workarounds — copying the unit to /etc/systemd/system/ or editing vendor files directly — both create maintenance debt: the former diverges from upstream bug fixes, the latter breaks on every package refresh.
How Drop-in Snippets Solve This
systemd's drop-in mechanism lets you overlay small configuration fragments on top of vendor units without touching the original file. Vendor units live in /usr/lib/systemd/system/ (managed by the package manager). Your overrides go in /etc/systemd/system/.d/*.conf. When systemd loads the unit, it merges the drop-ins in lexical filename order, with later files overriding earlier ones. The vendor unit remains pristine, so package updates apply cleanly while your customizations persist.
This replaces the legacy /etc/sysconfig/ and /etc/default/ side-files that many daemons still read. With drop-ins, systemctl show reflects the effective configuration, and systemd-delta makes drift visible across the whole system.
Safe Interactive Workflow: systemctl edit
The systemctl edit command creates /etc/systemd/system/.d/override.conf, opens your $EDITOR, and runs daemon-reload on save. This is the recommended entry point — it handles file placement, permissions, and reload atomically. For multiple concerns, create named files like 10-timeout.conf, 20-environment.conf so ordering is explicit and configuration-management tools (Ansible, Puppet) can manage each fragment independently.
Worked Example: Hardening sshd.service with Two Drop-ins
Assume you need to increase the login grace period and inject a custom environment variable for an internal audit tool. Run the following as root (or via sudo) on any systemd-based system (RHEL 7+, Debian 8+, Ubuntu 16.04+, Arch, Fedora).
# Create first drop-in for timeout
systemctl edit sshd.service
# In editor, add:
[Service]
LoginGraceTime=120
# Create second drop-in for environment
systemctl edit --force --full sshd.service
# This opens a full unit copy; add only the Environment line under [Service]
[Service]
Environment=AUDIT_TAG=prod-bastion
After saving each, systemd reloads automatically. Verify the merge:
systemctl show sshd.service -p LoginGraceTime,Environment
# Expected output:
# LoginGraceTime=2min
# Environment=AUDIT_TAG=prod-bastion
List all active drop-ins for auditing:
systemd-delta --type=extended sshd.service
# Shows each drop-in path and which keys it overrides
Trade-offs and Limitations
- Additive
ExecStart=: If a vendor unit definesExecStart=once, a drop-in with anotherExecStart=appends a second command — both run sequentially. To replace it, usesystemctl edit --fullto copy the entire unit, or ensure the vendor unit usesExecStartPre/Postfor the parts you want to keep. - Template instances: For
[contact removed], drop-ins underfoo@.service.d/apply to all instances; instance-specific overrides go under[contact removed].d/. This distinction trips up administrators regularly. - Cannot unset keys: To clear a vendor value, assign an empty string (
Environment=). There is no "remove" operation — a deliberate design choice to prevent silent regressions. - Vendor drop-ins: Packages may ship their own drop-ins in
/usr/lib/systemd/system/.d/. Local/etcdrop-ins win, but conflicts between vendor drop-ins resolve by lexical order, which varies by distribution. - Reload requirement: Manual file edits (outside
systemctl edit) needsystemctl daemon-reloadbeforesystemctl restart. Forgetting this is the most common operational error.
Check Your Work
Run systemd-delta --type=extended across all units to inventory every active override. For any customized service, systemctl show -p confirms the effective value. If a change doesn't appear, run systemctl daemon-reload and re-check — the old configuration is still loaded until reload completes.
Adopt the convention: one concern per drop-in file, named with a numeric prefix. Your future self (and the next package update) will thank you.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.