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.
Your unit
# 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.
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.
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
- 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.
- 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.
- 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: 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
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
Related
Next step
A free public tool by ANAROQ, a company building compute infrastructure. What ANAROQ is building