Systemd in WSL: Service Lifetime, Idle Shutdown, and the Limits of a Workstation VM
Why enabling systemd in WSL does not guarantee daemon permanence, and how services should actually handle WSL's own lifecycle events.
Enabling systemd in a WSL distribution gives you real, familiar Linux service management — dependency ordering, socket activation, proper logging through journald — but it’s easy to over-extend that familiarity into an assumption systemd doesn’t actually support here: that a service enabled and running under systemd is now a permanent, always-on part of the system the way it might be on a dedicated server. WSL’s surrounding lifecycle doesn’t work that way, and understanding the boundary matters for anything you’re relying on to keep running.
What systemd actually controls, once enabled
With systemd=true configured in a distribution’s /etc/wsl.conf, systemd runs as PID 1 inside that distribution and manages units with the same semantics you’d expect on a conventional Linux installation — dependency-ordered startup, systemctl enable making a service start automatically on boot, socket and timer-based activation, and journald-based logging. Within the boundary of “while this distribution’s Linux environment is actually running,” systemd behaves like systemd anywhere else.
What systemd does not control: whether the distribution is running at all
The critical boundary is that systemd governs behavior inside an already-running distribution — it has no authority over whether the surrounding WSL 2 utility VM and this specific distribution instance are running in the first place. That’s governed entirely by WSL’s own lifecycle, which responds to a different set of triggers: the user logging off Windows, an explicit wsl --shutdown, a Windows or WSL update requiring a restart, or WSL’s own idle-timeout behavior potentially stopping an inactive distribution to free up resources. Any of these can stop the entire distribution — and therefore every systemd-managed service inside it — regardless of how correctly configured those services are within systemd itself.
Why this distinction trips people up specifically
systemctl enable myservice followed by confirming it’s running correctly gives every appearance of having created a permanent, self-sustaining background service — and within a single, continuously-running session, it has. The gap appears later, often days afterward, when the Windows machine is restarted, the user logs off overnight, or WSL’s own idle behavior stops the distribution, and the “always on” service is simply gone until someone manually starts the distribution again. This isn’t a systemd bug or misconfiguration; it’s the expected consequence of running systemd inside an environment whose own lifetime was never meant to be permanent the way a dedicated server’s uptime is.
Designing services to expect this, rather than fight it
Because the surrounding environment can stop at any time, services meant to run under WSL’s systemd should be built to handle a clean stop and restart gracefully — correctly responding to SIGTERM by flushing in-progress work and shutting down cleanly rather than assuming they’ll never receive a termination signal outside of an explicit administrative stop. Any data the service manages needs its own durability story (proper commits to durable storage, regular backups) independent of the process’s own uptime, since that uptime is fundamentally bounded by the Windows session’s own lifecycle in ways a dedicated Linux server’s uptime typically isn’t.
Exposing network listeners deliberately, not accidentally
A service listening on a network port inside a systemd-managed WSL distribution is reachable according to whatever WSL networking mode is active — NAT-based, or the newer mirrored mode with its broader LAN reachability. Configure and firewall a listening service deliberately, with an explicit understanding of who’s actually meant to reach it, rather than assuming a development-oriented WSL environment’s default networking posture is automatically appropriately scoped for whatever you’ve just enabled.
Verifying boot health rather than assuming systemctl output tells the whole story
systemctl is-system-running
systemctl --failed
journalctl -b -p warning
A system reporting degraded rather than running indicates at least one unit failed during boot, even if the overall shell and most services still work — worth investigating specifically rather than dismissing, since the failed unit could be something you’re actually relying on despite the rest of the system appearing fine.
When you actually need something that behaves like a permanent server
If the real requirement is a genuinely always-on service — not “usually on while I’m using my laptop” but actually continuously available regardless of whether anyone is logged into the Windows machine — the right answer is a proper server or cloud VM platform with explicit uptime guarantees, patching processes, and monitoring, not a developer workstation’s WSL environment. Treating WSL as if it could be quietly upgraded into that role by enabling systemd is a mismatch between what systemd inside WSL was actually built to support and what a genuinely production-grade hosting environment requires.
Idle-related shutdown specifically
Beyond user-initiated shutdown and updates, WSL can stop an inactive distribution’s VM resources after a period without active use, freeing memory and CPU back to the rest of the system rather than holding them indefinitely for a session nobody is currently interacting with. This is a sensible resource-management default for a developer workstation, but it’s exactly the kind of event a background service assuming indefinite uptime won’t expect — reinforcing why graceful-stop handling in your own services matters more here than it might on a dedicated host that never has a legitimate reason to reclaim idle resources this way.
The practical summary
Use WSL’s systemd support for what it’s genuinely good at — proper dependency-managed local development services, correct logging, and familiar Linux service semantics during an active working session — while designing anything running under it to expect the surrounding distribution’s lifecycle to end unpredictably, and routing anything that actually needs permanent uptime to infrastructure built for that purpose instead.
Testing the graceful-shutdown path deliberately, before you depend on it
Rather than assuming a service handles wsl --shutdown cleanly, test it deliberately: start the service, trigger a shutdown, restart the distribution, and confirm the service both stopped without corrupting its own data and came back up correctly afterward. A service that appears to work fine during ordinary use can still handle an abrupt termination poorly, and discovering that gap during a deliberate test is considerably better than discovering it the first time an actual unplanned shutdown happens to catch important in-progress work.
Related: How to Enable systemd in WSL2 · Microsoft and Canonical Bring systemd Support to WSL
Sources: