systemd service generator

Fill in how your program runs and get a .service file that systemd reads as written, with the install commands and an explanation of every field. Everything is written in your browser.

The file becomes <name>.service in /etc/systemd/system.
An absolute path and its arguments. Quote an argument with spaces; no shell runs, so pipes and && need /bin/sh -c '…'.
The program stays in the foreground; systemd counts it as started right away.
Empty runs it as root. A dedicated user is safer.
Absolute path the program starts in. Empty: the user's home, or / for root.
One NAME=value per line. Values are written literally: $ and % are not expanded.
A file of NAME=value lines read at every start, for example secrets kept out of the unit.
Units, separated by spaces, that must start first. network-online.target is also wanted, so the network is up.
Restarted after a crash, a non-zero exit or a timeout, not after a clean exit.
NoNewPrivileges, PrivateTmp, ProtectSystem=full (/usr, /boot and /etc read-only) and protected kernel settings. Turn it off if the program writes under /etc or /usr.
Adds [Install] WantedBy=multi-user.target, so enable starts it at every boot.

Your unit

myapp.service
# myapp.service: My app
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=My app
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --port 8080
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes

[Install]
WantedBy=multi-user.target

Hand off to an agent

A Markdown task for a coding agent: the files, the findings, the limits and fixed guardrails. Values that look like secrets are masked. It is built on this page and sent nowhere.

How the agent handoff works

Install and start it

Run these on the server in the folder where you saved the file. systemd-analyze verify checks it before systemd loads it.

install-commands.txt
sudo install -m 0644 myapp.service /etc/systemd/system/myapp.service
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service
journalctl -u myapp.service -f

Runs on a schedule instead? Convert a cron line to a systemd timer

What it does

It writes a systemd service unit for a program you want the server to keep running: a web app, a worker, an agent or a tunnel. You choose the command, the account, the folder, the environment, when to restart and what to start after, and the page shows the unit and the commands that install it.

How it works

  1. The unit is written in your browser by @anaroq/linux, the engine behind our other Linux tools. Each value is written so systemd reads it literally: % is doubled, $ in the command is doubled, and an argument with spaces or quotes is quoted.
  2. A field that would break the file, such as a line break, a relative command or a unit name with a space, is refused next to the field instead of being written.
  3. The same unit files pass systemd-analyze verify in our tests, on Debian 12, Ubuntu 22.04 and Ubuntu 24.04.

What each line does

Description=
The name systemctl status and the journal show.
Wants= and After=
After= orders the start; Wants= also pulls the unit in. Together on network-online.target they wait for the network.
Type=
How systemd knows the program has started: simple and exec at once, oneshot when it exits, notify when it says so.
User= and Group=
The account the program runs as. Without them it runs as root.
WorkingDirectory=
The folder the program starts in.
Environment=
One variable per line, in quotes when the value has spaces. systemd does not expand $ or ~ in it.
EnvironmentFile=
A file of variables read at every start; its values win over Environment=. With -, a missing file is skipped.
ExecStart=
The command, with an absolute path. systemd splits the words itself and runs no shell.
Restart= and RestartSec=
When systemd starts the program again, and how long it waits first.
NoNewPrivileges= … RestrictSUIDSGID=
The basic sandbox: no gaining privileges, a private /tmp, read-only system folders and kernel settings, no setuid files.
WantedBy=multi-user.target
The [Install] section: systemctl enable links the unit there, so it starts at boot.

Example

A Node.js app run by its own user from /opt/myapp, with two variables in the unit and its secrets in an optional environment file:

myapp.service
# myapp.service: My Node.js app
# Generated by @anaroq/linux 1.0.0 (ANAROQ).
[Unit]
Description=My Node.js app
Wants=network-online.target
After=network-online.target

[Service]
Type=simple
User=myapp
Group=myapp
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
Environment=PORT=3000
EnvironmentFile=-/etc/myapp/myapp.env
ExecStart=/usr/bin/node server.js
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=full
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictSUIDSGID=yes

[Install]
WantedBy=multi-user.target

The commands that install and start it

install-commands.txt
sudo install -m 0644 myapp.service /etc/systemd/system/myapp.service
sudo systemd-analyze verify /etc/systemd/system/myapp.service
sudo systemctl daemon-reload
sudo systemctl enable --now myapp.service
systemctl status myapp.service
journalctl -u myapp.service -f

Limits

  • It writes system units in /etc/systemd/system. User units (systemctl --user) and templates ([email protected]) are not covered.
  • The sandbox is a conservative baseline. systemd-analyze security myapp.service scores the unit and lists what more you can restrict.
  • systemd-analyze verify checks the file, not your program: it cannot tell whether the command works or the user exists.
  • Socket activation, resource limits and timeouts are left at systemd's defaults.

Runs on a schedule instead? Convert a cron line to a systemd timer

Sources

  1. systemd.service(5)
  2. systemd.exec(5)
  3. systemd.unit(5)
  4. systemd.timer(5)
  5. systemd-analyze(1)

Updated

Next step

cron to systemd timer converter

A free public tool by ANAROQ, a company building compute infrastructure. What ANAROQ is building