systemd Basics: Starting, Stopping and Enabling Linux Services
Many Linux applications run quietly in the background.
Web servers listen for connections, databases process requests, network services manage connectivity and scheduled tools perform maintenance without opening a desktop window. On most modern Linux distributions, these background services are managed by systemd.
When a service fails, starts unexpectedly or does not launch after a reboot, systemctl is usually the first tool to use.
The essential commands are straightforward:
sudo systemctl start service-name
sudo systemctl stop service-name
sudo systemctl restart service-name
sudo systemctl enable service-name
sudo systemctl disable service-name
sudo systemctl status service-name
However, starting a service and enabling it are not the same thing. Understanding that distinction prevents many common mistakes.
What Is systemd?
systemd is a collection of core Linux components. Its system and service manager normally runs as process ID 1 and starts the rest of the operating system.
It manages much more than conventional background services, including:
- Devices
- Mount points
- Swap
- Sockets
- Timers
- User sessions
- System targets
- Logging through the journal
- Dependencies between system components
systemd tracks processes using Linux control groups and can start services in response to boot targets, sockets, devices, timers and other events.
The main command used to interact with it is:
systemctl
What Is a Unit?
systemd manages objects called units.
Common unit types include:
.service
.socket
.target
.timer
.mount
.automount
.path
.device
.swap
For ordinary service management, you will usually work with .service units.
Examples include:
ssh.service
nginx.service
apache2.service
docker.service
cups.service
NetworkManager.service
When the unit type is unambiguous, systemctl normally lets you omit .service.
These commands are therefore generally equivalent:
sudo systemctl restart ssh
sudo systemctl restart ssh.service
Using the complete unit name can be clearer in scripts and documentation.
Distribution Names Can Differ
The service name is not always the same on every Linux distribution.
For example, the OpenSSH server might be called:
ssh.service
on Debian or Ubuntu, but:
sshd.service
on Fedora or other distributions.
Similarly, the Apache web server is commonly:
apache2.service
on Debian-based systems and:
httpd.service
on Fedora or Red Hat-based systems.
Always confirm the unit name rather than guessing.
Check Whether a Service Exists
To inspect a known service:
systemctl status service-name
For example:
systemctl status ssh
You may see output similar to:
● ssh.service - OpenBSD Secure Shell server
Loaded: loaded (/usr/lib/systemd/system/ssh.service; enabled)
Active: active (running)
Main PID: 1248 (sshd)
Tasks: 1
Memory: 4.2M
CPU: 87ms
The most important lines are:
- Loaded — whether systemd found the unit file
- Enabled or disabled — whether it is configured for automatic activation
- Active — its current runtime state
- Main PID — the main process associated with it
- Recent journal entries — messages explaining its latest activity
systemctl status is intended to provide human-readable runtime information and recent log output for the selected unit. systemd’s related administration tools expose service state, dependencies and journal information through the same management framework.
Starting a Service
To start a service immediately:
sudo systemctl start service-name
For example:
sudo systemctl start nginx
This requests that systemd activate the unit now.
It does not necessarily configure the service to start after the next reboot.
Check that it started:
systemctl status nginx
Or use a simpler machine-friendly check:
systemctl is-active nginx
Possible results include:
active
inactive
failed
activating
deactivating
Stopping a Service
To stop a running service:
sudo systemctl stop service-name
For example:
sudo systemctl stop nginx
Then confirm:
systemctl is-active nginx
Stopping a service affects its current runtime state. It does not normally prevent it from starting again after reboot or being activated by another unit.
A stopped service can also be started again automatically if it is:
- Socket-activated
- Triggered by a timer
- Required by another unit
- Started by an administrator
- Restarted by its own configured recovery policy
If a service immediately returns after being stopped, inspect its dependencies, sockets, timers and restart settings rather than repeatedly stopping it.
Restarting a Service
To stop and then start a service:
sudo systemctl restart service-name
For example:
sudo systemctl restart ssh
Restarting is commonly required after changing configuration files.
Be careful when restarting:
- SSH on a remote server
- Networking
- Firewalls
- Storage services
- Databases
- Virtualisation platforms
- Authentication services
A bad configuration could disconnect your remote session or interrupt users.
Where the application provides a configuration-test command, run that first.
For Nginx:
sudo nginx -t
For Apache on many systems:
sudo apachectl configtest
For OpenSSH:
sudo sshd -t
Only restart after the configuration test succeeds.
Reloading a Service
Some services can reload their configuration without fully stopping.
Use:
sudo systemctl reload service-name
For example:
sudo systemctl reload nginx
Reloading can reduce interruption because the running service remains available while rereading its configuration.
Not every unit supports reload.
Check using:
systemctl show service-name -p CanReload
A result of:
CanReload=yes
means the unit declares reload support.
If reload is unsupported, systemctl will normally report an error rather than silently restarting the service.
Reload or Restart Automatically
You can ask systemd to reload when supported and restart otherwise:
sudo systemctl reload-or-restart service-name
This is useful in maintenance scripts when the service’s capabilities may vary.
However, it can conceal whether the operation interrupted the service, so use it thoughtfully on critical systems.
Start Versus Enable
This is the most important systemd distinction.
Start
sudo systemctl start nginx
Starts the service now.
Enable
sudo systemctl enable nginx
Configures the service for automatic activation through the dependencies defined in its unit file, commonly during boot.
Enabling does not normally start the service immediately.
To both enable and start it:
sudo systemctl enable --now nginx
This combines two actions:
- Enable the unit for future automatic activation.
- Start it in the current session.
Check Whether a Service Is Enabled
Run:
systemctl is-enabled service-name
For example:
systemctl is-enabled nginx
Possible results include:
enabled
disabled
static
masked
indirect
generated
enabled
The unit has the appropriate links or configuration for automatic activation.
disabled
The unit is available but not enabled through its install configuration.
It can still be started manually or as a dependency.
static
The unit does not normally contain installation instructions for direct enabling.
It may instead be started because another unit depends on it.
masked
The unit has been deliberately blocked from starting.
generated
The unit was created dynamically, often from another configuration source.
Do not assume that anything other than enabled means broken.
Disabling a Service
To remove its normal automatic-start configuration:
sudo systemctl disable service-name
For example:
sudo systemctl disable nginx
This does not normally stop the currently running service.
To disable and stop it together:
sudo systemctl disable --now nginx
A disabled service can still be:
- Started manually
- Started by another unit
- Activated through a socket
- Triggered by a timer
- Started through D-Bus or device activation
Disabling is therefore different from completely blocking activation.
Masking a Service
To prevent a service from being started at all:
sudo systemctl mask service-name
For example:
sudo systemctl mask cups
A masked unit normally points to /dev/null, causing activation attempts to fail.
To mask and stop it:
sudo systemctl mask --now cups
To allow it again:
sudo systemctl unmask cups
Masking is stronger than disabling.
Use it when a service must not be activated accidentally, but be careful with core system units. Masking networking, login, storage or security components can prevent normal startup or remote access.
Why a Disabled Service May Still Start
A disabled service can still start because “disabled” only means it has not been installed into its normal boot target through systemctl enable.
Another unit may contain a dependency such as:
Requires=example.service
or:
Wants=example.service
A socket or timer may also activate it.
Check what caused the activation with:
systemctl status service-name
Then inspect dependencies:
systemctl list-dependencies service-name
For reverse dependencies:
systemctl list-dependencies --reverse service-name
You can also look for related units:
systemctl list-unit-files | grep example
Possible related units might include:
example.service
example.socket
example.timer
example.path
systemd supports dependency-driven and on-demand activation, including socket and device activation, so a service does not need to be directly enabled to run.
Check All Running Services
List active service units:
systemctl list-units --type=service
Show only running services:
systemctl list-units --type=service --state=running
Show failed services:
systemctl --failed
Or specifically:
systemctl list-units --type=service --state=failed
The failed list is a useful first check after:
- A problematic boot
- A package upgrade
- A power failure
- A configuration change
- A server outage
List Installed Service Unit Files
To list service definitions whether active or not:
systemctl list-unit-files --type=service
This displays states such as:
enabled
disabled
static
masked
This differs from:
systemctl list-units
list-units shows units currently loaded into systemd’s runtime state, while list-unit-files focuses on unit files installed on disk.
View Service Logs
The systemd journal stores structured log messages collected by systemd-journald.
To view logs for one service:
journalctl -u service-name
For example:
journalctl -u nginx
journalctl reads entries from the systemd journal and can filter them by fields such as the associated systemd unit.
Show Recent Logs
To show the latest entries:
journalctl -u nginx -n 50
This displays the most recent 50 lines.
For logs from the current boot:
journalctl -u nginx -b
For the previous boot:
journalctl -u nginx -b -1
To show errors since today:
journalctl -u nginx --since today
For a specific period:
journalctl -u nginx \
--since "2026-08-01 08:00" \
--until "2026-08-01 09:00"
Follow Logs Live
To watch new messages as they arrive:
journalctl -u nginx -f
This is similar to following a traditional log file with:
tail -f
Press:
Ctrl + C
to stop following.
This is especially useful while reproducing a fault in another terminal.
Show More Detailed Errors
For explanations and related metadata:
journalctl -xeu service-name
For example:
journalctl -xeu ssh
The options mean broadly:
- -x — add explanatory text where available
- -e — jump near the end
- -u — filter for the selected unit
Do not focus only on the final line. The real cause may appear several messages earlier.
A Service Is “Failed”
Check its status:
systemctl status service-name
Then inspect its logs:
journalctl -xeu service-name
Common causes include:
- Invalid configuration syntax
- Missing files
- Wrong permissions
- An occupied network port
- A failed dependency
- Incorrect credentials
- Missing environment variables
- A damaged package
- A storage volume not being mounted
- A security policy blocking access
- The process exiting immediately
After fixing the cause, reset the failed state if necessary:
sudo systemctl reset-failed service-name
Then start it:
sudo systemctl start service-name
reset-failed clears the remembered failed state and also resets certain start-rate counters. It does not repair the service itself.
“Start Request Repeated Too Quickly”
systemd can limit how often it tries to restart a repeatedly failing unit.
You may see:
Start request repeated too quickly
This usually means:
- The service started.
- It failed quickly.
- systemd retried it.
- It failed repeatedly.
- systemd stopped retrying to avoid an endless loop.
Do not merely reset the failure and repeatedly start it.
First inspect:
systemctl status service-name
journalctl -u service-name -b
Fix the underlying application or configuration problem, then run:
sudo systemctl reset-failed service-name
sudo systemctl start service-name
Viewing the Unit File
To display the unit file and any overrides:
systemctl cat service-name
For example:
systemctl cat ssh
This is safer than guessing the unit’s location.
It can show:
- The main vendor file
- Administrator overrides
- Drop-in files
- Runtime-generated settings
To see where the main file was loaded from:
systemctl show service-name -p FragmentPath
Common Unit-File Locations
System unit files may be found under locations such as:
/etc/systemd/system
/run/systemd/system
/usr/lib/systemd/system
/lib/systemd/system
The exact vendor path differs between distributions.
As a general rule:
- Distribution packages place their unit files under a vendor directory such as /usr/lib/systemd/system
- Administrator-created units and overrides belong under /etc/systemd/system
- /run/systemd/system contains temporary runtime configuration
Do not directly edit a package-supplied unit under /usr/lib or /lib. A package upgrade may overwrite the change.
Editing a Service Safely
To create an override:
sudo systemctl edit service-name
This opens an editor for a drop-in file, normally under a path similar to:
/etc/systemd/system/service-name.service.d/override.conf
For example:
sudo systemctl edit nginx
You might add:
[Service]
Restart=on-failure
RestartSec=5s
Save and exit, then reload systemd’s unit configuration:
sudo systemctl daemon-reload
Restart the service if the new setting must apply immediately:
sudo systemctl restart nginx
What Does
daemon-reload
Do?
Run:
sudo systemctl daemon-reload
after:
- Creating a unit file
- Editing a unit file
- Adding or changing a drop-in
- Changing dependency links manually
- Modifying certain generator inputs
daemon-reload tells the system manager to rerun generators, reread unit files and rebuild its dependency information.
It does not restart all services.
It also does not necessarily apply new service settings to a process that is already running. Restart or reload the affected service afterwards where required.
Official systemd debugging guidance specifically calls for daemon-reload when configuration changes require the manager to refresh its view of units and generated dependencies.
Do Not Confuse These Three Commands
Reload the service
sudo systemctl reload nginx
Asks the application to reread its own configuration.
Restart the service
sudo systemctl restart nginx
Stops and starts the application process.
Reload systemd’s unit definitions
sudo systemctl daemon-reload
Makes systemd reread unit files.
They solve different problems.
Reverting Local Overrides
To remove overrides and return to the package-supplied unit:
sudo systemctl revert service-name
Review what will be removed before confirming.
Then run:
sudo systemctl daemon-reload
sudo systemctl restart service-name
where appropriate.
You can also inspect the existing override before removing it:
systemctl cat service-name
Creating a Basic Custom Service
Suppose you have a script:
/usr/local/bin/example-worker
Create a unit:
sudo nano /etc/systemd/system/example-worker.service
Add:
[Unit]
Description=Example Background Worker
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/example-worker
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
Then:
sudo systemctl daemon-reload
sudo systemctl enable --now example-worker.service
Check it:
systemctl status example-worker.service
View logs:
journalctl -u example-worker.service
Understanding the Unit Sections
[Unit]
Contains general metadata and dependencies.
[Unit]
Description=Example Background Worker
After=network.target
[Service]
Describes how the service starts and behaves.
[Service]
Type=simple
ExecStart=/usr/local/bin/example-worker
Restart=on-failure
[Install]
Describes what should happen when the unit is enabled.
[Install]
WantedBy=multi-user.target
Without an appropriate [Install] section, systemctl enable may report that the unit has no installation configuration.
That does not necessarily mean the unit is invalid. It may be intended to start only as a dependency or through another form of activation.
Use Absolute Paths
For system services, use full executable paths:
ExecStart=/usr/local/bin/example-worker
Do not rely on shell aliases or an interactive user’s PATH.
This is unreliable:
ExecStart=example-worker
Find the executable path with:
command -v example-worker
Also remember that ExecStart= does not automatically run through an interactive shell.
Shell features such as these will not behave as expected unless you deliberately invoke a shell:
|
>
>>
&&
$VARIABLE
*
Prefer a proper script with an explicit interpreter rather than placing a complicated shell command directly in the unit.
Set the Correct User
System services run as root by default unless configured otherwise.
To run the process as a dedicated account:
[Service]
User=example
Group=example
ExecStart=/usr/local/bin/example-worker
Running an internet-facing or file-processing service as root unnecessarily increases the impact of a compromise or programming error.
Give the service only the permissions it requires.
Set the Working Directory
If the program expects to start in a particular folder:
[Service]
WorkingDirectory=/srv/example
ExecStart=/usr/local/bin/example-worker
Do not assume it will start in the same directory as the unit file or script.
Environment Variables
You can define individual variables:
[Service]
Environment="APP_MODE=production"
Environment="PORT=8080"
Or load them from a file:
[Service]
EnvironmentFile=/etc/example-worker.conf
Protect files containing passwords, API keys or database credentials:
sudo chown root:root /etc/example-worker.conf
sudo chmod 600 /etc/example-worker.conf
Avoid including secrets directly in broadly readable unit files where better credential-management methods are available.
Service Types
The Type= setting tells systemd how to determine that startup has succeeded.
Common values include:
simple
The process started by ExecStart= is treated as the main service process.
Type=simple
This is suitable for many programs that remain in the foreground.
exec
Similar to simple, but systemd considers startup successful only after the service executable has been invoked successfully.
forking
Used by traditional daemons that start and then fork into the background.
Type=forking
Modern applications should generally run in the foreground under systemd rather than daemonising themselves where supported.
oneshot
Used for a command that runs once and exits.
Type=oneshot
RemainAfterExit=yes
notify
The service explicitly tells systemd when it has completed startup.
Choose the type documented by the application rather than guessing.
Restart Policies
Common policies include:
Restart=no
Restart=on-failure
Restart=always
no
Do not automatically restart.
on-failure
Restart after abnormal exits, signals or timeouts, depending on the detailed settings.
always
Restart regardless of why the process exited.
For most ordinary long-running services:
Restart=on-failure
is safer than always.
Do not use automatic restarts to hide a repeating crash. Monitor the logs and fix the actual fault.
Dependencies and Ordering Are Different
A frequent mistake is assuming that:
After=network.target
causes network.target to start.
It does not.
After= controls ordering when both units are part of the same transaction.
Dependencies are expressed separately with directives such as:
Wants=
Requires=
For example:
[Unit]
Wants=network-online.target
After=network-online.target
Even then, “network online” depends on the relevant wait-online service and network configuration. Being ordered after network.target does not by itself mean a usable network connection is available. The official systemd documentation explicitly warns about this distinction in network-dependent service configurations.
Wants=
Versus
Requires=
Wants=
Creates a weaker dependency.
systemd attempts to start the listed unit, but your service may still start when that other unit fails.
Requires=
Creates a stronger requirement.
When the required unit fails to activate, the requesting unit is generally not started. Depending on ordering and runtime relationships, stopping or failure behaviour can still require additional directives.
Do not use Requires= everywhere. It can create unnecessary coupling and make the system less resilient.
Targets
Targets group units and represent system states or synchronisation points.
Common targets include:
multi-user.target
graphical.target
network.target
network-online.target
rescue.target
emergency.target
A server service often includes:
[Install]
WantedBy=multi-user.target
A graphical desktop component may instead be associated with:
graphical.target
To see the current default target:
systemctl get-default
Typical output:
graphical.target
or:
multi-user.target
User Services
systemd can also manage services for an individual user.
Use:
systemctl --user status service-name
Start one:
systemctl --user start service-name
Enable one:
systemctl --user enable service-name
Enable and start:
systemctl --user enable --now service-name
User service files may be stored under:
~/.config/systemd/user
After changing one:
systemctl --user daemon-reload
Logs can be viewed with:
journalctl --user -u service-name
A user systemd manager is distinct from the system manager and can persist across multiple sessions according to the system’s login-manager configuration.
User Services After Logout
A normal user service may stop when the user has no remaining sessions.
To allow the user manager to remain active after logout:
sudo loginctl enable-linger username
Disable it with:
sudo loginctl disable-linger username
Use lingering only where there is a genuine requirement for the user’s services to run without an interactive login.
For system-wide infrastructure, a proper system service may be more appropriate.
Find Which Process Uses a Port
A service may fail because another process already occupies its port.
For example:
sudo ss -ltnp
To check port 80:
sudo ss -ltnp 'sport = :80'
You may find that:
- Apache is already using the port intended for Nginx
- A manually started process conflicts with the service
- An old development server is still running
- A container has published the same port
Do not kill the process until you identify why it is there.
Check Unit Dependencies
Display the dependency tree:
systemctl list-dependencies service-name
Reverse the direction:
systemctl list-dependencies --reverse service-name
Inspect specific unit properties:
systemctl show service-name
Useful individual properties include:
systemctl show service-name -p ActiveState
systemctl show service-name -p SubState
systemctl show service-name -p MainPID
systemctl show service-name -p Restart
systemctl show service-name -p FragmentPath
systemctl show is more suitable for scripts than parsing the decorative output of systemctl status.
Check for Stuck Jobs
List systemd jobs currently being processed:
systemctl list-jobs
This can help when boot, shutdown or service activation appears to be waiting indefinitely.
Official systemd debugging guidance recommends checking service status, logs and pending jobs when investigating startup problems.
Validate Unit Files
Run:
systemd-analyze verify /etc/systemd/system/example-worker.service
This can detect:
- Unknown directives
- Missing dependencies
- Invalid executable paths
- Syntax problems
- Certain ordering issues
A clean result does not prove that the application itself will work, but it can catch unit-file mistakes before deployment.
Do Not Edit Units with Windows Line Endings
A unit or script created in a Windows editor may contain CRLF line endings.
This can lead to confusing execution errors, especially for scripts with a shebang such as:
#!/bin/bash
Check with:
file /usr/local/bin/example-worker
Convert where appropriate using a trusted editor or:
dos2unix /usr/local/bin/example-worker
Also make sure the script is executable:
sudo chmod 755 /usr/local/bin/example-worker
Permission Problems
If the service reports:
Permission denied
check:
- The executable bit
- Parent-directory access
- The configured User= and Group=
- File ownership
- SELinux or AppArmor
- Mount options such as noexec
- Access to sockets and devices
- Whether a protected directory is writable
Do not respond by making every file world-writable.
This is rarely appropriate:
chmod -R 777 /path
Give the service account the narrowest access it needs.
SELinux and AppArmor
A service can have apparently correct Unix permissions and still be blocked by a mandatory access-control system.
On SELinux systems, inspect recent denials using the distribution’s supported tools and logs.
On AppArmor systems, check whether the service’s profile is denying a path or capability.
Do not disable SELinux or AppArmor globally simply to make one service run.
Correct the path, package, label or policy instead.
Services Installed from Containers or Sandboxed Packages
Not every application is managed by a conventional host .service unit.
It may instead be controlled by:
- Docker
- Podman
- Kubernetes
- Snap
- Flatpak
- A user service
- A process supervisor inside a container
For example, restarting:
sudo systemctl restart docker
restarts the Docker daemon and may affect many containers. It is not the same as restarting one container.
Use the correct management layer for the application.
Do Not Repeatedly Use
kill -9
systemd normally stops a service using its configured shutdown behaviour and signals.
A forced:
kill -9 PID
does not allow the process to:
- Flush data
- Close connections
- Remove temporary files
- Commit database transactions
- Release locks cleanly
Use:
sudo systemctl stop service-name
first.
Reserve forced termination for a genuinely stuck process after understanding the data risk.
A Safe Service-Management Workflow
When working with a systemd service:
- Confirm the exact unit name.
- Check its current status.
- Review recent journal entries.
- Test the application’s configuration.
- Start, stop, reload or restart it as required.
- Confirm the resulting state.
- Enable it only if it should activate automatically.
- Use --now when you also want the immediate runtime action.
- Use an override instead of editing a vendor unit.
- Run daemon-reload after unit-file changes.
- Restart the service if the new runtime settings require it.
- Check logs after every significant change.
- Mask only when activation must be completely blocked.
- Keep another administrative session open when changing remote-access or networking services.
Quick systemctl Reference
Status
systemctl status example.service
Start now
sudo systemctl start example.service
Stop now
sudo systemctl stop example.service
Restart
sudo systemctl restart example.service
Reload configuration
sudo systemctl reload example.service
Enable at boot
sudo systemctl enable example.service
Enable and start now
sudo systemctl enable --now example.service
Disable automatic activation
sudo systemctl disable example.service
Disable and stop now
sudo systemctl disable --now example.service
Block all activation
sudo systemctl mask example.service
Remove the block
sudo systemctl unmask example.service
Read logs
journalctl -u example.service
Follow logs live
journalctl -u example.service -f
Reload unit definitions
sudo systemctl daemon-reload
List failed units
systemctl --failed
Need Help Managing Linux Services?
A single systemd command can restore a failed service, but incorrect dependency, permission or restart settings can cause repeated crashes, boot delays or unexpected outages.
Hamilton Group can diagnose failing Linux services, review unit files and logs, configure secure automatic startup and help maintain reliable Linux workstations and servers.
Call 0330 043 0069 or visit hgmssp.com to speak with one of our IT experts.