Skip to main content

Run as a systemd service

For production hosts, run the agent as a systemd service so it survives reboots, auto-restarts on crash, and integrates with journalctl. Foreground mode (just orbit-agent in a shell) is fine for first-deploy validation but stops the moment the SSH session closes.

Quickstart: install + enable the unit

sudo tee /etc/systemd/system/orbit-agent.service > /dev/null <<EOF
[Unit]
Description=Orbit Deployment Agent
After=network-online.target

[Service]
User=$(whoami)
Group=$(id -gn)
EnvironmentFile=$HOME/orbit-agent.env
ExecStart=$(command -v orbit-agent)
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now orbit-agent

The heredoc expands $(whoami), $(id -gn), $HOME, and $(command -v orbit-agent) at install time so the resulting unit file is correct for whichever deploy user you ran it as.

v0.5.7+: init --systemd

From v0.5.7+, orbit-agent init can install the systemd unit for you:

sudo orbit-agent init --systemd ...usual flags...

It writes the unit, runs systemctl daemon-reload, and enables + starts the service. Equivalent to the manual heredoc above, just one less step. Requires sudo because /etc/systemd/system/ is root-owned.

v0.7.0+: multiple environments on one host

To run more than one environment on the same server (e.g. staging + production), orbit-agent init --name <instance> --systemd installs a template unit (orbit-agent@.service) and enables an instance from it:

orbit-agent init --name staging    --systemd ...flags...   # → orbit-agent@staging.service
orbit-agent init --name production --systemd ...flags... # → orbit-agent@production.service

Manage each by instance — sudo systemctl status orbit-agent@staging, sudo systemctl restart orbit-agent@production, orbit-agent logs --name staging. The template's EnvironmentFile=<home>/orbit-agent.%i.env selects the right config per instance, which all run as the same OS user. See Multiple environments on one host.

Verify the agent registered

In the dashboard, the environment row should flip to online with a recent last_seen_at. From the host:

systemctl status orbit-agent
# ● orbit-agent.service - Orbit Deployment Agent
# Loaded: loaded (/etc/systemd/system/orbit-agent.service; enabled)
# Active: active (running) since ...
# ...
# INFO orbit_agent: Orbit Agent v0.5.10 starting
# INFO orbit_agent: Registered with Orbit server environment="Production"

Why EnvironmentFile= instead of source ~/orbit-agent.env

systemd's EnvironmentFile= reads the env file directly — no shell to source it through. Foreground mode uses set -a; source ~/orbit-agent.env; set +a to load the file into the current shell; systemd skips that dance.

Restart policy

Restart=on-failure + RestartSec=5 means systemd restarts the agent within 5 seconds of any non-zero exit. The agent treats network errors as recoverable and retries internally, so restarts are rare in practice — they mostly happen during version upgrades or when the env file changes.

If you'd rather have systemd never restart automatically (e.g. during a known-broken debugging window): sudo systemctl edit orbit-agent and override Restart=no.

Switching between foreground and systemd

Foreground → systemd:

# Ctrl-C the foreground agent
sudo systemctl start orbit-agent

systemd → foreground (for ad-hoc debugging):

sudo systemctl stop orbit-agent
set -a; source ~/orbit-agent.env; set +a
orbit-agent

Never run both simultaneously — they'd race on tasks.

Logs

orbit-agent logs is the user-friendly wrapper. It's a thin shell over journalctl -u orbit-agent.service. If you'd rather use journalctl directly:

journalctl -u orbit-agent -f                 # tail (sudo may be needed)
journalctl -u orbit-agent --since "1h ago"
journalctl -u orbit-agent -n 500 --no-pager

sudo-less access requires the deploy user be in the systemd-journal group: sudo usermod -aG systemd-journal $USER (log out + back in).

Common systemd issues

SymptomFix
Failed to start orbit-agent.service: Unit not foundsudo systemctl daemon-reload after creating/editing the unit
status=203/EXECExecStart= path is wrong — re-run command -v orbit-agent and update the unit
Service starts then immediately exits with status=1Token typo or revoked. orbit-agent logs --since "5 minutes ago" shows the registration failure
EnvironmentFile: No such file or directory~/orbit-agent.env is missing. Re-run orbit-agent init to regenerate

Sudo for service reloads (optional)

If your deploys need to reload PHP-FPM or nginx (e.g. an OPcache warmer hook), grant the deploy user passwordless sudo for specific commands only:

sudo tee /etc/sudoers.d/orbit-deploy > /dev/null <<EOF
# Allow the orbit-agent user to reload specific services without a password.
# Scoped to exact commands — does NOT grant general sudo access.
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl reload php8.3-fpm
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl reload nginx
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart php8.3-fpm
EOF

sudo visudo -cf /etc/sudoers.d/orbit-deploy # syntax check

Replace deploy with your deploy user name and php8.3-fpm with your actual PHP-FPM unit name.