Skip to content

Host Control Tower and share the console URL

The PyPI package contains both the HTTP API and console assets. Run one Python service and open its /console/ route; there is no separate frontend build or static-site deployment. Installing the package does not provision hosting or create a public link. The customer supplies the server, credentials and network.

These instructions describe the implemented v0.3 console. If your installed release predates v0.3, use a published release containing the console or install this checkout locally with python -m pip install ".[api]".

Local computer

Install and generate reader/writer tokens, then run:

python -m pip install "agenticops-control-tower[api]"
agenticops-control-tower serve --database registry.sqlite --host 127.0.0.1 --port 8000

Open http://localhost:8000/console/. Enter your reader token and select Connect / refresh. Tokens must be configured in the server's environment before starting it; the command above reuses those values. The database path is relative to the working directory. Reuse that file across restarts to retain inventory. With no registered agents the console shows an empty fleet; registration and heartbeats populate it.

localhost refers to the computer running the browser. Sharing this URL with someone on a different computer does not give them access to your server.

Another computer on a private network

Bind to the server's network interfaces:

agenticops-control-tower serve --database registry.sqlite --host 0.0.0.0 --port 8000

Allow the intended clients through the host firewall. For a server whose private address is 192.168.1.20, its console URL is http://192.168.1.20:8000/console/. 0.0.0.0 is a bind address, not a browser URL. Use HTTPS through a reverse proxy when sending bearer tokens between machines.

For private access to a remote VM without opening the application port publicly, leave the service bound to 127.0.0.1 and use an SSH tunnel from your computer:

ssh -N -L 8000:127.0.0.1:8000 user@your-server

Then open http://localhost:8000/console/ on your computer. The tunnel carries traffic to the remote service; server token authorization still applies.

Cloud VM, container service or application platform

The same service can run on a cloud VM or a platform that supports a long-running Python web process. Configure these deployment inputs:

Setting Value
Installation python -m pip install "agenticops-control-tower[api]"
Reader secret A generated AGENTICOPS_READ_TOKEN in the platform's secret settings
Writer secret A separate generated AGENTICOPS_WRITE_TOKEN
Persistent storage A writable persistent volume, for example mounted at /data
Start command agenticops-control-tower serve --host 0.0.0.0 --port 8000 --database /data/registry.sqlite
Internal application port 8000, or the port assigned by the platform
Public ingress HTTPS routed to that application port
HTTP readiness check GET /console/ returns 200; this checks shell serving, not authenticated inventory
Shared console URL https://<your-hostname>/console/

If your platform injects a PORT variable, a Bash start command can use:

agenticops-control-tower serve --host 0.0.0.0 --port "${PORT:-8000}" --database /data/registry.sqlite

The CLI does not read PORT automatically. The command requires a shell to expand it; with an exec-array launcher, supply a numeric --port value or use an explicit shell launcher. Create/mount /data before starting the process. Without persistent storage, use in-memory mode by omitting --database, but inventory is lost on restart; writing SQLite to an ephemeral filesystem does not provide durable storage.

For this SQLite deployment use one service instance with its own local persistent volume. Independent replicas have separate inventory; distributed/shared storage and a horizontally scaled control plane are not implemented. Have the platform restart the process after failure and retain configured tokens across redeploys.

A platform-generated HTTPS hostname can be shared immediately after deployment. For your own hostname, configure DNS and a TLS certificate using the platform's custom-domain settings or your reverse proxy. The URL is then, for example, https://tower.example.com/console/. Users supply your reader token after opening that link. A link alone does not grant inventory access.

Route the whole application on the same hostname: /console/, /console/assets/, /agents, /status, /capabilities and /versions. The console fetches its API from the same origin. Hosting only its HTML/assets or routing only /console/ leaves those data requests disconnected. This guide uses a dedicated hostname at the root; hosting beneath another path prefix has not been validated.

Example HTTPS reverse proxy on a VM

Run Control Tower bound to 127.0.0.1:8000. Install/configure Nginx separately and adapt the example configuration with your hostname and existing certificate paths. It redirects HTTP to HTTPS and proxies all application paths to the local service. Expose ports 80/443 and keep 8000 private. On a platform with managed HTTPS ingress, its proxy replaces this step.

Validate your adapted configuration before reloading Nginx:

sudo nginx -t

The example follows the official Nginx proxy module documentation. For process and reverse-proxy deployment guidance, see Uvicorn deployment.

Verify access and troubleshoot

Open your actual console URL, enter the reader token and select Connect / refresh. From a client shell holding that token, verify the same API:

export AGENTICOPS_API_URL='https://tower.example.com'
export AGENTICOPS_TOKEN="$AGENTICOPS_READ_TOKEN"
agenticops-control-tower status

Set AGENTICOPS_READ_TOKEN in this client shell to the deployed value first; client variables are not automatically copied from your cloud server. Setting AGENTICOPS_API_URL changes the CLI target, not the browser console's API origin.

Symptom What to check
Connection refused or timeout Process running, correct bind address/port, firewall and ingress routing
/console/ returns 404 Installed package includes v0.3 console; proxy forwards the full path
Shell loads but inventory fails API routes on the same origin and Authorization header preserved
Reader token required or invalid Browser token matches the running server's configured reader value
Writes return 403 Use the writer value for registration/heartbeats
Inventory disappears after restart Same SQLite file on a persistent volume; same service instance
Console loads but is empty Agents have been registered with this deployment
Evidence shows missing or unavailable Nothing has been pushed for that producer and deployment (Tower never fetches evidence), or the pushed artifact could not be read; see evidence posture

See customer-managed authentication and the runnable examples.