Skip to content
Français
Account: not signed in, sync available My learning
Select theme
Français

Start a Linux service automatically at boot (systemctl enable)

By updated

Improve this page

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.

Two independent axes. On the left, the current state read by systemctl is-active: start moves from inactive to active, stop does the opposite, and a failing process leads to failed. On the right, the state at the next boot read by systemctl is-enabled: enable moves from disabled to enabled, disable does the opposite, mask leads to masked, a link to /dev/null. A service without an [Install] section is static.Right now (is-active)At next boot (is-enabled)inactiveactivefaileddisabledenabledmaskedlink to /dev/nullstaticno [Install] sectionstartstopthe process failsenabledisablemask
Source · SVG
Esc to close, + and − to zoom, scroll to move around. 100 %
QuestionStateCommand
Is the service running now?active / inactivesystemctl is-active nginx
Will the service come back at the next boot?enabled / disabledsystemctl is-enabled nginx

The two combine freely, and each combination matches a real operations situation:

CombinationWhat it means
active + enabledRunning and will come back at boot. The normal state of a production service.
active + disabledRunning, but will vanish at reboot. The classic trap after an installation.
inactive + enabledStopped now, will start at the next boot. Typical after a maintenance stop.
inactive + disabledStopped and will not come back. The state of a service deliberately set aside.

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
sudo systemctl enable nginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable nginx
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/.

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
sudo systemctl enable nginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable nginx

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
sudo systemctl enable --now nginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install enable nginx
Created symlink '/etc/systemd/system/multi-user.target.wants/nginx.service' → '/usr/lib/systemd/system/nginx.service'.

The --now flag adds a start to the enabling. Check both states afterwards, not just one:

Terminal window
systemctl is-active nginx && systemctl is-enabled nginx
active
enabled

Check the enabling, including in a script

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
systemctl is-enabled --quiet nginx; 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
sudo systemctl disable nginx
Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.
Executing: /usr/lib/systemd/systemd-sysv-install disable nginx
Removed '/etc/systemd/system/multi-user.target.wants/nginx.service'.

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: disable stops 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
sudo systemctl mask nginx
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
sudo systemctl start nginx
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-enabled does not only answer enabled 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.

StateWhat it meansExample captured
enabledEnabled at boot, symbolic link present in /etc/systemd/system/nginx.service
enabled-runtimeEnabled until the next reboot only, link created in /run/, so in memorysystemd-remount-fs.service
disabledNo autostart, no link, but the service can still be started by handdebug-shell.service
staticNo [Install] section, the unit cannot be enabled, it is pulled in as a dependencysystemd-tmpfiles-clean.service
maskedStart forbidden, the unit points to /dev/nullconsole-getty.service
aliasThe name is only another name for an existing unitkmod.service

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
sudo systemctl enable --runtime nginx
systemctl is-enabled nginx
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
sudo systemctl enable systemd-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
systemctl cat nginx.service
[Unit]
Description=A high performance web server and a reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target
ConditionFileIsExecutable=/usr/sbin/nginx
[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'
[Install]
WantedBy=multi-user.target
[Install] directiveRole at enabling time
WantedBy=multi-user.targetCreates 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

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.

TargetOld runlevelWhen it is reached
multi-user.target3Networked server without a graphical interface, the normal case in production
graphical.target5Workstation or server with a graphical environment
rescue.target1Maintenance mode, a minimum of services, often single-user

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:

Terminal window
systemctl list-dependencies multi-user.target --type=service
multi-user.target
nginx.service
systemd-logind.service
systemd-user-sessions.service
Terminal window
systemctl list-unit-files --type=service --state=enabled
UNIT FILE STATE PRESET
getty@.service enabled enabled
nginx.service enabled enabled
systemd-pstore.service enabled enabled
3 unit files listed.

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 reenable removes 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.

Terminal window
sudo systemctl reenable nginx
Removed '/etc/systemd/system/multi-user.target.wants/nginx.service'.
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
sudo reboot

Once reconnected, check the two things that matter, the state of the service and the absence of failed units:

Terminal window
systemctl is-active nginx
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-enabled reveals the truth.

SymptomProbable causeFix
The service is stopped after every rebootenable was never run, only startsudo systemctl enable --now nginx then systemctl is-enabled nginx
is-enabled answers enabled-runtimeEnabling done with --runtime, it lives in memoryReplay sudo systemctl enable nginx without --runtime
Failed to enable unit: ... is maskedThe service is maskedsudo systemctl unmask nginx then sudo systemctl enable --now nginx
enable shows "no installation config"Static unit, no [Install] sectionNothing to fix, the service is pulled in by a dependency; otherwise add [Install] to the unit file
No "Created symlink" on screenService already enabled (idempotent command) or package with a SysV scriptDo not trust the message, decide with systemctl is-enabled nginx
The service starts, but not in the right boot contextWantedBy= points to the wrong targetFix the [Install] section then sudo systemctl reenable nginx
enabled but missing after rebootThe enabling is fine, it is the start that failsjournalctl -b -u nginx to read the real error

The diagnostic trio fits in three commands: the enabling state, the contents of the unit, and the links actually present on disk.

Terminal window
systemctl is-enabled nginx
systemctl cat nginx.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 enable depends 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

Is this project useful to you?

The guides, courses, quizzes and labs stay free. If you use them regularly, you can contribute to their upkeep and development.

Become a supporting member (new tab) One-time support (new tab) Learn more

Follow the project on LinkedIn