Headless server deployment
Production servers, CI runners, build VMs — anywhere there’s no GUI but you still want CMDOP. This guide covers install, daemonize, verify, and the usual gotchas.
Prerequisites
- 64-bit Linux, macOS, or Windows.
- Outbound HTTPS to the CMDOP relay (no inbound ports needed).
- An OAuth login or a workspace API key.
Step 1 — install the agent
Linux / macOS:
curl -fsSL https://cmdop.com/install.sh | shFor unattended provisioning (no interactive prompts):
curl -fsSL https://cmdop.com/install.sh | sh -s -- --no-promptThe installer drops the cmdop binary into /usr/local/bin/ (or ~/.local/bin/ for unprivileged installs).
Step 2 — authenticate
Two paths:
API key (recommended for headless):
cmdop connect key set "$CMDOP_API_KEY" --workspace acme-prodOAuth (interactive):
cmdop login --headless
# Open the URL on a different machine to complete device flow.API keys survive member churn and don’t need refresh — better fit for headless.
Step 3 — register the machine
cmdop connectThe agent registers under the OS hostname by default. Override with --name if you want a friendly label distinct from hostname.
Step 4 — daemonize
Linux (systemd)
Create /etc/systemd/system/cmdop-agent.service:
[Unit]
Description=CMDOP agent
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=cmdop
ExecStart=/usr/local/bin/cmdop agent start --foreground
Restart=on-failure
RestartSec=5
Environment="CMDOP_API_KEY=replace-me-or-load-from-credentials-store"
[Install]
WantedBy=multi-user.targetThen:
sudo systemctl daemon-reload
sudo systemctl enable --now cmdop-agent
sudo systemctl status cmdop-agentmacOS (launchd)
CMDOP includes a launchd template:
cmdop service install # writes ~/Library/LaunchAgents/com.cmdop.agent.plist
cmdop service startWindows
cmdop service install
Start-Service cmdop-agentStep 5 — verify
cmdop agent statusExpect ONLINE and a recent heartbeat. From another machine:
cmdop connect --list
# headless-server-01 ONLINE 2s ago
cmdop connect headless-server-01 exec 'uname -a'Step 6 — set permissions for headless
Without an attached UI, asks would time out and end up denied. Two safe choices:
# Strict + explicit allowlist
cmdop permissions mode strict
cmdop permissions allow 'execute_command(systemctl status *)'
cmdop permissions allow 'read_file(/var/log/**)'Or:
# Bypass for fully trusted sandbox VMs only
cmdop permissions mode bypassSee Modes for the full picture.
Logs
cmdop agent logs -fLogs live at <LogDir>/agent.log (lumberjack-rotated by size, 10 MB × 5 files). For external shipping see Log rotation.
Updates
cmdop updateOr enable auto-update — see Auto-update.
Common pitfalls
- No outbound HTTPS — the agent can’t reach the relay. Open egress to
*.cmdop.com:443. - PATH issues under systemd — use absolute paths for the binary.
- Missing user —
User=cmdopmust exist; create withuseradd -r -s /sbin/nologin cmdopor run as your existing service user. - API key not loaded — read from a credentials manager (HashiCorp Vault, AWS Secrets Manager) rather than embedding in the unit file.
Treat the workspace API key like a database password. Use a secrets store or systemd credentials, not a literal Environment= line in version control.
The daemon talks outbound only. No inbound port needs to open. CGNAT, restrictive corporate firewalls, and behind-NAT laptops all work.