When working with systemd, it is common to rely on network-online.target to ensure services start only after the network is fully up. However, this target exists at the system level, while many modern workflows run long-lived services in the user systemd instance (for example, user-managed daemons, development tooling, or per-user agents). This setup provides a clean bridge: when the system reaches “network online,” it triggers a corresponding marker target inside a specific user’s systemd instance—automatically and reliably at boot.
Overview of the Approach
The solution consists of three parts:
- A small installation script (
install.sh) that sets up required system and user units. - A user-level marker unit (
network-online.target) that exists only to represent “network online” inside the user instance. - A system-level templated service (
user-network-online@.service) that waits for system networking to be online and then starts the user-level target for a given user ID (UID).
Together, these components ensure that user services can depend on network-online.target in the user instance, even though the real network readiness signal originates at the system level.
Enabling User systemd Without an Active Login
A key challenge with user systemd instances is lifecycle: by default, they are tied to interactive logins. If the user is not logged in, the user systemd instance may not exist, which prevents user services from starting at boot.
The installation script addresses this by enabling linger:
loginctl enable-linger $USER
With linger enabled, the user’s systemd instance can run even when no session is active. This is a prerequisite for starting user services during the boot process.
Creating a User-Level Network-Online Marker
In the user systemd directory (~/.config/systemd/user), the setup installs a minimal network-online.target unit:
[Unit]
Description=User-level Network is Online (marker only)
Documentation=man:systemd.special(7)
This unit is intentionally simple: it does not implement networking logic or checks. Its purpose is to provide a synchronization point so that user services can declare dependencies like:
After=network-online.targetWants=network-online.target
In other words, it acts as a “ready” flag inside the user instance.
Bridging the System Target to the User Instance
The real bridging happens via the system-level service template user-network-online@.service:
[Unit]
Description=Trigger user-level network-online.target for %i
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
User=%i
Environment=XDG_RUNTIME_DIR=/run/user/%i
ExecStart=/usr/bin/systemctl --user start network-online.target
[Install]
WantedBy=multi-user.target
How It Works
- The service runs after the system’s
network-online.target, meaning it triggers only once the system considers networking ready. -
It runs as a one-shot task and executes:
systemctl --user start network-online.target
The
XDG_RUNTIME_DIR=/run/user/%ienvironment is critical. It pointssystemctl --userat the correct runtime directory for the target user instance, ensuring the command reaches the intended user systemd manager rather than failing due to missing session context.
Ensuring It Starts Automatically at Boot
The install script wires everything together:
#!/bin/sh
loginctl enable-linger $USER
sudo cp -t /etc/systemd/system/ user-network-online@.service
sudo systemctl daemon-reload
USER_SYSTEMD_PATH="$HOME"/.config/systemd/user
mkdir -p "$USER_SYSTEMD_PATH"
cp -t "$USER_SYSTEMD_PATH" network-online.target
systemctl --user daemon-reload
sudo systemctl enable --now user-network-online@$(id -u).service
Key Steps
- Installs the system unit into
/etc/systemd/system/and reloads systemd. - Installs the user target into
~/.config/systemd/user/and reloads the user daemon. -
Enables and starts the templated system service for the current user’s UID:
user-network-online@<UID>.service
Because the unit is installed with WantedBy=multi-user.target, it will run during the normal boot sequence. As soon as the system reaches network-online.target, it triggers the user’s network-online.target, allowing user services to start in an orderly and dependency-driven way.
Practical Outcome
With this bridge in place:
- The system decides when networking is “online.”
- The user systemd instance receives an equivalent “network online” signal.
- User services can safely depend on
network-online.targetwithout implementing their own network checks. - Everything starts automatically at boot, even when the user is not logged in, thanks to linger.
This pattern is lightweight, explicit, and aligns well with systemd’s dependency model—making it a solid foundation for user-managed background services that must wait for reliable network availability.
Top comments (0)