Writing Proper systemd Service Files
Every time I deploy a long-running process on Linux, I write a systemd service file. Here is my approach.
Basic Template
[Unit]
Description=My Application
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=app
Group=app
WorkingDirectory=/opt/myapp
ExecStart=/opt/myapp/bin/server
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
Important Options
Restart Policy
Restart=on-failure # Restart only on non-zero exit
RestartSec=5 # Wait 5 seconds between restarts
StartLimitBurst=3 # Max 3 restarts...
StartLimitIntervalSec=60 # ...within 60 seconds
Environment Variables
# Inline
Environment=NODE_ENV=production PORT=3000
# From file (better for secrets)
EnvironmentFile=/opt/myapp/.env
Resource Limits
LimitNOFILE=65535 # Max open files
MemoryMax=512M # Kill if exceeds 512MB
CPUQuota=50% # Max 50% of one CPU core
Security Hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/opt/myapp/data
Useful Commands
# Reload after editing service file
systemctl daemon-reload
# Enable and start
systemctl enable --now myapp
# View logs
journalctl -u myapp -f --no-pager
# Check why a service failed
systemctl status myapp
journalctl -u myapp --since "5 minutes ago"
Common Mistakes
- Forgetting
daemon-reloadafter editing the service file - Running as root when the app does not need it
- Using
Type=forkingfor apps that stay in foreground (usesimple) - Not setting
Restart— your app will stay down after a crash
A well-written service file is the difference between a service that quietly recovers and one that pages you at 3 AM.