On a systemd host, `systemctl enable myapp.service` refuses with a message that the unit file has no installation config. Which section is missing from the unit file, and what exactly does WantedBy=multi-user.target cause systemd to create on disk?
answer
- one section is not read at runtime
- enable and disable are its only readers
- enabling is symlink management
- a directory named after the target
- no such section means static
basics
~10 sThe unit has no [Install] section, so there is nothing telling systemctl where to hook it. WantedBy=multi-user.target makes enable create a symlink to the unit inside /etc/systemd/system/multi-user.target.wants/, which is all that enabling physically does.
solid answer
~40 s`[Install]` is missing. That section is never read by the running manager — only `systemctl enable` and `disable` consult it, and it tells them which symlinks to manage. `WantedBy=multi-user.target` means enabling creates `/etc/systemd/system/multi-user.target.wants/myapp.service`, a symlink pointing at the real unit file; disabling deletes it. `RequiredBy=` uses a `.requires/` directory instead, `Alias=` creates a symlink under a second name, and `Also=` enables companion units alongside this one. A unit with no `[Install]` is perfectly usable — `systemctl list-unit-files` reports it as `static`, and it can still be started by hand or pulled in by something else — it just has no place to be hooked. If you cannot change the file, `systemctl add-wants multi-user.target myapp.service` creates the same symlink directly.
code
bash · 3 linessudo systemctl enable myapp.service
ls -l /etc/systemd/system/multi-user.target.wants/myapp.service
systemctl is-enabled myapp.servicego deeper
Know that WantedBy= lives in [Install] and that enabling a unit creates a symlink under a target's .wants directory rather than changing anything at runtime.
Explain that [Install] is read only by enable and disable, what RequiredBy=, Alias= and Also= each produce, and why a unit reported as static simply has no [Install] section.
Show how you verify boot behaviour rather than trusting is-enabled: which target the symlink sits under, whether the host reaches that target, and how add-wants attaches a vendor static unit without forking it.
Own the packaging convention: which target internal services attach to, whether socket- or timer-fronted pairs are wired with Also= so operators cannot enable half of one, and how enablement is asserted by configuration management rather than by hand.
## What enabling physically is Enabling a unit is not a database write and not a flag inside systemd. It is symlink management, and `[Install]` is the instruction set for it. The manager that runs your system at runtime never looks at `[Install]` at all — it resolves relationships from `[Unit]` and from the symlink farm on disk. That is why a unit missing the section starts happily by hand and fails only when you try to enable it: the message says, in effect, "you have not told me where to hook this". ## WantedBy= and the .wants directory A target unit's relationships can be expressed in two equivalent places: inside the target's own file, or as symlinks in a directory named after the target. Given: ```ini [Install] WantedBy=multi-user.target ``` `systemctl enable myapp.service` creates: ``` /etc/systemd/system/multi-user.target.wants/myapp.service -> /etc/systemd/system/myapp.service ``` That symlink is the entire effect. At the next boot, when the manager pulls in `multi-user.target`, it reads that directory and finds your unit attached to it. `systemctl disable` removes the symlink, and `systemctl is-enabled` is essentially asking whether it exists. The symlink points at wherever the real unit file lives — under `/etc/systemd/system` for a unit you wrote, under `/usr/lib/systemd/system` for a packaged one. If the unit file lives entirely outside the search path, `systemctl link /path/to/myapp.service` creates the pointer into `/etc/systemd/system` first, and only then can it be enabled. ## The other [Install] keys - `RequiredBy=` — same idea, but the symlink goes into `<target>.requires/`, expressing a stronger relationship than `.wants/`. - `Alias=` — creates an extra symlink under a different unit name, so the unit can be addressed by both. The alias must have the same suffix as the unit. - `Also=` — when this unit is enabled, enable these units too. This is the standard way a `.socket` and its paired `.service`, or a `.timer` and its job, are enabled together. - `DefaultInstance=` — for template units, the instance name to use when the template itself is enabled. ## Which target should a unit be wanted by? For an ordinary long-running server process, `multi-user.target` is the conventional answer: it is the state a non-graphical system reaches when it is fully up. Attaching to `graphical.target` instead means the unit only starts on hosts that reach a graphical state, which is rarely what a server operator wants. Targets are what make this work at all — a target has no process of its own, so it exists purely as a name that other units can attach themselves to and that the boot can be driven towards. ## Static units are not broken units `systemctl list-unit-files` classifies each unit as `enabled`, `disabled`, `static`, `masked`, `generated` and so on. `static` means exactly one thing: the unit has no `[Install]` section, so enabling is not applicable to it. Plenty of shipped units are deliberately static, because they are meant to be pulled in by another unit rather than hooked to a target on their own. The mistake is reading `static` as a fault and adding an `[Install]` section to a vendor unit that never wanted one. ## When you cannot edit the unit file Two commands cover this: ``` systemctl add-wants multi-user.target myapp.service systemctl enable --now myapp.service ``` `add-wants` creates the same `.wants/` symlink without touching the unit file — useful for a packaged static unit you want attached anyway. `enable --now` is simply enable plus start, saving the second command; note that plain enable does not start anything in the current boot, and a plain start leaves nothing on disk. ## Verifying `systemctl is-enabled myapp.service` gives the one-word verdict. `ls -l` on the `.wants/` directory shows what the boot will actually pull in, which is the check worth doing after a configuration-management run: a unit can be `enabled` in one target while nothing on the host ever reaches that target.
- You need a packaged static unit to come up at boot but you must not modify the vendor file. What do you do?`systemctl add-wants multi-user.target theunit.service` creates the same `/etc/systemd/system/multi-user.target.wants/` symlink that an `[Install]` section would have produced, without editing anything the package owns. The alternative — a drop-in adding `[Install]`— does not work reliably, because enable reads the section from the unit as loaded; add-wants is the supported route.
- What does Also= in an [Install] section achieve?It enables companion units in the same operation. When a service is fronted by a socket unit, the socket carries the `[Install]` hook and the service names the socket in `Also=`, so a single `systemctl enable` wires up both and a single disable removes both. Without it, operators reliably enable one half of a pair and wonder why nothing activates.
- A unit shows as enabled but never comes up at boot. What would you check?Which target it is attached to, and whether the host ever reaches that target. A unit symlinked into `graphical.target.wants/` on a server that boots to `multi-user.target` is genuinely enabled and genuinely never pulled in. `ls -l` on the `.wants/` directories and `systemctl get-default` settle it in a few seconds.
saying these in an interview costs you the question
- Enabling a unit starts it in the current boot
- [Install] is what the manager reads to run the service
- A static unit is broken and needs fixing
- Enable writes a flag into an internal systemd database
- WantedBy= adds an ordering constraint against the target