Failed or repeat-starting systemd services often hide the real cause in a dependency edge, a drop-in override, or a runtime path that differs from the packaged unit. Checking the merged unit and parsed properties before changing the service separates missing prerequisites from executable, environment file, user, and directory problems.
systemctl cat shows the unit file and drop-ins in the order systemd applies them, while systemctl show prints the properties systemd actually loaded. That distinction matters because dependencies can come from Requires, Wants, After, install-time symlinks, socket activation, generated mount units, and implicit defaults.
Runtime path checks should focus on the executable from ExecStart, optional or required EnvironmentFile entries, WorkingDirectory, service identity, and directories such as RuntimeDirectory or StateDirectory. Run the checks with enough privileges to read protected unit files and paths, and avoid restarting a failing service until the missing dependency or path is understood.
$ systemctl --no-pager cat ssh.service # /usr/lib/systemd/system/ssh.service [Unit] Description=OpenBSD Secure Shell server Documentation=man:sshd(8) man:sshd_config(5) After=network.target nss-user-lookup.target auditd.service ConditionPathExists=!/etc/ssh/sshd_not_to_be_run [Service] EnvironmentFile=-/etc/default/ssh ExecStartPre=/usr/sbin/sshd -t ExecStart=/usr/sbin/sshd -D $SSHD_OPTS ExecReload=/usr/sbin/sshd -t ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartPreventExitStatus=255 Type=notify RuntimeDirectory=sshd RuntimeDirectoryMode=0755 [Install] WantedBy=multi-user.target Alias=sshd.service
Replace ssh.service with the affected unit name. Include the suffix when checking a socket, timer, mount, or template instance.
$ systemctl show ssh.service -p FragmentPath -p DropInPaths -p Requires -p Wants -p After -p Before Requires=system.slice sysinit.target ssh.socket Wants=sshd-keygen.service Before=shutdown.target After=basic.target network.target sshd-keygen.service systemd-journald.socket -.mount system.slice nss-user-lookup.target auditd.service sysinit.target ssh.socket FragmentPath=/usr/lib/systemd/system/ssh.service DropInPaths=
FragmentPath identifies the main unit file. DropInPaths is blank when no override snippets are loaded for that unit.
$ systemctl list-dependencies --after --all --plain --full ssh.service ssh.service -.mount -.slice auditd.service ssh.socket system.slice sysinit.target dev-hugepages.mount systemd-journald.socket dev-mqueue.mount kmod-static-nodes.service ldconfig.service ##### snipped #####
Use --before to inspect units ordered after the service. Use --reverse when the question is which other units depend on the selected unit.
$ systemctl show ssh.service -p ExecStartPre -p ExecStart -p ExecReload -p EnvironmentFiles -p User -p Group -p WorkingDirectory -p RuntimeDirectory -p StateDirectory -p CacheDirectory -p LogsDirectory -p ConfigurationDirectory -p PIDFile
PIDFile=
ExecStartPre={ path=/usr/sbin/sshd ; argv[]=/usr/sbin/sshd -t ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecStart={ path=/usr/sbin/sshd ; argv[]=/usr/sbin/sshd -D $SSHD_OPTS ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecReload={ path=/usr/sbin/sshd ; argv[]=/usr/sbin/sshd -t ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
ExecReload={ path=/bin/kill ; argv[]=/bin/kill -HUP $MAINPID ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }
EnvironmentFiles=/etc/default/ssh (ignore_errors=yes)
WorkingDirectory=
User=
Group=
RuntimeDirectory=sshd
StateDirectory=
CacheDirectory=
LogsDirectory=
ConfigurationDirectory=
A leading dash in EnvironmentFile appears as ignore_errors=yes, so a missing file is allowed. The executable shown in path= is the program systemd will try to spawn.
$ sudo ls -l /usr/sbin/sshd /etc/default/ssh /etc/ssh/sshd_config -rw-r--r-- 1 root root 133 Mar 12 14:14 /etc/default/ssh -rw-r--r-- 1 root root 4307 Apr 28 00:15 /etc/ssh/sshd_config -rwxr-xr-x 1 root root 396152 Apr 28 00:15 /usr/sbin/sshd
A missing ExecStart binary or an unreadable required EnvironmentFile causes an immediate start failure and can contribute to start-limit-hit after repeated retries.
$ sudo ls -ld /run/sshd /var/log drwxr-xr-x 2 root root 40 Jun 13 20:31 /run/sshd drwxr-xr-x 1 root root 4096 Jun 13 20:31 /var/log
Paths under /run/ may be created only while the service is running. A configured RuntimeDirectory tells systemd to create that directory for the service lifecycle.
$ systemctl show ssh.service -p LoadState -p ActiveState -p SubState -p Result -p NRestarts LoadState=loaded ActiveState=active SubState=running Result=success NRestarts=0
LoadState=loaded confirms the unit definition was accepted. Result=success and NRestarts=0 help separate a stable service from a crash loop or a recently failed start.
Related: How to check Linux service status