systemd Unit File Validator
Paste a .service, .timer, .socket, or .mount file and check it for syntax errors, missing directives, and common mistakes.
Client-side only. Nothing leaves your browser
Paste a systemd unit file on the left to see validation results.
What this validator checks
The validator parses your unit file as INI and runs a series of structural and semantic checks against the rules described in systemd.unit(5), systemd.service(5), systemd.timer(5), systemd.socket(5), and systemd.mount(5). Every check runs locally in your browser. Your unit file never leaves the page.
- Detects the unit type (.service, .timer, .socket, .mount) from section headers and directives
- Flags lines without an
=sign and directives outside any section - Verifies required sections per type (e.g.
[Service],[Timer],[Mount]) - Checks that
ExecStartuses an absolute path (systemd does not consult PATH) - Validates allowed values for
Type,Restart,KillMode,StandardOutput, andStandardError - Sanity-checks
OnCalendar=expressions for timer units - Warns when
[Install]is missing or has noWantedBy=, needed forsystemctl enable - Flags unknown directives and unknown section headers (typos like
Restar=always)
Common systemd unit file mistakes
| Mistake | What goes wrong |
|---|---|
| ExecStart=node app.js | Relative command, which fails with status=203/EXEC. Use the absolute path: /usr/bin/node. |
| Description My App | Missing =. Every directive must be Key=Value. |
| Restart=sometimes | Invalid Restart value. Allowed: no, always, on-success, on-failure, on-abnormal, on-watchdog, on-abort. |
| No [Install] section | systemctl enable is a no-op. Add [Install] with WantedBy=multi-user.target. |
| Type=forking, no PIDFile= | systemd cannot reliably track which child is the main process, so the service may be marked failed. |
| OnCalendar=every 5 min | Wrong syntax. Use *:0/5 or *-*-* *:0/5:00. |
| Multiple ExecStart= | Only allowed for Type=oneshot. Other types accept exactly one ExecStart=. |
| StandardOutput=jurnal | Typo: should be journal. Other valid values: null, inherit, file:/path, append:/path. |
Using systemd-analyze verify locally
This tool catches the most common authoring mistakes, but systemd ships its own native validator. Once your unit is in place, you can verify it against the running systemd's full schema:
systemd-analyze verify /etc/systemd/system/myapp.servicesystemd-analyze verify loads the unit, resolves its dependencies, and prints any issues without actually starting it. Combine it with systemctl daemon-reload after every edit and systemctl status myapp.service to inspect the live state.
Frequently Asked Questions
Where are systemd unit files stored on Linux?
There are three main locations, in order of precedence: /etc/systemd/system/ (admin-installed units, highest priority), /run/systemd/system/ (runtime, second priority), and /lib/systemd/system/ or /usr/lib/systemd/system/ (package-installed units, lowest priority). User units live under ~/.config/systemd/user/ or /etc/systemd/user/. After dropping a new file in any of these directories, run 'sudo systemctl daemon-reload' so systemd picks up the change.
Do systemd unit files need to be executable?
No. Unit files are configuration files, not scripts. systemd reads them. The recommended permissions are 644 (rw-r--r--) and ownership root:root. The binary or script referenced by ExecStart= does need to be executable (chmod +x), but the .service file itself does not. Setting it executable is harmless but signals confusion about how systemd works.
What is the difference between Type=simple, forking, oneshot, and notify?
Type=simple (the default) means the process started by ExecStart is the main process, and systemd considers the unit started as soon as it execs. Type=forking expects the process to fork a child and the parent to exit; you must set PIDFile= so systemd can track the child. Type=oneshot is for short-lived commands and is the only Type that allows multiple ExecStart= lines or zero ExecStart= (often paired with RemainAfterExit=yes). Type=notify expects the process to call sd_notify("READY=1") when it has finished initializing. This is the most accurate startup signal but requires support in the binary.
Why does my service need an [Install] section with WantedBy?
The [Install] section tells systemctl enable how to wire the unit into the boot process. WantedBy=multi-user.target creates a symlink in /etc/systemd/system/multi-user.target.wants/ so the unit starts when the system reaches that target. Without [Install], 'systemctl enable myapp.service' silently does nothing and your service will not start on boot. The [Install] section is only consulted by enable/disable. It is ignored when you start the unit manually with 'systemctl start'.
What does status=203/EXEC mean when my service fails?
Exit status 203/EXEC means systemd was unable to execute the binary specified in ExecStart=. The four most common causes are: (1) the path is relative (systemd does not search PATH), so 'ExecStart=node server.js' fails but 'ExecStart=/usr/bin/node /srv/app/server.js' works; (2) the file does not exist at that path; (3) the file is not marked executable (chmod +x); (4) the interpreter on the shebang line is missing. Run 'systemctl status myapp.service' and check the journal with 'journalctl -u myapp.service -n 50' for the exact error.
Related Tools
Unit File Generator
Generate systemd .service, .timer, and .socket unit files visually. Set ExecStart, User, Restart, env vars, and Install target.
PM2 Ecosystem Generator
Visual builder for ecosystem.config.js. Configure cluster mode, env vars, watch, and max_memory_restart.
PM2 to systemd
Convert a PM2 app entry into a systemd .service unit file with cluster template support.
Cron Generator
Generate, validate, and translate cron expressions. Visual cron builder with human-readable descriptions.
Cron to systemd Timer
Convert cron expressions to systemd .service and .timer files with OnCalendar syntax.
Need to manage SSH connections?
SSH Workbench lets you connect, browse files, and manage servers visually.
Try SSH Workbench Free