Your VPS boots, and your app is gone. You started it months ago with nohup, maybe under tmux, and the first time it crashed you did not notice for days. Reboot? Same story. The fix is comfortingly boring: hand the job to systemd. It starts your process at boot, restarts it when it dies, and keeps its logs. No more babysitting.
Write the unit file
A systemd service unit is a single INI-style file. It lives at /etc/systemd/system/<name>.service, where <name> is whatever you want to call the service. Create it:
[Unit]
Description=My Node web app
[Service]
Type=simple
User=deploy
WorkingDirectory=/opt/myapp
ExecStart=/usr/bin/node /opt/myapp/server.js
Environment="PORT=8080"
Restart=on-failure
RestartSec=3
[Install]
WantedBy=multi-user.target
Three sections do the work. [Unit] carries the description. [Service] holds the runtime settings. [Install] makes the service start at boot. The important lines:
Type=simpleis the default. With it,ExecStartmust run in the foreground — never daemonize or fork inside it. systemd treats that foreground process as the service.ExecStart=is the command to run. It must be an absolute path to the executable. Write/usr/bin/node, notnode— runwhich nodeif you are not sure of the path.User=runs the process as that user instead of root.WorkingDirectory=sets the working folder, so relative paths behave.Environment="KEY=value"sets a variable (the quotes matter).Restart=on-failurebrings the service back when it crashes — the recommended setting for a long-running process. AddRestartSec=3to pause three seconds first; the default restart delay is 100 ms.
Enable and start
WantedBy=multi-user.target in [Install] means "start this at boot." Turning that on is one command:
sudo systemctl enable --now myapp
enable --now both enables start-at-boot and starts the service immediately. From here it survives reboots and crashes on its own.
Reload after any edit
Editing a unit file is not enough — systemd caches units. After every change, run:
sudo systemctl daemon-reload
then sudo systemctl restart myapp to apply it.
Check it is alive
systemctl status myapp
This shows whether the service is active, since when, its recent log lines, and a hint if it keeps dying.
Read the logs
Whatever your process writes to stdout and stderr lands in the systemd journal. Read it with:
journalctl -u myapp
Add -f to follow it live:
journalctl -u myapp -f
That one command replaces your old tail -f nohup.out searches.
Now your script is a real service. It starts at boot, restarts itself on failure, and logs where you can actually find it. Rinse and repeat for every app on the box — then stop thinking about it.
