systemd’s enable, disable, and mask commands aren’t just about turning services on and off; they’re about controlling how systemd starts and stops units, and crucially, how they interact with each other and the boot process.

Let’s see systemd in action. Imagine you have a custom service called my-awesome-app.service.

First, we need to create a unit file for it. This typically lives in /etc/systemd/system/.

# /etc/systemd/system/my-awesome-app.service
[Unit]
Description=My Awesome Application

[Service]
ExecStart=/usr/local/bin/my-awesome-app
Restart=on-failure

[Install]
WantedBy=multi-user.target

Now, to make this service start automatically when the system boots into the multi-user runlevel, we enable it:

sudo systemctl enable my-awesome-app.service

What just happened? systemd created a symbolic link:

ls -l /etc/systemd/system/multi-user.target.wants/
lrwxrwxrwx 1 root root 42 Jan 1 10:00 my-awesome-app.service -> /etc/systemd/system/my-awesome-app.service

This link tells systemd: "When you are about to enter multi-user.target, make sure my-awesome-app.service is started."

To start it right now, without rebooting:

sudo systemctl start my-awesome-app.service

And to stop it:

sudo systemctl stop my-awesome-app.service

To prevent it from starting on boot, we disable it:

sudo systemctl disable my-awesome-app.service

This removes the symbolic link we saw earlier:

ls -l /etc/systemd/system/multi-user.target.wants/
# my-awesome-app.service link is gone

But what if you want to be absolutely sure a service never starts, not even accidentally or as a dependency of another service? That’s where mask comes in.

sudo systemctl mask my-awesome-app.service

This doesn’t just remove the symlink; it creates a new symlink pointing to /dev/null:

ls -l /etc/systemd/system/my-awesome-app.service
lrwxrwxrwx 1 root root 9 Jan 1 10:05 my-awesome-app.service -> /dev/null

Now, if you try to start my-awesome-app.service directly:

sudo systemctl start my-awesome-app.service
# Output: Failed to start my-awesome-app.service: Unit my-awesome-app.service is masked.

Even if another service tries to Wants or Requires it, systemd will refuse to start it because its unit file is effectively a black hole.

To undo mask, you use unmask:

sudo systemctl unmask my-awesome-app.service

This removes the /dev/null symlink, restoring the original unit file, and the service can then be enabled, disabled, started, or stopped as usual.

The WantedBy directive in the [Install] section is key to enable. It specifies which target(s) should create the symlink to this unit when enable is run. Common targets include multi-user.target (for server environments), graphical.target (for desktop environments), or even other service units.

The systemctl list-unit-files --state=enabled command is your go-to for seeing what’s set to start on boot.

When you enable a service, systemd looks at the WantedBy directive in its [Install] section. If WantedBy is multi-user.target, systemd creates a symbolic link from /etc/systemd/system/multi-user.target.wants/ to your service’s unit file. This establishes a dependency: when multi-user.target is activated, it will ensure all units symlinked in its .wants directory are also started. This is how services are brought up during the boot process.

The difference between disable and mask is subtle but critical. disable simply removes the automatic startup mechanism (the symlink in .wants), but the unit file itself remains, and the service can still be started manually or as a dependency of another service. mask, on the other hand, links the unit file to /dev/null, making it impossible to start the service by any means until it’s unmasked. This is a stronger guarantee of non-execution.

This mechanism is also how systemd manages dependencies. If ServiceA Requires=ServiceB and ServiceB has WantedBy=multi-user.target, then enabling ServiceB implicitly enables ServiceA if ServiceA is also configured to be wanted by multi-user.target (or another target that pulls in multi-user.target).

The real power comes when you understand how systemd resolves dependencies. If you enable a service that has Requires or Wants directives pointing to other services, systemd will attempt to start those dependent services as well. Conversely, if a service is WantedBy a target, and that target is stopped, systemd will also stop the wanted service.

The next step is understanding how systemd manages dependencies between units, particularly the difference between Requires and Wants, and how Before and After directives influence startup order.

Want structured learning?

Take the full Systemd course →