Documentation
How to use this tool, practical use cases, and technical notes.
Generating a production-ready systemd unit file takes under 5 minutes. Here is a complete walkthrough of every field, what it controls, and how to choose the right value.
Step 1 — Choose a Template (or Start Blank)
The tool offers five quick-start templates at the top of the configuration panel. Clicking a template pre-fills all fields with appropriate values for that service type. You can then customize any field. The templates available are:
Node.js web app — for Express, Fastify, NestJS, Next.js and similar Node runtimes
Python API — for Flask, FastAPI, Django + Gunicorn and similar Python web servers
Docker Compose — for starting a
docker compose upstack as a system serviceBackup job — for shell scripts or Python scripts that run once and exit
Static + Nginx — for Nginx configured to serve static files
If none of these match your use case, leave the defaults and fill in the fields manually.
Step 2 — Fill in the Configuration Fields
Service Name
The name used for the unit file filename and for systemctl commands. Use lowercase letters, numbers, and hyphens — no spaces.
Example Input | Resulting File | systemctl Command |
|---|---|---|
|
|
|
|
|
|
|
|
|
Description
A human-readable string that describes what the service does. Shown in systemctl status output and in journalctl log headers. Keep it concise but descriptive — this is the first thing a sysadmin sees when investigating a service.
ExecStart
The absolute path to the binary (and any arguments) that systemd will execute to start the service. This is the most critical field.
Runtime | Correct ExecStart Format | Find Binary With |
|---|---|---|
Node.js |
|
|
Python (Gunicorn) |
|
|
Python (direct) |
|
|
Bash script |
| N/A |
Docker Compose |
|
|
Nginx |
|
|
Important: Always use the full absolute path. Relative paths and shell aliases do not work in ExecStart. Use which <binary> on your server to confirm the correct path.
Run As User
Option | UID | When to Use | Security Risk |
|---|---|---|---|
| 33 (Debian/Ubuntu) | Web servers, APIs serving HTTP traffic | Low — unprivileged |
| 65534 | Services that need no filesystem write access | Lowest — most restricted |
| 0 | Services that genuinely require system-level access | High — use only when necessary |
Custom user | Variable | Dedicated service account (recommended for production) | Low if configured correctly |
Best practice: Create a dedicated system user for each service (sudo useradd --system --no-create-home myapp) and use that account. This limits blast radius if the service is compromised.
Service Type
This is the most commonly misconfigured field. Choosing the wrong type causes the service to be considered "started" at the wrong time, leading to dependency failures or infinite restart loops.
Type | Behavior | When to Use | Common Examples |
|---|---|---|---|
| Process started by | Long-running foreground processes | Node.js, Python Flask/FastAPI, most modern apps |
| Service forks a child process and the parent exits; systemd tracks the child | Traditional Unix daemons | Nginx, Apache, classic sysvinit-style daemons |
| Service runs once and exits; systemd waits for it to complete before proceeding | Initialization scripts, backup jobs, one-time tasks | Database migrations, backup scripts, setup tasks |
| Like | Services that take time to initialize before accepting connections | PostgreSQL, systemd-aware services |
| Execution delayed until all active jobs are dispatched | Services that should start last, after everything else | Low-priority cleanup or telemetry services |
After (Dependency)
Controls startup ordering — what systemd must start (or attempt to start) before this service is launched.
Target | Meaning | When to Use |
|---|---|---|
| Basic network interfaces are up | Any service that makes outbound network calls |
| Network is fully online and routable | Services that fail if the network is not reachable at startup |
| System has reached multi-user mode (all standard services running) | Services with no specific dependency |
| Docker daemon is running | Any service that depends on Docker |
| PostgreSQL is running | Application servers that require a database connection at startup |
Note: After= only controls ordering, not hard dependency. Use Requires= or Wants= if you need systemd to also ensure the dependency is running, not just started first.
Restart Policy
Policy | Restarts On | Does Not Restart On | Best For |
|---|---|---|---|
| Nothing | Everything | One-shot jobs, scripts you manage manually |
| Non-zero exit, signal, timeout | Clean exit (code 0) | Production web apps and APIs |
| Signals, watchdog timeout, core dumps | Clean or error exit | Services where crashes need recovery but normal exits don't |
| Everything including clean exit | Nothing | Services that should never be allowed to stay stopped |
| Clean exit only (code 0) | Failures | Unusual; rarely the right choice |
Working Directory
The directory systemd will chdir into before executing ExecStart. If your application loads relative config paths (e.g., ./config.json), this must point to your app's root directory.
Environment Variables
One KEY=VALUE pair per line. These are injected into the service process's environment. Sensitive values (database passwords, API keys) should ideally be stored in a separate environment file (EnvironmentFile=/etc/myapp/env) rather than directly in the unit file, to control permissions separately.
Step 3 — Read the Live Preview
The unit file preview updates in real time as you change any field. Review it for:
Correct
ExecStartabsolute pathExpected
UserandTypevaluesCorrect
After=target for your dependenciesRestartSec=5(auto-included) — the delay between restart attempts
Step 4 — Copy the Unit File
Click "Copy unit" to copy the generated .service file contents to your clipboard.
Step 5 — Deploy Using the Generated Commands
The "Enable & start" section generates the exact shell commands for your service name:
# Install unit file to /etc/systemd/system/my-app.service
sudo cp my-app.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable my-app
sudo systemctl start my-app
sudo systemctl status my-appCommand | What It Does |
|---|---|
| Installs the unit file to the correct location |
| Tells systemd to re-read all unit files (required after any change) |
| Creates symlinks so the service starts automatically at boot |
| Starts the service immediately (without waiting for reboot) |
| Verifies the service is active and shows recent log lines |
Useful Post-Deployment Commands
Task | Command |
|---|---|
View live service logs |
|
View last 100 log lines |
|
Stop the service |
|
Restart the service |
|
Reload config without restart |
|
Disable autostart at boot |
|
Check service file syntax |
|
Check all failed services |
|
Generating a production-ready systemd unit file takes under 5 minutes. Here is a complete walkthrough of every field, what it controls, and how to choose the right value.
Step 1 — Choose a Template (or Start Blank)
The tool offers five quick-start templates at the top of the configuration panel. Clicking a template pre-fills all fields with appropriate values for that service type. You can then customize any field. The templates available are:
Node.js web app — for Express, Fastify, NestJS, Next.js and similar Node runtimes
Python API — for Flask, FastAPI, Django + Gunicorn and similar Python web servers
Docker Compose — for starting a
docker compose upstack as a system serviceBackup job — for shell scripts or Python scripts that run once and exit
Static + Nginx — for Nginx configured to serve static files
If none of these match your use case, leave the defaults and fill in the fields manually.
Step 2 — Fill in the Configuration Fields
Service Name
The name used for the unit file filename and for systemctl commands. Use lowercase letters, numbers, and hyphens — no spaces.
Example Input | Resulting File | systemctl Command |
|---|---|---|
|
|
|
|
|
|
|
|
|
Description
A human-readable string that describes what the service does. Shown in systemctl status output and in journalctl log headers. Keep it concise but descriptive — this is the first thing a sysadmin sees when investigating a service.
ExecStart
The absolute path to the binary (and any arguments) that systemd will execute to start the service. This is the most critical field.
Runtime | Correct ExecStart Format | Find Binary With |
|---|---|---|
Node.js |
|
|
Python (Gunicorn) |
|
|
Python (direct) |
|
|
Bash script |
| N/A |
Docker Compose |
|
|
Nginx |
|
|
Important: Always use the full absolute path. Relative paths and shell aliases do not work in ExecStart. Use which <binary> on your server to confirm the correct path.
Run As User
Option | UID | When to Use | Security Risk |
|---|---|---|---|
| 33 (Debian/Ubuntu) | Web servers, APIs serving HTTP traffic | Low — unprivileged |
| 65534 | Services that need no filesystem write access | Lowest — most restricted |
| 0 | Services that genuinely require system-level access | High — use only when necessary |
Custom user | Variable | Dedicated service account (recommended for production) | Low if configured correctly |
Best practice: Create a dedicated system user for each service (sudo useradd --system --no-create-home myapp) and use that account. This limits blast radius if the service is compromised.
Service Type
This is the most commonly misconfigured field. Choosing the wrong type causes the service to be considered "started" at the wrong time, leading to dependency failures or infinite restart loops.
Type | Behavior | When to Use | Common Examples |
|---|---|---|---|
| Process started by | Long-running foreground processes | Node.js, Python Flask/FastAPI, most modern apps |
| Service forks a child process and the parent exits; systemd tracks the child | Traditional Unix daemons | Nginx, Apache, classic sysvinit-style daemons |
| Service runs once and exits; systemd waits for it to complete before proceeding | Initialization scripts, backup jobs, one-time tasks | Database migrations, backup scripts, setup tasks |
| Like | Services that take time to initialize before accepting connections | PostgreSQL, systemd-aware services |
| Execution delayed until all active jobs are dispatched | Services that should start last, after everything else | Low-priority cleanup or telemetry services |
After (Dependency)
Controls startup ordering — what systemd must start (or attempt to start) before this service is launched.
Target | Meaning | When to Use |
|---|---|---|
| Basic network interfaces are up | Any service that makes outbound network calls |
| Network is fully online and routable | Services that fail if the network is not reachable at startup |
| System has reached multi-user mode (all standard services running) | Services with no specific dependency |
| Docker daemon is running | Any service that depends on Docker |
| PostgreSQL is running | Application servers that require a database connection at startup |
Note: After= only controls ordering, not hard dependency. Use Requires= or Wants= if you need systemd to also ensure the dependency is running, not just started first.
Restart Policy
Policy | Restarts On | Does Not Restart On | Best For |
|---|---|---|---|
| Nothing | Everything | One-shot jobs, scripts you manage manually |
| Non-zero exit, signal, timeout | Clean exit (code 0) | Production web apps and APIs |
| Signals, watchdog timeout, core dumps | Clean or error exit | Services where crashes need recovery but normal exits don't |
| Everything including clean exit | Nothing | Services that should never be allowed to stay stopped |
| Clean exit only (code 0) | Failures | Unusual; rarely the right choice |
Working Directory
The directory systemd will chdir into before executing ExecStart. If your application loads relative config paths (e.g., ./config.json), this must point to your app's root directory.
Environment Variables
One KEY=VALUE pair per line. These are injected into the service process's environment. Sensitive values (database passwords, API keys) should ideally be stored in a separate environment file (EnvironmentFile=/etc/myapp/env) rather than directly in the unit file, to control permissions separately.
Step 3 — Read the Live Preview
The unit file preview updates in real time as you change any field. Review it for:
Correct
ExecStartabsolute pathExpected
UserandTypevaluesCorrect
After=target for your dependenciesRestartSec=5(auto-included) — the delay between restart attempts
Step 4 — Copy the Unit File
Click "Copy unit" to copy the generated .service file contents to your clipboard.
Step 5 — Deploy Using the Generated Commands
The "Enable & start" section generates the exact shell commands for your service name:
# Install unit file to /etc/systemd/system/my-app.service
sudo cp my-app.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable my-app
sudo systemctl start my-app
sudo systemctl status my-appCommand | What It Does |
|---|---|
| Installs the unit file to the correct location |
| Tells systemd to re-read all unit files (required after any change) |
| Creates symlinks so the service starts automatically at boot |
| Starts the service immediately (without waiting for reboot) |
| Verifies the service is active and shows recent log lines |
Useful Post-Deployment Commands
Task | Command |
|---|---|
View live service logs |
|
View last 100 log lines |
|
Stop the service |
|
Restart the service |
|
Reload config without restart |
|
Disable autostart at boot |
|
Check service file syntax |
|
Check all failed services |
|