Self-hosting
The gateway must run where your apps can reach it. It's a single Node process with no database and no external services, so hosting it is deliberately boring.
Know the failure mode: the gateway sits in the request path
This is a proxy, not a tap - it is not fail-open. If the gateway process is down, your apps' LLM calls fail at the connection: the SDK sees connection refused, runs its own retries (most SDKs retry a handful of times over a few seconds), and then surfaces an error to your app. Nothing queues, nothing silently falls through to the provider.
Two consequences for anything beyond local development:
- Run it supervised - under systemd, Docker with a restart policy, or any process manager, so a crash or reboot brings it straight back (examples below).
- Keep a kill switch. Integration is just a base URL, so the fallback is equally small: unset
OPENAI_BASE_URL/ANTHROPIC_BASE_URL(or whatever base URL you set) in the consuming app and restart it - calls go directly to the provider again. You lose telemetry while it's off, not availability. Caveat: this assumes apps carry their own provider keys (the default pass-through setup). If you rely on centrally injected keys (configkeys/keyEnv), the apps have nothing to authenticate with when they bypass the gateway - keep provider keys available to the apps if you want the kill switch to work.
Run it as a long-lived service
# on the box your apps call
npm install -g ai-command-center
aicc start --host 0.0.0.0 --port 4321 --data-dir /var/lib/aiccThen point apps at http://that-host:4321/…. Create the admin account immediately so it isn't left open on the network.
systemd unit
[Unit] Description=AI Command Center After=network.target [Service] ExecStart=/usr/bin/aicc start --host 0.0.0.0 --port 4321 --data-dir /var/lib/aicc Restart=on-failure Environment=NODE_ENV=production User=aicc [Install] WantedBy=multi-user.target
Docker / docker-compose (recommended)
Pin the npm version in the image so a container rebuild can't silently change gateway behavior under your apps:
FROM node:22-alpine RUN npm install -g ai-command-center@0.2.1 # pin - upgrade deliberately VOLUME /data EXPOSE 4321 ENV AICC_DATA_DIR=/data CMD ["aicc","start","--host","0.0.0.0","--no-open"]
The container binds 0.0.0.0 inside its own network namespace (so the port mapping works), while the host port stays on 127.0.0.1 - the gateway is reachable from the box, not the network. Drop the 127.0.0.1: prefix only when you intend to share it (and create the admin account first):
services:
aicc:
build: .
restart: unless-stopped # survives crashes and reboots
ports:
- "127.0.0.1:4321:4321" # host-local only; remove the prefix to share
volumes:
- aicc-data:/data # telemetry + auth survive image rebuilds
volumes:
aicc-data:docker compose up -d --build
Behind a reverse proxy (recommended for anything shared)
Terminate TLS and forward to the gateway. Keep streaming working by disabling response buffering:
location / {
proxy_pass http://127.0.0.1:4321;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_buffering off; # important for SSE / streaming
proxy_read_timeout 3600s;
}Data & backups
- All telemetry is append-only JSONL in the data dir (
events.jsonl); auth lives inauth.json(0600). - Back up the data dir; that's the whole state. No migrations, no schema.
- JSONL + in-memory aggregation is comfortable into the hundreds of thousands of records. Past that, the storage layer is intentionally small and swappable (SQLite/Postgres).
Company build
Run the same binary with a preset for branding + defaults, and keep secrets in your own config file:
aicc start --preset example --config /etc/aicc/prod.json