Skip to content

Autostart

runwisp service install registers the daemon with systemd or launchd so it starts on boot.

Terminal window
sudo runwisp service install # system service (Linux, WSL)
runwisp service install --local # per-user service (Linux, WSL, macOS)

The system service is what you want on a server. It writes /etc/systemd/system/runwisp.service, runs the daemon as root, and starts it now. There’s one per host. It uses /etc/runwisp/runwisp.toml and /var/lib/runwisp unless you pass --config or --data.

--local installs a service that runs as you:

  • Linux and WSL: ~/.config/systemd/user/runwisp-<fingerprint>.service. The installer turns on linger (one sudo loginctl enable-linger prompt) so the daemon keeps running after you log out.
  • macOS: ~/Library/LaunchAgents/com.runwisp.daemon.<fingerprint>.plist. macOS has no system-wide install yet, so --local is required there.

The fingerprint (like bright-falcon) lets several per-user daemons run on one host. Don’t combine sudo with --local; the installer refuses, because a root user unit would never start.

The installer shows what it will do and asks before writing anything (--yes skips the prompt). It never touches runwisp.toml, and re-running it is safe. All flags are in the CLI reference.

A few things it checks:

  • The binary stays put. The unit points at the binary you ran. A binary in /tmp or the go run cache is refused. Put it somewhere permanent like /usr/local/bin. A Homebrew install points at opt/runwisp, which survives brew upgrade.
  • Root runs only root’s binary. For the system service, a binary that isn’t owned by root (like ~/.local/bin/runwisp) is copied to /usr/local/bin/runwisp first, and the unit runs the copy. Upgrade it with sudo runwisp upgrade.
  • The config is safe to run as root. For the system service, the config file must be owned by root and not writable by group or others.
  • Nothing else holds the data directory. Stop a daemon you started by hand (runwisp stop) before installing.

With --local and the default ./.runwisp data directory, the installer asks whether to keep it or use ~/.local/share/runwisp. A relative --data is turned into an absolute path in the unit.

Terminal window
runwisp service status
RunWisp service status
Installed: yes
Autostart: enabled
Running: yes
Unit file: /etc/systemd/system/runwisp.service (matches recorded settings)
Binary: /usr/local/bin/runwisp
Data dir: /var/lib/runwisp (last write 2026-05-20 10:32:01)
Last start: 2026-05-19 09:00:11 UTC
Logs: sudo journalctl -u runwisp.service

It exits 0 only when the service is installed, enabled, running, and unchanged since install, so you can use it in scripts. See the exit codes.

runwisp status answers “is the daemon up right now?”. runwisp service status answers “will it come back after a reboot?”.

Terminal window
runwisp restart # restart the daemon
runwisp stop # stop it; it starts again on the next boot

When the daemon runs under an installed unit, both commands go through systemctl or launchctl, so the service manager always knows the real state. They find the installed unit on their own. Pass --local only if both a system and a per-user unit exist.

For config edits, runwisp reload is usually enough.

A daemon without RUNWISP_PASSWORD makes up a new password on every boot. So when auth is on and you haven’t set one, service install generates a password, saves it in a 0600 file next to the unit, and prints it once:

Generated a Web UI password and saved it to
/etc/systemd/system/runwisp.service.d/password.conf (0600):
curl-battery-staple-hinge
  • Store it right away. runwisp password won’t show it later.
  • Re-installing never changes it, so nobody gets logged out.
  • To rotate it, edit or delete the file and run runwisp restart.
  • To use your own, set RUNWISP_PASSWORD before you install. The installer carries it into the unit (see below) and generates nothing.

See Authentication for how the password works.

A service never sees the shell you installed it from. So service install copies every RUNWISP_* variable set in your shell (RUNWISP_AUTH, RUNWISP_TLS, RUNWISP_TRUSTED_PROXIES, RUNWISP_PASSWORD, and the rest) into a 0600 file next to the unit, runwisp-env.conf, and restarts the daemon to apply it:

Terminal window
sudo RUNWISP_AUTH=off runwisp service install

Put the variables after sudo, or sudo drops them. The file is rewritten on every install: to change a value or remove one, change your shell and install again.

Only RUNWISP_* variables are carried over. For a ${SLACK_URL} in runwisp.toml, pick one of these.

