Run Defender on a headless Linux host
Run Defender as a local service on a headless Linux host, configure supported agents, verify local capture, enroll for managed upload when required, and restore settings when removing it.
- Unprivileged serviceRuns without a desktop UI
- Enroll for uploadLocal capture works without enrollment
- Local loopbackNot a shared cluster gateway
agent-rs-mitm runs Defender as an unprivileged service on Debian 13 or newer, Fedora, and Amazon Linux 2023. Use it for supported agents on one Linux host. It is a local service, not a shared Egress Gateway. For a shared gateway, see Deploy Egress Gateway on Kubernetes.
The package does not configure the system proxy, trust its certificate authority (CA), or enroll the host. You can configure agents and verify local capture before enrollment. Even when CAPTURE_REQUIRE_ENROLLMENT=1, local capture remains available before enrollment; device events are withheld from managed upload until enrollment succeeds.
Install and start the service
Obtain the package for the host architecture from Chaos Labs, then install it with the operating system's package manager:
sudo apt install ./agent-rs-mitm_VERSION-1_amd64.deb
# or
sudo dnf install ./agent-rs-mitm-VERSION-1.x86_64.rpmThe package creates an unprivileged agent-rs service account and leaves the service disabled. Start it once to generate the host-specific CA, then check its logs:
sudo systemctl start agent-rs-mitm
sudo journalctl -u agent-rs-mitm -n 50 --no-pager
Configure the local service
Create /etc/agent-rs/mitm.env from this deployment example and replace the capture API placeholder with the value supplied by Chaos Labs:
# Local TLS-intercepting listener for explicitly configured clients.
MITM_LISTEN_ADDR=127.0.0.1:9001
# Loopback relay, status, and capture-inspection API.
PROXY_LISTEN_ADDR=127.0.0.1:9000
# Persistent per-install CA material.
MITM_CA_PATH=/var/lib/agent-rs/ca.pem
MITM_CA_KEY_PATH=/var/lib/agent-rs/ca-key.pem
# Local service and capture state.
CAPTURE_STATE_DB_PATH=/var/lib/agent-rs/agent-state.sqlite
CAPTURE_LOCAL_SQLITE_ENABLED=1
CAPTURE_LOCAL_SQLITE_PATH=/var/lib/agent-rs/exchanges.sqlite
AGENT_USE_OS_KEYSTORE=0
# Managed upload. A nonempty CAPTURE_API_URL enables upload.
AGENT_RS_MITM_MANAGED_ENABLED=1
CAPTURE_API_URL=https://<capture-api-provided-by-chaos-labs>
# When set to 1, device events wait for enrollment before managed upload.
CAPTURE_REQUIRE_ENROLLMENT=1
# Headless capture scope.
PROCESS_LINEAGE_ENABLED=0
WORKMEMORY_ROUTER_SHADOW_OBSERVATION_ENABLED=0
GATEWAY_POLICY_ENFORCEMENT_ENABLED=0
# Journald logging and redacted local inspection.
LOG_FORMAT=json
RUST_LOG=info,agent_rs=debug
CAPTURE_INSPECTOR_UNREDACTED=0Keep both listeners on loopback. The package's systemd unit reads this file as the unprivileged agent-rs user and stores state under /var/lib/agent-rs. Do not place an onboarding token in the file.
Restart the service to apply the local configuration. You can configure agents and verify local capture before enrollment.
Enroll for managed upload
Enroll when your organization requires managed upload. Obtain a current onboarding ID token and pass it to the enrollment command on standard input. Replace the identity placeholders with the organization and identity-provider values supplied during onboarding:
sudo systemctl restart agent-rs-mitm
sudo -v
read -r -s -p "Onboarding token: " CORTEX_ONBOARDING_TOKEN
printf '\n'
printf '%s\n' "$CORTEX_ONBOARDING_TOKEN" | sudo agent-rs-mitm onboard \
--provider-id <provider-id> \
--organization-domain <example.com> \
--client-id <user@example.com>
unset CORTEX_ONBOARDING_TOKENFor unattended provisioning, pipe the token directly from the approved deployment secret manager. Do not write it to a file or put it on the command line. The token is exchanged once and is not stored. Successful enrollment creates a per-device signing key under /var/lib/agent-rs; subsequent capture uploads use device-signature headers. If enrollment fails while CAPTURE_REQUIRE_ENROLLMENT=1, local capture remains available but device events are withheld from managed upload until enrollment succeeds.
Review and trust the CA
Review the generated certificate fingerprint before adding it to system trust:
sudo openssl x509 -in /var/lib/agent-rs/ca.pem \
-noout -fingerprint -sha256
sudo agent-rs-mitm-trust install
sudo agent-rs-mitm-trust status
sudo systemctl enable agent-rs-mitmOnly applications using the TLS-intercepting listener need this CA. Browser-specific certificate stores may require a separate explicit import. Configure only the browser or application being inspected to use 127.0.0.1:9001 as its HTTP and HTTPS proxy.
Configure command-line agents
Run cli commands as the Unix user who runs the agents, without sudo. Cortex refuses to configure tools as root.
agent-rs-mitm cli detect
agent-rs-mitm cli configure --all
agent-rs-mitm cli status--all configures only detected installations. To configure selected tools, name them explicitly:
agent-rs-mitm cli configure claude codex gemini| Tool | Selector | Connection path |
|---|---|---|
| Claude Code | claude | Local relay |
| Codex | codex | Local relay |
| Gemini CLI | gemini | Local relay |
| Grok CLI | grok | Local relay |
| Pi | pi_dev | Local relay |
| OpenCode | opencode | Local relay |
| OpenClaw | openclaw | Local relay |
| Cursor CLI | cursor_cli | Scoped launch shim through the TLS listener |
Provider-native base URLs use http://127.0.0.1:9000 and do not require CA trust. Cursor CLI has no base-URL setting, so install the Cortex Defender CA before configuring it. Restart existing agent processes after configuration.
Verify local capture
Check service and capture health without exposing credentials:
curl --fail --silent http://127.0.0.1:9000/status
sudo journalctl -u agent-rs-mitm -n 50 --no-pagerThen run a configured agent, send a test prompt, and run agent-rs-mitm cli status. Confirm that the tool is configured, its service forwarding state is active, and the provider responds.
For local diagnostics, routine journald records contain metadata rather than request or response bodies. Capture summaries and details are available only through the loopback inspection API:
curl --fail --silent http://127.0.0.1:9000/captures/recent/summary
curl --fail --silent http://127.0.0.1:9000/captures/recent
curl --fail --silent \
http://127.0.0.1:9000/status/captures/<exchange-id>A provider response verifies local forwarding. A recent capture from the loopback inspection API verifies local capture. Neither result proves that the host uploaded activity to Cortex.
The default CAPTURE_INSPECTOR_UNREDACTED=0 scrubs local paths, inline media, and policy-hidden content. Change it only on a controlled host when the full local payload is required, then restart the service.
Verify managed upload
After enrollment, run another test prompt and confirm that the capture appears under the expected person in the relevant user profile in Cortex Atlas. That matching record verifies managed upload and attribution. With CAPTURE_REQUIRE_ENROLLMENT=1, an unenrolled host can still capture locally while its device events remain withheld from upload.
Restore configuration and remove Cortex Defender
Restore every managed tool as the owning Unix user before disabling the relay or uninstalling the package:
agent-rs-mitm cli restore --allRestart the affected tools and verify they connect directly to their providers. Then remove the trust anchor and package:
sudo agent-rs-mitm-trust remove
sudo dnf remove agent-rs-mitm
# or: sudo apt remove agent-rs-mitmThe listener has no client authentication. Do not bind it to 0.0.0.0 or enable non-loopback access. For remote inspection, use an authenticated SSH tunnel instead of exposing the proxy port.
Package removal preserves /var/lib/agent-rs so an upgrade does not silently rotate a previously trusted CA. After confirming that captures and the CA are no longer needed, an administrator may remove that directory through the organization's approved data-removal process.