Understanding systemd Unit Files: Complete Configuration Guide

Master the art of systemd unit file configuration. This comprehensive guide covers all unit file types, syntax, directives, and best practices for creating robust systemd configurations.

systemd Unit File Structure /etc/systemd/system/myservice.service [Unit] Description=My Service After=network.target Requires=network.target Wants=sshd.service Before=multi-user.target Documentation=man:myservice(8) [Service] Type=simple User=myuser ExecStart=/usr/bin/myservice Restart=on-failure RestartSec=10 Environment="KEY=value" [Install] WantedBy=multi-user.target Alias=myservice-alias.service Also=other-service.service [Unit] - Metadata & dependencies [Service] - Service configuration [Install] - Installation info
Structure of a systemd service unit file showing the three main sections

What are systemd Unit Files?

Unit files are the configuration files that define how systemd should manage resources. Each unit file describes a single resource such as a service, socket, device, mount point, or timer.

  • Declarative configuration: Describe what you want, not how to do it
  • Standardized format: INI-style configuration files
  • Multiple types: Services, sockets, timers, mounts, swaps, etc.
  • Location-based: Different directories for different purposes
  • Drop-in overrides: Partial configuration overrides supported

1. Unit File Types

Service Units
.service
Manage daemons, services, and processes. Most common unit type for running applications.
Socket Units
.socket
Manage IPC or network sockets. Allows socket-based activation of services.
Timer Units
.timer
Schedule tasks to run at specific times. Systemd's replacement for cron.
Mount Units
.mount
Control filesystem mount points. Automatically generated from /etc/fstab.
Path Units
.path
Monitor filesystem paths. Activate services when files change.
Swap Units
.swap
Manage swap devices or files. Automatically generated from /etc/fstab.
Target Units
.target
Group other units. Used for synchronization (like runlevels).
Slice Units
.slice
Manage resource allocation (cgroups). For limiting CPU, memory, IO.

2. Unit File Locations & Hierarchy

