Payments are experiencing issues due to temporary restrictions in Russia. If your payment does not go through, please submit a support request.Our support team is available 24/7 — we are always here to help with hosting and server issues.We are now accepting requests for dedicated server rental and colocation services in our data center.Reminder: we recommend enabling backups for additional data protection.A new VPS/VDS lineup with NVMe storage and improved performance is now available.Maintenance work on some servers has been completed. All services are operating normally.
Article5 min readViews0

How to check a systemd unit file before daemon-reload and starting the service

Check a complete candidate unit with systemd-analyze verify and interpret exit codes, a misspelled directive, a missing executable, and a missing dependency, without daemon-reload or starting the service.

Comments 0

A server rack and a configuration checking toolkit before a service change
In this article

It is better to detect an error in a unit file before daemon-reload and starting the service. For a complete candidate file, run systemd-analyze verify --man=no ./candidate.service: exit code 0 allows you to proceed to the next check, while a nonzero exit code means the change is not ready to apply.

Below is a reproducible check on Ubuntu 24.04, systemd 255 (255.4-1ubuntu8.17), performed on October 10, 2026. All four unit files were in a separate working directory. The commands systemctl daemon-reload, systemctl start, and systemctl restart were not run, and the system was not rebooted.

What systemd-analyze verify checks

The systemd-analyze documentation states that verify loads the supplied unit files, reports errors it finds, and also examines other units they reference. The result therefore depends not only on the syntax of an individual line, but also on the available dependencies and executables.

This is a static check before deployment. It does not send the new configuration to the running systemd manager or start the service. However, even exit code 0 does not prove that the application will connect to its database, read a secret, gain network access, or work successfully as the configured user.

Record the version first

systemd-analyze --version

In the test environment, the first output line was systemd 255 (255.4-1ubuntu8.17). Other versions may perform different checks and use different diagnostic wording, so it is useful to save the version with the result.

Prepare a separate candidate unit

The minimal training file is named candidate.service. The extension matters: systemd uses it to determine the unit type. In this example, the command only prints a string; the service itself was not started during the check.

[Unit]

Description=Training verification unit

[Service]

Type=oneshot

ExecStart=/usr/bin/printf systemd-verify-ok

For Type=oneshot and the rules governing ExecStart=, refer to the systemd.service manual. The training example does not include the user, directory, environment variable, or restriction settings from a real service.

Check the file without applying it

systemd-analyze verify --man=no ./candidate.service

The --man=no option disables checks for the existence of manual pages when the unit uses Documentation=man:. It does not disable the analysis of the unit, its dependencies, or its executable.

systemd-analyze verify --man=no ./candidate.service; printf 'exit=%s\n' "$?"

The valid training file produced no messages and returned exit=0. A repeat check gave the same result; the file checksums matched before and after the checks.

Checking a candidate unit with systemd-analyze verify and following the branches for exit codes 0 and 1
Exit code 0 allows you to proceed to the next check; exit code 1 stops deployment until the candidate is corrected.

Three errors detected in the test

In the first defective file, the ExecStart directive was misspelled as ExecStrat. The check reported Unknown key name 'ExecStrat', then refused to accept a service without a startup command and returned 1.

ExecStrat=/usr/bin/printf systemd-verify-ok

In the second file, the path specified in ExecStart= did not exist. The diagnostic Command /opt/example/bin/not-installed is not executable: No such file or directory was accompanied by exit code 1.

ExecStart=/opt/example/bin/not-installed

The third file used Requires= and After= to reference a unit that was absent from the available load paths. The check reported Unit definitely-missing-example.service not found and returned 1.

Requires=definitely-missing-example.service

After=definitely-missing-example.service

All three failures were reproduced twice. The valid file returned 0, while the misspelled directive, missing executable, and missing dependency returned 1.

A matrix of four systemd unit file checks with exit codes 0 and 1
In the test, the valid unit returned 0, while the misspelling, missing executable, and missing dependency returned 1.

Do not lose the exit code

Do not pipe the output straight into grep or head: without special shell settings, you may get the exit code of the last command in the pipeline instead of the exit code from systemd-analyze. It is simpler to use a conditional first and save the diagnostics separately.

if systemd-analyze verify --man=no ./candidate.service >./verify.log 2>&1; then printf 'verify=ok\n' else printf 'verify=stop\n' sed -n '1,80p' ./verify.log fi

In a separate repeat test, this pattern printed verify=ok for the valid file and verify=stop for the file with a missing executable path. The verify.log file may contain paths and internal unit names; store it with suitable permissions and review it before publishing.

Why empty output does not mean the unit is ready

  • The check sees the units and paths available to it. A dependency or executable may be present or absent on a different system.

  • A complete unit and a drop-in are different objects. A separate override.conf file cannot be assessed as a standalone service without the original unit and the actual order in which the configuration is layered.

  • The existence of a program does not prove that it will run under User= or gain access to WorkingDirectory=, a socket, a certificate, or a secret.

  • The check does not reproduce network readiness, resource limits, sandbox settings, database state, or the user scenario.

  • Generated and template units require the same generator versions and a valid instance; checking an abstract template may not describe the instance used in production.

A safe acceptance procedure

  • Save the original unit and all drop-ins separately; record the systemd version.

  • Build the complete candidate in the same way as the configuration management system generates it.

  • Run systemd-analyze verify for the candidate and resolve every diagnostic message, not just syntax errors.

  • Compare ExecStart=, User=, directories, dependencies, and environment variables against the change plan.

  • Only after approval should you deploy the unit through the standard procedure and run daemon-reload in a controlled maintenance window.

  • Separately check the actual startup, status, journal, and the service function used by its users; keep a way to restore the original unit ready.

The stop condition is simple: any unknown key, missing executable, missing dependency, or nonzero exit code means the candidate is not ready. Exit code 0 completes only the static checks. The actual process and service that must work after the change still need to be tested.

Discussion 0

Share your experience and ask questions. Comments without links appear after editorial review.

No comments yet. Start the discussion.