From fc24e063244ff6d3b0d6f6236472f4286c0d89f7 Mon Sep 17 00:00:00 2001 From: Federico Jaramillo Martinez Date: Sat, 9 May 2026 20:20:44 +0200 Subject: [PATCH] Recommend systemd user lingering --- README.md | 19 +++++++++++++++++++ src/cli.ts | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7770965..dca28c8 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,15 @@ Recommended install uses npm plus systemd user services: ```bash npm install -g @jmfederico/pi-web + +# Recommended on servers: keep user services running after logout/reboot. +sudo loginctl enable-linger "$USER" + pi-web install ``` +`loginctl enable-linger` is optional for local desktop use, but recommended on servers. It lets the user systemd manager start at boot and continue running after you log out, so Pi Web remains available without an active SSH/login session. + This writes and starts: - `~/.config/systemd/user/pi-web-sessiond.service` @@ -102,6 +108,12 @@ This writes and starts: The generated services run through `bash -lc` so they see a shell environment similar to running `pi` from your terminal. +To check whether lingering is enabled: + +```bash +loginctl show-user "$USER" -p Linger +``` + Open . Useful commands: @@ -236,6 +248,13 @@ Restart=no WantedBy=default.target ``` +On servers, enable persistent user services so the user systemd manager starts at boot and remains running after logout: + +```bash +sudo loginctl enable-linger "$USER" +loginctl show-user "$USER" -p Linger +``` + After creating or changing units: ```bash diff --git a/src/cli.ts b/src/cli.ts index f2f2507..3b60611 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node import { existsSync } from "node:fs"; import { mkdir, rm, writeFile } from "node:fs/promises"; -import { homedir } from "node:os"; +import { homedir, userInfo } from "node:os"; import { dirname, join, resolve } from "node:path"; import { spawnSync } from "node:child_process"; import { defaultPiWebConfigPath, examplePiWebConfig } from "./config.js"; @@ -32,6 +32,16 @@ function hasCommand(command: string): boolean { return capture("/usr/bin/env", ["bash", "-lc", `command -v ${command}`]).status === 0; } +function isLingerEnabled(): boolean | undefined { + if (!hasCommand("loginctl")) return undefined; + const result = capture("loginctl", ["show-user", userInfo().username, "-p", "Linger"]); + if (result.status !== 0) return undefined; + const value = result.stdout.trim(); + if (value === "Linger=yes") return true; + if (value === "Linger=no") return false; + return undefined; +} + function parseInstallOptions(args: string[]): InstallOptions { const options: InstallOptions = { host: "127.0.0.1", port: "8504" }; for (let i = 0; i < args.length; i += 1) { @@ -136,6 +146,16 @@ async function install(args: string[]): Promise { console.log(`\nPi Web is installed and starting.`); console.log(`Config: ${configPath}`); console.log(`Open: http://${options.host === "0.0.0.0" ? "127.0.0.1" : options.host}:${options.port}`); + + const linger = isLingerEnabled(); + if (linger === false) { + console.log("\nRecommended for server use: keep user services running after logout/reboot:"); + console.log(` sudo loginctl enable-linger ${userInfo().username}`); + } else if (linger === undefined) { + console.log("\nRecommended for server use: enable systemd user lingering so services survive logout/reboot:"); + console.log(` sudo loginctl enable-linger ${userInfo().username}`); + } + console.log("\nUseful commands:"); console.log(" pi-web status"); console.log(" pi-web logs"); @@ -181,6 +201,17 @@ function doctor(): void { if (output !== "") console.log(` ${output.split("\n")[0] ?? ""}`); } + const linger = isLingerEnabled(); + if (linger === true) { + console.log("✓ systemd user lingering enabled"); + } else if (linger === false) { + console.log("✗ systemd user lingering disabled"); + console.log(` Recommended on servers: sudo loginctl enable-linger ${userInfo().username}`); + } else { + console.log("? systemd user lingering unknown"); + console.log(` Recommended on servers: sudo loginctl enable-linger ${userInfo().username}`); + } + if (failed) { console.log("\nIf a command works in your terminal but fails here, make sure your bash login files set PATH the same way."); process.exitCode = 1;