Onboard: auto-enable systemd lingering on Linux
This commit is contained in:
committed by
Peter Steinberger
parent
949ea38ef5
commit
de153a40d0
@@ -188,6 +188,14 @@ Then enable the service:
|
|||||||
systemctl --user enable --now clawdbot-gateway.service
|
systemctl --user enable --now clawdbot-gateway.service
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**Alternative (system service)** - for always-on or multi-user servers, you can
|
||||||
|
install a systemd **system** unit instead of a user unit (no lingering needed).
|
||||||
|
Create `/etc/systemd/system/clawdbot-gateway.service`, set `User=` and
|
||||||
|
`WorkingDirectory=`, then enable with:
|
||||||
|
```
|
||||||
|
sudo systemctl enable --now clawdbot-gateway.service
|
||||||
|
```
|
||||||
|
|
||||||
## Supervision (Windows scheduled task)
|
## Supervision (Windows scheduled task)
|
||||||
- Onboarding installs a Scheduled Task named `Clawdbot Gateway` (runs on user logon).
|
- Onboarding installs a Scheduled Task named `Clawdbot Gateway` (runs on user logon).
|
||||||
- Requires a logged-in user session; for headless setups use a system service or a task configured to run without a logged-in user (not shipped).
|
- Requires a logged-in user session; for headless setups use a system service or a task configured to run without a logged-in user (not shipped).
|
||||||
|
|||||||
@@ -109,6 +109,18 @@ pnpm clawdbot health
|
|||||||
- Keep `~/clawd` and `~/.clawdbot/` as “your stuff”; don’t put personal prompts/config into the `clawdbot` repo.
|
- Keep `~/clawd` and `~/.clawdbot/` as “your stuff”; don’t put personal prompts/config into the `clawdbot` repo.
|
||||||
- Updating source: `git pull` + `pnpm install` (when lockfile changed) + keep using `pnpm gateway:watch`.
|
- Updating source: `git pull` + `pnpm install` (when lockfile changed) + keep using `pnpm gateway:watch`.
|
||||||
|
|
||||||
|
## Linux (systemd user service)
|
||||||
|
|
||||||
|
Linux installs use a systemd **user** service. By default, systemd stops user
|
||||||
|
services on logout/idle, which kills the Gateway. Enable lingering:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo loginctl enable-linger $USER
|
||||||
|
```
|
||||||
|
|
||||||
|
For always-on or multi-user servers, consider a **system** service instead of a
|
||||||
|
user service (no lingering needed). See `docs/gateway.md` for the systemd notes.
|
||||||
|
|
||||||
## Related docs
|
## Related docs
|
||||||
|
|
||||||
- `docs/gateway.md` (Gateway runbook; flags, supervision, ports)
|
- `docs/gateway.md` (Gateway runbook; flags, supervision, ports)
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ export async function ensureSystemdUserLingerInteractive(params: {
|
|||||||
params.reason ??
|
params.reason ??
|
||||||
"Systemd user services stop when you log out or go idle, which kills the Gateway.";
|
"Systemd user services stop when you log out or go idle, which kills the Gateway.";
|
||||||
const actionNote = params.requireConfirm
|
const actionNote = params.requireConfirm
|
||||||
? "We can enable lingering now (needs sudo; writes /var/lib/systemd/linger)."
|
? "We can enable lingering now (may require sudo; writes /var/lib/systemd/linger)."
|
||||||
: "Enabling lingering now (needs sudo; writes /var/lib/systemd/linger).";
|
: "Enabling lingering now (may require sudo; writes /var/lib/systemd/linger).";
|
||||||
await prompter.note(`${reason}\n${actionNote}`, title);
|
await prompter.note(`${reason}\n${actionNote}`, title);
|
||||||
|
|
||||||
if (params.requireConfirm && prompter.confirm) {
|
if (params.requireConfirm && prompter.confirm) {
|
||||||
@@ -60,6 +60,15 @@ export async function ensureSystemdUserLingerInteractive(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resultNoSudo = await enableSystemdUserLinger({
|
||||||
|
env,
|
||||||
|
user: status.user,
|
||||||
|
});
|
||||||
|
if (resultNoSudo.ok) {
|
||||||
|
await prompter.note(`Enabled systemd lingering for ${status.user}.`, title);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const result = await enableSystemdUserLinger({
|
const result = await enableSystemdUserLinger({
|
||||||
env,
|
env,
|
||||||
user: status.user,
|
user: status.user,
|
||||||
|
|||||||
@@ -489,6 +489,17 @@ export async function runOnboardingWizard(
|
|||||||
nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
|
nextConfig = applyWizardMetadata(nextConfig, { command: "onboard", mode });
|
||||||
await writeConfigFile(nextConfig);
|
await writeConfigFile(nextConfig);
|
||||||
|
|
||||||
|
await ensureSystemdUserLingerInteractive({
|
||||||
|
runtime,
|
||||||
|
prompter: {
|
||||||
|
confirm: prompter.confirm,
|
||||||
|
note: prompter.note,
|
||||||
|
},
|
||||||
|
reason:
|
||||||
|
"Linux installs use a systemd user service by default. Without lingering, systemd stops the user session on logout/idle and kills the Gateway.",
|
||||||
|
requireConfirm: false,
|
||||||
|
});
|
||||||
|
|
||||||
const installDaemon = await prompter.confirm({
|
const installDaemon = await prompter.confirm({
|
||||||
message: "Install Gateway daemon (recommended)",
|
message: "Install Gateway daemon (recommended)",
|
||||||
initialValue: true,
|
initialValue: true,
|
||||||
@@ -539,16 +550,6 @@ export async function runOnboardingWizard(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await ensureSystemdUserLingerInteractive({
|
|
||||||
runtime,
|
|
||||||
prompter: {
|
|
||||||
confirm: prompter.confirm,
|
|
||||||
note: prompter.note,
|
|
||||||
},
|
|
||||||
reason:
|
|
||||||
"Linux installs use a systemd user service. Without lingering, systemd stops the user session on logout/idle and kills the Gateway.",
|
|
||||||
requireConfirm: true,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await sleep(1500);
|
await sleep(1500);
|
||||||
|
|||||||
Reference in New Issue
Block a user