Skip to main content
DevOps Insightsguides & answers

Interactive tool

A systemd service for your program

Answer a few questions and get a unit file that runs your program as its own user, restarts it on failure and sandboxes it, plus the commands to check it with systemd-analyze before you enable it.

Runs in your browser · nothing is sent anywhere

api.service

[Unit]
Description=Example API server
Wants=network-online.target
After=network-online.target

[Service]
Type=exec
User=api
WorkingDirectory=/opt/api
ExecStart=/opt/api/bin/server --port 8080
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/api

[Install]
WantedBy=multi-user.target

The link holds every field of the form above. Remove passwords and tokens before you send it.

Install, check and start it

sudo install -m 644 api.service /etc/systemd/system/
sudo systemd-analyze verify /etc/systemd/system/api.service
sudo systemctl daemon-reload
sudo systemctl enable --now api
systemctl status api
journalctl -u api -f
systemd-analyze security api

What a unit file is

A unit file tells systemd, the service manager on most Linux servers, how to run a program as a service: the command, which user it runs as, and what to do when it stops. systemd then starts it at boot, restarts it if it crashes and collects its output in the journal.

Using it

Give the full path to your program and a user to run it as. Read the warnings: each is a mistake that would stop the service or make it less safe. Then install the file in /etc/systemd/system, the directory for units created by the administrator, check it with systemd-analyze verify and enable it.

If the service will not start, journalctl -u with its name shows why. With sandboxing on, the usual cause is a directory it needs to write to that is not in the writable paths.

What this checks

  • Builds a service unit from your answers, using directives checked against the systemd manual, and warns about relative paths, running as root, secrets in the environment and sandboxing that will block your program.

What it cannot know

  • Run your program or know what it needs: which paths it writes, whether it signals readiness, or what sandboxing it tolerates.
  • Check that the user, paths and files exist on your server.

Check it for real

sudo systemd-analyze verify /etc/systemd/system/<name>.service
systemd-analyze security <name>

verify loads the unit and prints any errors; security scores the sandboxing from 0 to 10, where lower is tighter. Neither tests the program itself, so watch journalctl -u <name> after starting it. systemd-analyze(1)

Why these defaults

Type=exec. With simple, systemd reports the start as successful as soon as it has forked, even if the program then cannot be executed. With exec it waits until the program has actually started, so a wrong path fails the start. The systemd manual recommends exec for long-running services.

Sandboxing. ProtectSystem=strict makes the whole filesystem read-only for the service except the paths you allow, ProtectHome hides home directories, PrivateTmp gives it its own /tmp, and NoNewPrivileges stops it gaining privileges through setuid programs. systemd-analyze security scores the result from 0 to 10, lower meaning tighter.

Secrets. The systemd manual says environment variables are not suitable for passing secrets: they are visible to unprivileged clients and inherited by child processes. Use LoadCredential= for passwords and keys; the program reads them from files under $CREDENTIALS_DIRECTORY.

Questions people ask about this

Where do I put a systemd service file?

In /etc/systemd/system, which the systemd manual lists as the place for units created by the administrator. Run systemctl daemon-reload after adding or changing a file there, then systemctl enable --now with its name to start it now and at every boot.

Should I use Type=simple or Type=exec?

exec, for most long-running programs. With simple, systemd treats the service as started the moment it forks, so a wrong path still looks like a successful start. With exec it waits until the program has been executed. The systemd manual recommends exec for long-running services.

How do I give a systemd service a password safely?

Not through Environment= or an EnvironmentFile: the systemd manual says environment variables are not suitable for passing secrets. Store the secret in a file only root can read, add LoadCredential=name:/path/to/file to the unit, and have the program read it from $CREDENTIALS_DIRECTORY/name.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it