Skip to content

How to Create a systemd Service

Key idea:

systemd is the init system on every modern Linux. A service unit = .service file describing how to start/stop/restart a daemon. Replaces supervisord, pm2 (for Node), rc.d. Auto-start on boot, auto-restart on crash, journalctl for logs, systemctl for control. Minimal unit — 10 lines.

Below: step-by-step, working examples, common pitfalls, FAQ.

Step-by-Step Setup

  1. Create /etc/systemd/system/myapp.service
  2. [Unit] section: Description, After=network.target
  3. [Service] section: ExecStart, User, WorkingDirectory, Restart=on-failure
  4. [Install] WantedBy=multi-user.target
  5. systemctl daemon-reload — reload units
  6. systemctl enable myapp — auto-start on boot
  7. systemctl start myapp + systemctl status
  8. Logs: journalctl -u myapp -f (live tail)

Working Examples

ScenarioConfig
Simple Node.js service[Unit] Description=My App After=network.target [Service] Type=simple User=nodejs WorkingDirectory=/opt/myapp ExecStart=/usr/bin/node /opt/myapp/server.js Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target
Python with venv[Service] Type=simple User=app WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/venv/bin/python /opt/myapp/app.py Environment="PATH=/opt/myapp/venv/bin" Restart=on-failure
Systemd hardening (sandboxing)[Service] NoNewPrivileges=true PrivateTmp=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/log/myapp
Timer (cron-like)# /etc/systemd/system/backup.timer [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true [Install] WantedBy=timers.target
Reload config without restartExecReload=/bin/kill -HUP $MAINPID # systemctl reload myapp

Common Pitfalls

  • ExecStart with relative path — "not found". Always absolute /usr/bin/node
  • Environment variables: Environment="KEY=value", not bash syntax
  • User=root — anti-pattern. Create a dedicated user: useradd -r -s /bin/false nodejs
  • Logs don't write to a file — they go to journald: journalctl -u myapp
  • Missing systemctl daemon-reload after a unit change → stale config

Learn more

Frequently Asked Questions

systemd vs pm2 / supervisord?

systemd — built-in Linux, zero deps. pm2 — specialized for Node.js (cluster, zero-downtime reload). For simple apps — systemd.

Which restart policy?

on-failure (restart on non-zero exit) — standard. always — restart even on normal exit (useful for daemons). no — manual only.

How to graceful shutdown?

<code>TimeoutStopSec=30s</code> — systemd waits 30 s before SIGKILL. App must handle SIGTERM and exit cleanly.

Logs get huge — rotation?

journald auto-rotates. Settings: <code>/etc/systemd/journald.conf</code> → SystemMaxUse=1G, MaxRetentionSec=30d.