Directory Purpose Priority Example /etc/systemd/system/ System administrator units Highest Custom services, overrides /run/systemd/system/ Runtime units Medium Generated at runtime, temporary /usr/lib/systemd/system/ Packaged units Lowest Installed by distribution packages /etc/systemd/system/*.d/ Drop-in directories Overrides Partial configuration overrides

Drop-in Directory Example

# Original unit file
/usr/lib/systemd/system/nginx.service

# System administrator override
/etc/systemd/system/nginx.service.d/custom.conf

# Drop-in file content
[Service]
Environment="NGINX_WORKER_PROCESSES=4"
LimitNOFILE=65536
RestartSec=5

3. Service Unit File Deep Dive

Complete Service Unit Example

# /etc/systemd/system/webapp.service
[Unit]
Description=Python Web Application
Documentation=https://example.com/docs
After=network.target postgresql.service
Wants=postgresql.service
Requires=network.target
Before=multi-user.target
ConditionPathExists=/opt/webapp/config.py
AssertPathIsReadWrite=/var/log/webapp

[Service]
Type=simple
User=webapp
Group=webapp
WorkingDirectory=/opt/webapp
Environment="DATABASE_URL=postgresql://localhost/webapp"
EnvironmentFile=/etc/default/webapp
ExecStart=/usr/bin/python3 /opt/webapp/app.py
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -TERM $MAINPID
Restart=on-failure
RestartSec=10
TimeoutStopSec=30
TimeoutStartSec=30
StartLimitInterval=100
StartLimitBurst=10
LimitNOFILE=65536
LimitNPROC=4096
StandardOutput=journal
StandardError=journal
SyslogIdentifier=webapp

# Security hardening
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/lib/webapp
ReadOnlyPaths=/etc/webapp

[Install]
WantedBy=multi-user.target
Alias=webapp.service
Also=webapp-socket.socket

[Unit] Section Directives

Directive Description Example Description Human-readable description Description=Web Application Server Documentation Documentation URLs Documentation=man:nginx(8) After Start after these units After=network.target Before Start before these units Before=multi-user.target Requires Strong dependency Requires=postgresql.service Wants Weak dependency Wants=network-online.target Conflicts Cannot run with these units Conflicts=old-service.service Condition* Conditional startup ConditionPathExists=/etc/config Assert* Assertion checks AssertPathIsDirectory=/var/lib/app

[Service] Section Directives

Directive Description Example Type Service type (simple, forking, oneshot, etc.) Type=simple User/Group Run as specific user/group User=nginx ExecStart Command to start service ExecStart=/usr/sbin/nginx ExecStop Command to stop service ExecStop=/bin/kill $MAINPID Restart When to restart Restart=on-failure RestartSec Wait before restarting RestartSec=5s Environment Set environment variables Environment="PORT=8080" WorkingDirectory Change working directory WorkingDirectory=/var/www Limit* Resource limits LimitNOFILE=65536 StandardOutput Where to send stdout StandardOutput=journal

4. Advanced Unit File Examples

Socket Activation Unit

# /etc/systemd/system/myapp.socket
[Unit]
Description=MyApp Socket
PartOf=myapp.service

[Socket]
ListenStream=0.0.0.0:8080
Accept=true
SocketUser=myapp
SocketGroup=myapp
SocketMode=0660

[Install]
WantedBy=sockets.target

# /etc/systemd/system/myapp@.service
[Unit]
Description=MyApp Instance %i

[Service]
ExecStart=/usr/bin/myapp --instance %i
StandardInput=socket

Timer Unit with Calendar Expressions

# /etc/systemd/system/backup.timer
[Unit]
Description=Daily backup timer

[Timer]
OnCalendar=daily
Persistent=true
RandomizedDelaySec=1h
AccuracySec=1min
Unit=backup.service

[Install]
WantedBy=timers.target

# Calendar expression examples
# OnCalendar=*-*-* 02:00:00      # Daily at 2 AM
# OnCalendar=Mon,Fri *-*-* 10:00 # Monday and Friday at 10 AM
# OnCalendar=*-*-15 00:00        # 15th of every month
# OnCalendar=*-12-25 00:00       # December 25th every year

Path Unit for File Monitoring

# /etc/systemd/system/config-watcher.path
[Unit]
Description=Monitor config file changes

[Path]
PathChanged=/etc/myapp/config.conf
PathModified=/etc/myapp/
Unit=config-reloader.service

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/config-reloader.service
[Unit]
Description=Reload configuration

[Service]
Type=oneshot
ExecStart=/usr/bin/myapp --reload-config

5. Unit File Management Tools

# View unit files
systemctl cat nginx.service # View complete unit
systemctl show nginx.service # Show all properties
systemd-analyze cat-config nginx.service # Show with drop-ins
# Create/edit units
systemctl edit nginx.service # Create drop-in override
systemctl edit --full nginx.service # Edit full unit file
systemd-delta # Show overridden units
# Validate units
systemd-analyze verify nginx.service # Validate syntax
systemd-analyze unit-paths # Show unit search paths
test -f /usr/lib/systemd/system/nginx.service && echo "Exists"
# Manage drop-ins
mkdir -p /etc/systemd/system/nginx.service.d/
cat > /etc/systemd/system/nginx.service.d/custom.conf << EOF
[Service]
Environment="CUSTOM=value"
EOF
systemctl daemon-reload # Always reload after changes

6. Best Practices & Common Patterns

Validation
Always validate unit files with systemd-analyze verify before deploying. Check for syntax errors and undefined dependencies.
Use Drop-ins
Never modify packaged unit files directly. Use drop-in directories in /etc/systemd/system/*.d/ for overrides.
Section Order
Maintain consistent section order: [Unit], [Service]/[Socket]/[Timer], [Install]. Keep directives alphabetically ordered within sections.
Debugging
Use systemctl status -l and journalctl -u for debugging. Enable debug logging with StandardOutput=journal+console.

Unit File Creation Checklist

  • Use descriptive Description with application name
  • Set proper dependencies (After, Requires, Wants)
  • Specify User and Group for security
  • Set WorkingDirectory for consistent paths
  • Configure Restart and RestartSec for resilience
  • Set appropriate resource limits (LimitNOFILE, LimitNPROC)
  • Use Environment or EnvironmentFile for configuration
  • Specify ExecStop for clean shutdown
  • Set WantedBy in [Install] section
  • Test with systemd-analyze verify
Common Unit File Mistakes to Avoid:
1. Missing Type= directive: Defaults to Type=simple which may not be correct
2. Forgetting daemon-reload: Always run systemctl daemon-reload after changes
3. Absolute paths required: All paths in ExecStart must be absolute
4. Incorrect dependencies: Circular dependencies or missing requirements
5. No ExecStop: Services may not stop cleanly
6. Missing User/Group: Running as root is a security risk
7. Hardcoded values: Use environment variables for configuration
8. No resource limits: Can lead to system resource exhaustion
9. Incorrect socket permissions: Socket units need proper SocketUser/SocketGroup
10. Not testing: Always test units in a staging environment first

7. Template Units & Instance Units

Template Unit Example

# /etc/systemd/system/app@.service (Template)
[Unit]
Description=Application Instance %i

[Service]
Type=simple
User=appuser
ExecStart=/usr/bin/app --instance %i --port 80%i
Environment="INSTANCE=%i"
Restart=on-failure

[Install]
WantedBy=multi-user.target

# Create instances
systemctl start app@1.service    # Instance 1, port 801
systemctl start app@2.service    # Instance 2, port 802
systemctl start app@web.service  # Instance "web", port 80web

Template Unit Patterns

# Common template patterns
app@%i.service                    # Numeric instances
app@%I.service                    # Instance identifier
app-%i.service                    # Alternative naming
app@%H.service                    # Hostname-based
app@%m.service                    # Machine ID-based

# Special specifiers
%n = full unit name              # app@1.service
%N = escaped unit name           # app\x401.service
%p = prefix                      # app
%i = instance name               # 1, web, etc.
%j = removed suffix              # Depends on unit type
%g = last component of %j

Getting Started with Unit Files

Follow this learning path to master systemd unit files:

  1. Start with services: Learn .service unit files first
  2. Study packaged units: Examine units from your distribution
  3. Create simple units: Make a basic service for a script
  4. Add dependencies: Learn After, Requires, Wants
  5. Experiment with types: Try simple, forking, oneshot
  6. Use drop-ins: Practice overriding packaged units
  7. Learn other types: Explore sockets, timers, paths
  8. Master templates: Create instance-based services
  9. Implement security: Add User, PrivateTmp, etc.
  10. Automate validation: Use systemd-analyze in scripts

Master systemd Unit File Configuration

systemd unit files provide a powerful, declarative way to manage system resources. By understanding the structure, directives, and best practices, you can create robust, maintainable system configurations.

Remember: Good unit files are like good code - they should be clear, maintainable, and well-documented. Use drop-ins for customizations, validate your configurations, and always test before deploying to production.

Next Steps: Start by examining existing unit files on your system. Create a simple service unit for a custom script. Experiment with socket activation and timer units. As you gain experience, you'll appreciate the flexibility and power of systemd's unit file system.