Read the value from a file with ${file:...}. This needs no change to the unit, and runwisp reload picks up a new value:

runwisp.toml
[notifiers.slack-ops]
type = "slack"
webhook_url = "${file:/etc/runwisp/slack.url}"

Or set the variable on the unit with a systemd drop-in:

Terminal window
sudo systemctl edit runwisp
/etc/systemd/system/runwisp.service.d/override.conf
[Service]
Environment=SLACK_URL=https://hooks.slack.com/services/...
# or, one KEY=VALUE per line in a 0600 file:
EnvironmentFile=/etc/runwisp/daemon.env

The daemon reads its environment only when it starts, so run sudo runwisp restart after the edit. service install leaves this file alone.

If only a task’s command needs the value, and not runwisp.toml itself, give that task an env_file, or a secrets_file for a secret.

To keep a daemon connected to a Station across reboots, install it with --station:

Terminal window
sudo runwisp service install --station --url https://station.example.com --token "$TOKEN"

The unit runs runwisp station --no-tui instead of runwisp daemon. Without the flags, --station reads RUNWISP_STATION_URL and RUNWISP_STATION_TOKEN from your shell. The token goes into the 0600 runwisp-env.conf described above, never into the unit, so --print and --dry-run don’t show it. Station mode needs that file, so it isn’t available for a macOS LaunchAgent.

A --local LaunchAgent starts when you log in and runs as you. launchd has no drop-in files, so the installer doesn’t generate a password or copy your environment. Set RUNWISP_PASSWORD and other variables in the plist’s EnvironmentVariables, or get the generated password with runwisp password. The daemon log goes to <data-dir>/daemon.log.

The install works as on Linux. Windows also has to start the WSL distro at login, so the installer ends by printing a PowerShell snippet with your distro name filled in. Run it in Windows:

Terminal window
$Action = New-ScheduledTaskAction -Execute 'wsl.exe' -Argument '~ -d <distro> -- true'
$Trigger = New-ScheduledTaskTrigger -AtLogOn
Register-ScheduledTask -TaskName 'RunWispBoot' -Action $Action -Trigger $Trigger

service install doesn’t touch cron. If cron still runs jobs on the box, the installer tells you to run sudo runwisp takeover. See From cron.

Everything RunWisp knows lives in a few places. Back these up:

  • The data directory, /var/lib/runwisp: run history in runwisp.db (with its runwisp.db-wal and runwisp.db-shm files), run output in logs/, and the self-signed certificate in tls/. Keep tls/ so clients that pinned the certificate still connect.
  • The config, /etc/runwisp/.
  • The unit’s drop-ins, /etc/systemd/system/runwisp.service.d/: the saved password and the carried environment.
  • After a takeover, the crontabs RunWisp reads.

daemon.pid, runwisp.sock and daemon.log are rebuilt on start and don’t need a backup.

The database is SQLite in WAL mode, so copying it while the daemon writes can catch it halfway. Stop the daemon for the copy:

Terminal window
sudo runwisp stop
sudo tar -czf runwisp-backup.tar.gz /var/lib/runwisp /etc/runwisp \
/etc/systemd/system/runwisp.service.d
sudo systemctl start runwisp

For a copy without stopping, use sqlite3 /var/lib/runwisp/runwisp.db ".backup /tmp/runwisp.db" (sqlite3 doesn’t ship with RunWisp) and copy logs/ next to it.

To move RunWisp to a new machine:

  1. Install the same version or a newer one. The database only migrates forward.
  2. Restore the paths above, keeping their owners and the data directory’s 0700 mode.
  3. Run sudo runwisp service install. It keeps the restored password.conf.
  4. If the old machine ran takeover, run sudo runwisp takeover again.

In Docker, back up the volume mounted at /var/lib/runwisp the same way, with the container stopped.

Terminal window
sudo runwisp service uninstall # keep the data directory
sudo runwisp service uninstall --purge # delete it too

Uninstall stops the daemon, turns off autostart, and removes the unit. Your data directory (run history and logs) stays. If takeover retired cron, uninstall gives it back, along with the jobs promote moved out of your crontabs. It lists the tasks and services that stop running before it asks.

--purge also deletes the data directory. It asks you to type delete, even with --yes.