Turn an Ubuntu Laptop Into an Always-On Headless Server (Lid Closed)
-
Jason Yang - 22 Nov, 2025
- Updated 28 Jul, 2026
- Views —
An old laptop makes a great home server — it’s a small box with a built-in UPS (the battery) — but Ubuntu keeps trying to put it to sleep. Closing the lid is only one of the ways it nods off. For a machine that has to stay reachable over SSH at 3 a.m. with no monitor attached, you need to shut down every suspend trigger, not just the lid.
There are three of them: the lid switch, the idle timeout, and the sleep targets themselves. A true headless server should ignore all three.
Why the GUI power settings aren’t enough
Changing “Power” in the GNOME settings menu feels like the fix, but it fails for a server in two ways:
- GNOME settings apply only after a user logs in. If the server reboots after a power blip and sits at the login screen, closing the lid still suspends it — and it silently drops off the network.
- They only cover the desktop session’s idea of idle, not the system-level lid and sleep behavior.
For an always-on box, you want system-level settings that hold before and without any login.
1. Ignore the lid, unconditionally
Edit /etc/systemd/logind.conf and set the lid to ignore. Because a server lives on a charger, set the external-power case too:
[Login]
HandleLidSwitch=ignore
HandleLidSwitchExternalPower=ignore
Then reload the login manager:
sudo systemctl restart systemd-logind
This is unconditional on purpose — a headless server should never sleep on lid close, docked or not. (If you actually want it to sleep when undocked and only stay awake on an external monitor, that’s a different setup — see the clamshell guide linked at the end.)
2. Stop the idle suspend
Even with the lid handled, a desktop install will suspend the machine after a stretch of inactivity. Turn that off for the on-AC case:
gsettings set org.gnome.settings-daemon.plugins.power sleep-inactive-ac-type 'nothing'
Better yet, if you’re running it truly headless, you don’t need the graphical session at all. Booting to the console frees memory and removes the whole idle-suspend machinery:
sudo systemctl set-default multi-user.target
3. Mask the sleep targets (the definitive lock)
The belt-and-suspenders step: tell systemd the machine may not suspend or hibernate at all, from any source — lid, idle, a stray systemctl suspend, an application request. Masking the four sleep targets makes it impossible:
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target
After this, the normal systemd suspend and hibernate paths are all blocked — including systemctl suspend, the lid, and idle triggers. It’s the most reliable line for a headless box because it doesn’t matter which component asks; the systemd-managed routes are simply gone.
Verify it holds
Check the lid setting is live:
$ busctl get-property org.freedesktop.login1 /org/freedesktop/login1 \
org.freedesktop.login1.Manager HandleLidSwitch
s "ignore"
(systemctl show systemd-logind won’t work here — it reports the service unit’s properties, not logind’s lid settings, so it returns nothing. The lid values live on the login1 D-Bus Manager, which is what busctl queries.)
And confirm the targets are masked:
$ systemctl status sleep.target
Loaded: masked (Reason: Unit sleep.target is masked.)
Then the real test: close the lid, walk away, and hold an SSH session open across it. If the connection survives and uptime keeps climbing, the box is a proper server now. This works the same on Ubuntu 20.04, 22.04, and 24.04 LTS.
Want the opposite behavior — awake only while docked to an external monitor, but still sleeping in your bag? See clamshell mode.