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.