Dev Notes

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

  1. Forgetting daemon-reload after editing the service file
  2. Running as root when the app does not need it
  3. Using Type=forking for apps that stay in foreground (use simple)
  4. 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.