systemd services explained
Manage, debug and write systemd units — the thing that runs your long-lived processes.
systemd is the init system of most Linux distributions: it starts services at boot and keeps them running. Most "how do I run this in the background" questions have a systemd answer.
Managing services
systemctl status myapp # running? recent log lines?
systemctl start myapp
systemctl stop myapp
systemctl restart myapp
systemctl reload myapp # re-read config without dropping connections
systemctl enable myapp # start at boot
systemctl disable myapp # do not start at boot
systemctl list-units --failed # what is broken?Reload vs restart: reload re-reads configuration in place (no downtime) where the service supports it; restart stops and starts (brief downtime). Prefer reload for web servers.
Writing a unit
/etc/systemd/system/myapp.service:
[Unit]
Description=My App
After=network.target postgresql.service
[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=/etc/myapp/env
ExecStart=/usr/bin/node /opt/myapp/server.js
Restart=on-failure
RestartSec=5
# hardening
NoNewPrivileges=true
PrivateTmp=true
[Install]
WantedBy=multi-user.targetThen:
systemctl daemon-reload # after editing any unit file
systemctl enable --now myapp
systemctl status myapp --no-pagerThe settings that matter most
User=/Group=— never run as root if you can avoid it.EnvironmentFile=— keep secrets out of the unit file itself (which is world-readable).Restart=on-failure— auto-recover crashes.After=— start order dependencies (e.g. after the database).Type=—simplefor a foreground process;forkingfor one that daemonises.
Debugging a service that will not start
systemctl status myapp --no-pager # the first place to look
journalctl -u myapp -n 100 --no-pager # the actual error
journalctl -u myapp -f # liveCommon causes: wrong ExecStart path, missing permissions on the working directory, an environment file that does not exist, or a port already in use.
Timers (cron, the systemd way)
systemd can replace cron with timers. A .timer unit triggers a matching .service. Advantages: logging via the journal, and dependency ordering. For simple scheduled jobs, classic cron is still perfectly fine — use whichever you will remember.
Related reading