Admin Commands
CLI reference for podspawn machine management and monitoring commands
These commands manage machines and monitor system health. list, stop, and doctor work in both local and server mode. The rest (cleanup, status, etc.) are server-side administration commands.
stop, remove-user --force, and remove-project are destructive operations that immediately destroy containers. Connected sessions will be terminated and unsaved work lost.
list
Lists all machines (local mode) or active sessions (server mode) tracked in the state database.
podspawn listLocal mode output
In local mode, list shows machines with their name, status, image, and age. No internal container names are shown:
NAME STATUS IMAGE AGE
mydev running ubuntu:24.04 2h30m
scratch running alpine:3.20 5mHeaders are bold and status is color-coded in the terminal: green for running, yellow for grace period.
Server mode output
In server mode, list shows per-user sessions with connection counts and lifetime tracking:
| Column | Description |
|---|---|
| USER | Username that owns the session |
| PROJECT | Project name, or (default) for non-project sessions |
| CONTAINER | Docker container name |
| STATUS | running or grace_period |
| CONNS | Number of active SSH connections to this session |
| AGE | Time since session was created (e.g., 2h30m, 45s) |
| LIFETIME LEFT | Time until max lifetime expires, or expired |
USER PROJECT CONTAINER STATUS CONNS AGE LIFETIME LEFT
alice backend podspawn-alice-backend running 2 1h30m 6h30m
bob (default) podspawn-bob grace_period 0 45m 7h15m
carol frontend podspawn-carol-frontend running 1 5m 7h55mWhen no machines exist:
No machines.stop
Stops a machine and destroys its container, companion services, and network.
podspawn stop <name>
podspawn stop <user[@project]>Argument format
The argument is interpreted differently depending on mode:
Local mode: The argument is the machine name. The current $USER is used automatically.
| Format | Meaning |
|---|---|
mydev | Stop the machine named "mydev" |
Server mode: The argument is user[@project].
| Format | Meaning |
|---|---|
alice | Stop alice's default (non-project) session |
alice@backend | Stop alice's session for the backend project |
What it destroys
Examples
# Local mode: stop a machine by name
podspawn stop mydev
# Server mode: stop alice's default session
podspawn stop alice
# Server mode: stop alice's backend project session
podspawn stop alice@backendOutput
✓ Stopped machine mydevIf no active machine exists:
Error: no active machine "mydev"This immediately destroys the container. Any unsaved work inside the container is lost. Connected SSH sessions will be terminated.
cleanup
Reconciles orphaned containers and enforces time-to-live limits. Runs a single pass by default, or loops continuously in daemon mode.
podspawn cleanup [flags]Flags
| Flag | Default | Description |
|---|---|---|
--daemon | false | Run as a background cleanup daemon |
--interval | 60s | Cleanup interval in daemon mode (Go duration format) |
What each cleanup pass does
Examples
# Single cleanup pass
podspawn cleanup
# Run as a daemon with default 60s interval
podspawn cleanup --daemon
# Custom interval
podspawn cleanup --daemon --interval 30sRunning with systemd
Podspawn ships systemd units in the deb/rpm packages. You can also use them manually:
# Shipped at /etc/systemd/system/podspawn-cleanup.service
sudo systemctl enable --now podspawn-cleanup.serviceThis runs podspawn cleanup --daemon --interval 60s as a long-lived process.
# Shipped at /etc/systemd/system/podspawn-cleanup.timer
sudo systemctl enable --now podspawn-cleanup.timerThis runs a single cleanup pass every 60 seconds via systemd's timer infrastructure.
The cleanup command is not in the critical path. The system works without it, just with slightly delayed cleanup. Orphaned containers from crashes will be caught on the next pass.
status
Shows system-level metrics about sessions and containers. Supports both human-readable and Prometheus exposition formats.
podspawn status [flags]Flags
| Flag | Default | Description |
|---|---|---|
--prometheus | false | Output in Prometheus exposition format |
Human-readable output
Sessions: 3 total (2 running, 1 grace)
Connections: 4 active
Containers: 3 in Docker
Oldest: 2h30m| Metric | Description |
|---|---|
| Sessions | Total tracked sessions, broken down by running and grace period |
| Connections | Sum of active SSH connections across all sessions |
| Containers | Docker containers with the managed-by=podspawn label |
| Oldest | Age of the longest-running session |
Prometheus output
podspawn status --prometheus# HELP podspawn_sessions_total Total tracked sessions
# TYPE podspawn_sessions_total gauge
podspawn_sessions_total 3
# HELP podspawn_sessions_running Sessions in running state
# TYPE podspawn_sessions_running gauge
podspawn_sessions_running 2
# HELP podspawn_sessions_grace Sessions in grace period
# TYPE podspawn_sessions_grace gauge
podspawn_sessions_grace 1
# HELP podspawn_connections_total Total active SSH connections
# TYPE podspawn_connections_total gauge
podspawn_connections_total 4
# HELP podspawn_containers_docker Docker containers with managed-by=podspawn
# TYPE podspawn_containers_docker gauge
podspawn_containers_docker 3
# HELP podspawn_oldest_session_seconds Age of the oldest session in seconds
# TYPE podspawn_oldest_session_seconds gauge
podspawn_oldest_session_seconds 9000Monitoring integration
Scrape the Prometheus output with a textfile collector or a cron job:
# Write metrics for node_exporter textfile collector
podspawn status --prometheus > /var/lib/prometheus/node-exporter/podspawn.promlist-users
Lists all registered container users by scanning the key directory.
podspawn list-usersExample output
alice (3 keys)
ci-runner (1 key)
deploy (2 keys)remove-user
Removes a container user by deleting their key file and optionally destroying their active sessions.
podspawn remove-user <username> [flags]Flags
| Flag | Default | Description |
|---|---|---|
--force | false | Destroy active sessions without confirmation |
--purge | false | Also delete the user's persistent home directory |
Behavior
/etc/podspawn/keys/--force is not set, returns an error--force, destroys all active sessions (containers, services, networks)--purge, removes the user's persistent home directory at <homes_dir>/<username>--purge, prints a notice if a persistent home directory exists so you can decide whether to keep itExamples
# Remove user with no active sessions
podspawn remove-user alice
# Force-remove user with active sessions
podspawn remove-user alice --force
# Remove user and delete their persistent home directory
podspawn remove-user alice --force --purgeWithout --purge, the home directory is left in place:
removed user alice
NOTE: persistent home dir exists at /var/lib/podspawn/homes/alice; use --purge to delete itWith --force, all active sessions are immediately destroyed. Connected SSH sessions will be terminated and unsaved work lost. With --purge, the user's persistent home directory is permanently deleted.
doctor
Runs preflight checks to verify that podspawn is correctly configured. The checks adapt based on what's installed: if /etc/podspawn/config.yaml exists (i.e., server-setup has been run), doctor runs the full set of checks including sshd validation. Without the server config, it only checks Docker and local state.
podspawn doctorAdaptive checks
Runs when /etc/podspawn/config.yaml does not exist.
Checks: Docker daemon, Docker socket, state directory, lock directory, disk space, default image.
Runs when /etc/podspawn/config.yaml exists.
All local checks plus: OpenSSH version, sshd config, AuthorizedKeysCommand, podspawn config dir, key directory.
Local mode output
After a local-only install (no server-setup):
podspawn doctor
[pass] Docker daemon
[pass] Docker socket
[pass] state directory
[pass] lock directory
[pass] disk space
[pass] default image
6 passed, 0 warnings, 0 failedServer mode output
After running server-setup:
podspawn doctor
[pass] Docker daemon
[pass] Docker socket
[pass] OpenSSH version
[pass] sshd config valid
[pass] AuthorizedKeysCommand
[pass] podspawn config dir
[pass] key directory
[pass] state directory
[pass] lock directory
[pass] disk space
[pass] default image
11 passed, 0 warnings, 0 failedChecks
remove-project
Deregisters a project and removes its local clone.
podspawn remove-project <name>Behavior
- Removes the project's local repository clone from
/var/lib/podspawn/projects/ - Removes the project entry from
projects.yaml - Does NOT remove the Docker image (prints a hint to
docker rmi)
Example
podspawn remove-project backend
# removed project backend
# note: image podspawn/backend:podfile-abc123 still exists; run 'docker rmi ...' to remove itHow is this guide?