D Darkless Help
Open the portal

Help Running your server Docker and apps

Run something on boot with systemd

Write a service file so your app starts at boot, restarts if it crashes, and logs to the journal, then read those logs.

3 min Updated 7 Nov 2026 Ubuntu, Debian, AlmaLinux

A program started from your SSH session stops when you log out. systemd can run it instead: at boot, in the background, restarted if it crashes, with its output saved. It's the same on Ubuntu, Debian and AlmaLinux.

Give the app its own user#

An app running as root can do anything if it's broken into. Make a user just for it, with no login. The example is myapp in /opt/myapp:

sudo useradd --system --home /opt/myapp --shell /usr/sbin/nologin myapp

Put the app's files in /opt/myapp and give them to that user:

sudo chown -R myapp:myapp /opt/myapp

Write the service file#

A service is a short file in /etc/systemd/system/, called by its name before .service:

sudo tee /etc/systemd/system/myapp.service <<'EOF'
[Unit]
Description=My app
After=network-online.target
Wants=network-online.target

[Service]
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
EnvironmentFile=-/etc/myapp.env
ExecStart=/opt/myapp/myapp --port 3000
Restart=on-failure
RestartSec=5
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target
EOF
LineWhat it does
After, WantsWaits for the network before starting
User, GroupRuns it as its own user, not root
WorkingDirectoryThe folder it starts in
EnvironmentFileReads passwords and tokens from a separate file. The - means fine if missing
ExecStartThe command. It needs the full path: find it with command -v node
Restart=on-failureStarts it again 5 seconds after a crash
NoNewPrivilegesStops it gaining more rights than it started with
WantedBy=multi-user.targetMeans start at boot

Start it#

sudo systemctl daemon-reload
sudo systemctl enable --now myapp

The first reads the new file; the second starts it now and at every boot. Then check: sudo systemctl status myapp should say active (running). Press q to leave.

CommandWhat it does
sudo systemctl restart myappRestarts it, after you change the app
sudo systemctl stop myappStops it until the next boot
sudo systemctl disable myappStops it starting at boot
sudo systemctl daemon-reloadRereads the .service file after you edit it. Restart after
sudo journalctl -u myapp -fFollows its log live. Ctrl+C to stop
sudo journalctl -u myapp -n 100 --no-pagerIts last 100 lines
sudo journalctl -u myapp --since "1 hour ago"Its log for the last hour

Keep secrets out of the service file#

Anyone on the server can read /etc/systemd/system/. Put passwords and tokens in the environment file, readable only by root:

sudo tee /etc/myapp.env <<'EOF'
DATABASE_URL=postgres://myapp:[email protected]/myapp
API_TOKEN=replace-me
EOF
sudo chmod 600 /etc/myapp.env

Restart the app to pick up changes to it.

If it won't start#

systemctl status shows the last lines of output, which usually say why.

It saysTry
Permission deniedmyapp can't read its files. Check ls -l /opt/myapp and chown again
No such file or directoryThe ExecStart path is wrong, or not a full path
start request repeated too quicklyIt crashes at once. Run it by hand to see why: sudo -u myapp /opt/myapp/myapp --port 3000

For a worked example with a real app, see Run a Node.js app or Discord bot.

Still stuck? Open a ticket and say which guide you followed.