Run sudo loginctl enable-linger "$USER". Your systemctl --user services normally start when you log in and stop when you log out. With lingering on, systemd starts your user manager at boot and keeps it running after you log out. On our laptop server, a user timer ran its job at boot while the machine sat at the login screen, three minutes before anyone connected.
This is step 4 of turning an old laptop into a 24/7 Ubuntu server. A server that reboots after an update or a power cut shouldn't wait for someone to log in before its jobs run.
The fix
sudo loginctl enable-linger "$USER"
loginctl show-user "$USER" --property=Linger
ls -l --time-style=full-iso /var/lib/systemd/linger/
Linger=yes
total 0
-rw-r--r-- 1 root root 0 2026-02-17 10:11:30.848983711 +0200 x1
loginctl(1) describes it like this: "a user manager is spawned for the user at boot and kept around after logouts." The setting is stored as an empty file named after the user in /var/lib/systemd/linger/. Ours dates from February, so it has been on for every boot since.
Your services still need to be enabled, so they start when the user manager does:
systemctl --user enable --now myjob.service # with WantedBy=default.target
systemctl --user enable --now myjob.timer # or a timer, WantedBy=timers.target
The proof: a real boot
Our laptop runs a test job, daily-job, from a user timer every 15 minutes. On the evening of 14 October we switched the laptop off for two hours, then on again, and left it at the login screen. The user manager for UID 1000 started without anyone logging in:
systemctl show user@1000.service -p ExecMainStartTimestamp -p ActiveEnterTimestamp
ExecMainStartTimestamp=Wed 2026-10-14 22:50:04 EEST
ActiveEnterTimestamp=Wed 2026-10-14 22:50:05 EEST
In the second it became active, it started the timer, and the timer ran the job:
2026-10-14T22:50:05+03:00 x1 systemd[1650]: Started daily-job.timer - Run daily-job every 15 minutes.
2026-10-14T22:50:05+03:00 x1 systemd[1650]: Starting daily-job.service - Daily job...
2026-10-14T22:50:05+03:00 x1 systemd[1650]: Finished daily-job.service - Daily job.
2026-10-14T22:50:07+03:00 x1 echo[1748]: daily-job ran
Nobody had logged in. Session c1 belongs to gdm, the login screen itself. The first session for our user came three minutes later:
2026-10-14T22:50:04+03:00 x1 systemd-logind[1027]: New session c1 of user gdm.
2026-10-14T22:53:12+03:00 x1 systemd-logind[1027]: New session 4 of user x1.
Session 4 is us: sshd logged our key being accepted at 22:53:12, when we connected to collect these logs. Nobody logged in at the laptop itself.
If it still doesn't start
- Check
Linger=yesfor the right user.loginctl enable-lingerwith no argument applies to the user of the current session. - Check the service is enabled, not just started:
systemctl --user is-enabled myjob.service. - Read the user journal:
journalctl --user -b -u myjob.service. If your system has no per-user journal files,sudo journalctl -b _SYSTEMD_USER_UNIT=myjob.servicefinds the same lines in the system journal. - Don't depend on your desktop session. A lingering service starts before anyone logs in, so anything that needs a graphical session or a logged-in user's keyring won't be there.
If it starts too early
Starting at boot also means starting before the network. On that boot the job ran at 22:50:05 and the Wi-Fi connected at 22:50:08:
2026-10-14T22:50:08+03:00 x1 NetworkManager[1082]: <info> [1792007408.8464] device (wlp0s20f3): state change: secondaries -> activated (reason 'none', sys-iface-state: 'managed')
Our test job only runs echo, so it didn't matter. It did matter earlier that day for another daily job on this laptop, one that calls a web API. After a boot at 14:52 it started at 14:52:57 and failed 8 seconds later because it couldn't resolve a hostname. The Wi-Fi connected at 14:53:12. That service file asks for the network, but a user unit can't wait for the system's network-online.target:
systemctl --user show <our daily job>.service -p Wants -p After
systemctl --user list-units --all network-online.target
Wants=network-online.target
After=basic.target network-online.target <our daily job>.timer app.slice -.mount
● network-online.target not-found inactive dead network-online.target
Unit name redacted; the rest is verbatim.
not-found means the user manager has no such unit, so the ordering does nothing. systemd.special(7) lists it only among the system manager's units. If a lingering job needs the network at boot, run it as a system service with User= and order it after network-online.target, or have the job retry until the network is up. We haven't tested either fix on this machine yet.
If the job is on a timer and the machine is sometimes off when it's due, add Persistent=true as well.