Start a Linux service automatically at boot (systemctl enable)
Make a Linux service start automatically at boot with systemctl enable, check it with is-enabled, and understand enabled, enabled-runtime, static and masked.
The issue opens pre-filled with this page title and URL.
The service is running, you reboot the machine, it is stopped. Nothing is broken: it was simply never enabled at boot. The command that fixes it fits on one line, sudo systemctl enable --now nginx, and the only check that counts afterwards is systemctl is-enabled. This page covers the automatic start of a Linux service with systemd: enable, disable, mask, read the enabling states, understand the target that triggers the service, and know what is-enabled really proves.
What you will learn
Make a service start automatically at boot with systemctl enable
Check the enabling with systemctl is-enabled and read the output without mistakes
Tell apart the enabled, enabled-runtime, disabled, static, masked and alias states
Understand the WantedBy mechanism and the targets that trigger a service at boot
Mask a service to forbid any start, including a manual one
Diagnose a service that does not come back after a reboot
All outputs on this page come from a Debian 13 (trixie) system with systemd 257 and Nginx as a real service. They may differ slightly on your side depending on the distribution, and that difference is precisely one of the traps explained below.
Started now, automatic at boot: two different things
This is the confusion that sends most people to this page. A systemd service has two completely independent states: is it running right now, and will it restart on its own at the next boot. start answers the first, enable answers the second.
The diagram puts the two axes side by side. Each arrow carries the command that moves from one state to the other: start and stop change nothing on the right, enable and disable nothing on the left. That is why enable --now exists: it chains both actions. A static unit, without an [Install] section, cannot be enabled at all: the section "A static service is not enabled" explains why.
The two combine freely, and each combination matches a real operations situation:
Combination
What it means
active + enabled
Running and will come back at boot. The normal state of a production service.
active + disabled
Running, but will vanish at reboot. The classic trap after an installation.
inactive + enabled
Stopped now, will start at the next boot. Typical after a maintenance stop.
inactive + disabled
Stopped and will not come back. The state of a service deliberately set aside.
Swipe to see more
Enable the automatic start of a service
Enabling means asking systemd to remember that this service must be started at every boot. Concretely, systemd writes a symbolic link in the directory of the target that triggers the service. This link lives on disk, so it survives a reboot.
Enable without starting right away
Use case: you are preparing a server, the service must be automatic at boot but you do not want to expose it yet.
Terminal window
sudosystemctlenablenginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Created symlink '/etc/systemd/system/multi-user.target.wants/nginx.service' → '/usr/lib/systemd/system/nginx.service'.
Three lines, and two of them are not about systemd. The Debian and Ubuntu packages that still ship a SysV script (the old init system) trigger a compatibility layer, systemd-sysv-install, whose first two lines are just chatter. The useful line is the third: the symbolic link created in multi-user.target.wants/.
Why you do not always see "Created symlink"
Many readers rerun the command, only see the two SysV lines again, and believe it failed. There is no failure: enable is idempotent. If the link already exists, systemd has nothing to create and shows nothing more.
Terminal window
sudosystemctlenablenginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
On a unit without a SysV script (most modern services, and the general case on RHEL or Fedora), the two compatibility lines disappear and only Created symlink remains. Remember the rule: the displayed message depends on the package and the previous state, it proves nothing. The only output that is authoritative is that of is-enabled.
Enable and start in one command
This is the form to use in 99% of installations, because it removes the most frequent oversight.
Terminal window
sudosystemctlenable--nownginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
is-enabled prints the state and also sets an exit code usable in automation. With --quiet, the command prints nothing and simply returns 0 if the service is enabled.
Terminal window
systemctlis-enabled--quietnginx; echo"code=$?"
code=0
This pairing of output and exit code is the basis of compliance checks: a loop over the list of a server's critical services is enough to spot the one that was started by hand and never enabled.
Beware of a trap in automation: is-enabled also returns 0 for the static, alias, indirect, generated and transient states, not only for enabled. A loop that only tests the exit code can therefore validate a static unit that will nevertheless not start on its own at boot. For a real check, compare the displayed string with enabled (or enabled-runtime), not only $?.
Disable and mask a service
Disabling removes the automatic start without touching the running service. Masking goes much further: the service becomes impossible to start, including by hand. The two meet different needs, and confusing them leads either to a service that comes back on its own, or to a service nobody can restart anymore.
Disable the autostart
Terminal window
sudosystemctldisablenginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
The symbolic link disappears, so the service will no longer come back at boot. On the other hand, it keeps running if it was active: disablestops nothing. To disable and stop at once, sudo systemctl disable --now nginx. Check with systemctl is-enabled nginx, which must show disabled.
Mask to forbid any start
Masking replaces the unit with a link to /dev/null. Nothing can start it anymore: not you, not a dependency of another service, not a package being updated.
Terminal window
sudosystemctlmasknginx
Created symlink '/etc/systemd/system/nginx.service' → '/dev/null'.
Any attempt to start it fails outright, with a message that names the cause:
Terminal window
sudosystemctlstartnginx
Failed to start nginx.service: Unit nginx.service is masked.
An enable on a masked unit fails too, with exit code 1: Failed to enable unit: Unit /etc/systemd/system/nginx.service is masked. To go back, sudo systemctl unmask nginx removes the link to /dev/null and makes the unit manageable again.
Read the enabling states
systemctl is-enableddoes not only answerenabled or disabled. The states below are the ones you will meet on a real server, all captured on the same Debian 13 system. Knowing them avoids concluding too quickly that a service "is not enabled" when it is simply designed differently.
State
What it means
Example captured
enabled
Enabled at boot, symbolic link present in /etc/systemd/system/
nginx.service
enabled-runtime
Enabled until the next reboot only, link created in /run/, so in memory
systemd-remount-fs.service
disabled
No autostart, no link, but the service can still be started by hand
debug-shell.service
static
No [Install] section, the unit cannot be enabled, it is pulled in as a dependency
systemd-tmpfiles-clean.service
masked
Start forbidden, the unit points to /dev/null
console-getty.service
alias
The name is only another name for an existing unit
kmod.service
Swipe to see more
The enabled-runtime state, the one everybody forgets
systemctl enable --runtime enables a service without writing anything to disk: the symbolic link lands in /run/systemd/system/, a file system in memory, emptied at every reboot.
Terminal window
sudosystemctlenable--runtimenginx
systemctlis-enablednginx
Created symlink '/run/systemd/system/multi-user.target.wants/nginx.service' → '/usr/lib/systemd/system/nginx.service'.
enabled-runtime
It is useful for a temporary enabling during an intervention, when you want the guarantee that the original state comes back at reboot. It is a formidable trap in the opposite case: an is-enabled answering enabled-runtime looks very much like enabled, while the service will not come back after a reboot. If you wanted a durable enabling, replay a sudo systemctl enable nginx without --runtime.
A static service is not enabled, and that is normal
A static unit has no [Install] section, so systemd does not know where to hook the symbolic link. It is designed to be pulled in by a dependency, a timer or an on-demand activation.
Terminal window
sudosystemctlenablesystemd-tmpfiles-clean.service
The unit files have no installation config (WantedBy=, RequiredBy=, UpheldBy=,
Also=, or Alias= settings in the [Install] section, and DefaultInstance= for
template units). This means they are not meant to be enabled or disabled using systemctl.
systemd explains the situation itself and creates no link. Nothing to repair: if you wanted to make this service automatic at boot, it is the unit file that must be completed, not the command that must change.
What really triggers the service at boot
A service does not start "at boot" in the absolute. It starts because a target reached during boot asks for it. The [Install] section of the unit file says which one, and it is exactly what enable reads to know in which directory to put the link.
Terminal window
systemctlcatnginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
Creates the link in multi-user.target.wants/, soft dependency: if the service fails, the target is reached anyway
RequiredBy=
Same principle as a hard dependency: the failure of the service makes the target fail
Also=
Enables other units at the same time (without starting them), typically an associated socket. Also applies on disable
Swipe to see more
The targets that matter on a server
Targets replaced the SysV runlevels, and the old names survive as simple aliases: runlevel3.target points to multi-user.target, runlevel5.target to graphical.target, runlevel1.target to rescue.target. Seeing this equivalence helps to read old operations scripts.
Target
Old runlevel
When it is reached
multi-user.target
3
Networked server without a graphical interface, the normal case in production
graphical.target
5
Workstation or server with a graphical environment
rescue.target
1
Maintenance mode, a minimum of services, often single-user
Swipe to see more
The vast majority of server services declare WantedBy=multi-user.target. And even if the machine boots into graphical.target, they start anyway: graphical.target declares Requires=multi-user.target, so it encompasses the multi-user target. The target used at boot is read with systemctl get-default.
See what will be started, and the full inventory
Two commands are enough to answer "what starts on this machine". The first lists the services hooked to the target, the second gives the enabling state of everything installed:
The PRESET column is not the current state: it is what the distribution recommends by default. An enabled in PRESET and a disabled in STATE flag a service someone disabled deliberately, valuable information when you take over a server you did not install.
Presets and reenable: fixing a shaky enabling
Two commands help when the enabling no longer looks the way it should, typically after editing a unit file by hand.
systemctl reenableremoves then recreates the links from the current [Install] section. It is the reflex after changing a WantedBy=: without it, the old link stays in place and the service keeps being hooked to the wrong target.
Created symlink '/etc/systemd/system/multi-user.target.wants/nginx.service' → '/usr/lib/systemd/system/nginx.service'.
systemctl preset nginx puts the service back in the state wanted by the distribution (the PRESET column). Debian and Ubuntu enable most services as soon as the package is installed, RHEL is much more conservative. The command says nothing when there is nothing to change, which is the most frequent case; check the result with systemctl is-enabled nginx.
Check that the service really comes back
An honest page must say it clearly: is-enabled does not prove the service will start. It proves that the enabling intent is correctly recorded, that is, the symbolic link exists in the right place. The service can perfectly well be enabled and fail at boot, because its configuration is broken, because it waits for a network mount that is not there yet, or because a dependency was masked.
The check that counts is therefore a real reboot, on a machine where you can afford it:
Terminal window
sudoreboot
Once reconnected, check the two things that matter, the state of the service and the absence of failed units:
Terminal window
systemctlis-activenginx
systemctl--failed
active
An empty output of systemctl --failed means no unit failed at boot. If your service is enabled but missing after the reboot, the diagnosis continues with journalctl -b -u nginx, which shows the current boot's log for that unit, and carries on in Troubleshoot a service that does not start.
Troubleshooting
The symptoms below cover most of what blocks an enabling at boot. What these situations have in common: the command looks like it worked, only is-enabledreveals the truth.
Symptom
Probable cause
Fix
The service is stopped after every reboot
enable was never run, only start
sudo systemctl enable --now nginx then systemctl is-enabled nginx
is-enabled answers enabled-runtime
Enabling done with --runtime, it lives in memory
Replay sudo systemctl enable nginx without --runtime
Failed to enable unit: ... is masked
The service is masked
sudo systemctl unmask nginx then sudo systemctl enable --now nginx
enable shows "no installation config"
Static unit, no [Install] section
Nothing to fix, the service is pulled in by a dependency; otherwise add [Install] to the unit file
No "Created symlink" on screen
Service already enabled (idempotent command) or package with a SysV script
Do not trust the message, decide with systemctl is-enabled nginx
The service starts, but not in the right boot context
WantedBy= points to the wrong target
Fix the [Install] section then sudo systemctl reenable nginx
enabled but missing after reboot
The enabling is fine, it is the start that fails
journalctl -b -u nginx to read the real error
Swipe to see more
The diagnostic trio fits in three commands: the enabling state, the contents of the unit, and the links actually present on disk.
Terminal window
systemctlis-enablednginx
systemctlcatnginx.service
ls-l/etc/systemd/system/multi-user.target.wants/
Good practices and security
Enabling at boot is not just an operations convenience, it is also an attack surface decision. Every enabled service is a process that will start without anyone asking, often listening on the network.
Use --now systematically at installation: enable --now to put into service, disable --now to withdraw. Forgetting one of the two halves is the most common mistake.
Explicitly disable what the server does not need rather than leaving it enabled by the distribution preset, especially on Debian and Ubuntu, which enable almost everything at installation.
Mask the services you want to forbid for good, after checking that no other unit depends on them.
Inventory what exists with systemctl list-unit-files --state=enabled on a server you take over: it is the exact list of what will come back at the next reboot.
Test with a real reboot before going into production. A server that has never rebooted since its installation is a server whose boot behaviour nobody knows.
Automate the enabling in your configuration management rather than redoing it by hand on each machine, which guarantees the enabling state is the same everywhere.
Key points
systemctl enable makes a service start automatically at boot by creating a symbolic link; disable removes it; --now adds the matching start or stop.
A service can be active without being enabled, and vice versa: is-active and is-enabled answer two different questions.
The message printed by enabledepends on the package and the previous state: the Synchronizing state ... SysV lines are Debian compatibility, and Created symlink only appears if a link is actually created. Only is-enabled is authoritative.
enabled-runtime means enabled until the next reboot only: the link is in /run/, it does not survive a reboot.
A static unit has no [Install] section and cannot be enabled: it is pulled in as a dependency.
mask forbids any start, including manual and including by a dependency; it is stronger than disable.
Enabling relies on WantedBy= in the [Install] section, and the multi-user.target target is the one used by almost all server services.
Only a real reboot proves anything: is-enabled proves the enabling intent, not a successful start.
Knowledge check
Check that the essentials of this guide are acquired. The questions only
cover what has just been explained here.
Knowledge check
Check what you have learned with this interactive quiz
6 questions
6 min
70% to pass
How it works
The timer starts when you click Start
Multiple choice, true/false and short answer questions
You can move between questions
Detailed results are shown at the end
Starts the quiz and the timer
⏱️--:--
0 / 6
Review
(0/0)
--:--
0%
0Correct
0To review
0:00Time
-Level
Score by domain
A domain groups several guides and gets several questions, so its score is more reliable than a per-topic score, which often rests on a single question.
Summary
Strengths
No topic passed at 80% on at least two questions yet.