Deploying with Docker Compose
The repository ships a docker-compose.yml that brings up the complete single-instance public-beta
stack: the gated axonos service, the HTTP axonos-launcher that spawns per-session desktops, a
postgres ledger, and a coturn TURN server for browser-native WebRTC streaming.
For a single personal desktop, the plain docker run in Installation
is enough. Use Compose when you want the wallet-gated, multi-session platform with billing
and GPU scheduling — the same shape that powers app.axonos.io.
TL;DR
git clone https://github.com/AXDT-INC/AxonOS.git
cd AxonOS
cp env.example .env # then edit secrets — see Configuration
docker compose build
docker compose up -d
# UI: http://HOST:6080/vnc.html
# Gate API: http://HOST:8889
What's in the stack
| Service | Image / build | Role |
|---|---|---|
axonos | Dockerfile → axonos:public-beta | Gate server + billing + session orchestration entrypoint |
axonos-launcher | docker/launcher/Dockerfile | HTTP launcher that spawns per-session desktop containers |
postgres | postgres:15-alpine | Challenges, auth tokens, sessions, and the deposit/credit ledger |
coturn | coturn/coturn:4.6.2-alpine | TURN/STUN relay for WebRTC streaming behind firewalls |
All services join a fixed bridge network named axonos_stack, and per-session desktops the launcher
spawns join the same network so the gate can reach their WebRTC agents.
The base axonos service runs gate-only (no Xorg) so a GPU stays free for
the desktop sessions. The launcher mounts the host Docker socket and starts axgt-session-*
desktop containers on demand, assigning GPUs with --gpus device=N. See
Architecture.
A minimal compose file
The full file in the repo is heavily commented and wires every WebRTC/storage knob. Conceptually it reduces to:
name: axonos
services:
axonos-launcher:
build:
context: .
dockerfile: docker/launcher/Dockerfile
env_file: .env
container_name: axonos_session_launcher
environment:
AXGT_SESSION_LAUNCHER_BIND_HOST: 0.0.0.0
AXGT_SESSION_LAUNCHER_BIND_PORT: ${AXGT_SESSION_LAUNCHER_BIND_PORT:-8090}
AXGT_SESSION_LAUNCHER_TOKEN: ${AXGT_SESSION_LAUNCHER_TOKEN:-change-me-launcher-token}
AXGT_CHALLENGE_DB_URL: postgresql://${POSTGRES_USER:-axonos_gate}:${POSTGRES_PASSWORD:-axonos_gate_secret}@postgres:5432/${POSTGRES_DB:-axonos_gate}
AXGT_HOST_SESSION_CONTAINER_IMAGE: ${AXGT_HOST_SESSION_CONTAINER_IMAGE:-axonos:public-beta}
AXGT_HOST_SESSION_CONTAINER_NETWORK: ${AXGT_HOST_SESSION_CONTAINER_NETWORK:-axonos_stack}
volumes:
- /var/run/docker.sock:/var/run/docker.sock # to spawn session containers
networks: [axonos_stack]
restart: unless-stopped
postgres:
image: postgres:15-alpine
container_name: axonos_postgres
environment:
POSTGRES_USER: ${POSTGRES_USER:-axonos_gate}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-axonos_gate_secret}
POSTGRES_DB: ${POSTGRES_DB:-axonos_gate}
volumes:
- axonos_postgres_data:/var/lib/postgresql/data
networks: [axonos_stack]
restart: unless-stopped
axonos:
image: axonos:public-beta
build:
context: .
dockerfile: Dockerfile
args:
PASSWORD: ${AXONOS_VNC_PASSWORD}
NVIDIA_DRIVER_PKG_VERSION: ${NVIDIA_DRIVER_PKG_VERSION:-}
container_name: axonos
shm_size: "32gb"
env_file: .env
environment:
AXGT_CHALLENGE_DB_URL: postgresql://${POSTGRES_USER:-axonos_gate}:${POSTGRES_PASSWORD:-axonos_gate_secret}@postgres:5432/${POSTGRES_DB:-axonos_gate}
AXGT_SESSION_LAUNCHER_MODE: ${AXGT_SESSION_LAUNCHER_MODE:-http}
AXGT_SESSION_LAUNCHER_URL: ${AXGT_SESSION_LAUNCHER_URL:-http://axonos-launcher:8090}
GATE_HOST: ${GATE_HOST:-0.0.0.0}
GATE_PORT: ${GATE_PORT:-8889}
depends_on:
postgres: { condition: service_healthy }
axonos-launcher: { condition: service_healthy }
command: ["/startup.sh"]
ports:
- "${AXONOS_PUBLISH_NOVNC:-6080}:6080"
- "${AXONOS_PUBLISH_GATE:-8889}:8889"
networks: [axonos_stack]
restart: unless-stopped
networks:
axonos_stack:
name: axonos_stack
driver: bridge
volumes:
axonos_postgres_data: {}
The snippet above is an orientation aid. Always deploy with the maintained
docker-compose.yml from the repository — it includes the TURN service, WebRTC env
passthrough, healthchecks, and persistent-storage settings this summary omits.
Key environment variables
These are read from your .env. The compose file auto-derives AXGT_CHALLENGE_DB_URL for you, so
you usually only set credentials and chain config.
| Variable | Default | Purpose |
|---|---|---|
AXONOS_VNC_PASSWORD | (required) | Build arg PASSWORD — VNC + in-container sudo |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB | axonos_gate / axonos_gate_secret / axonos_gate | Bundled Postgres credentials |
AXONOS_PUBLISH_NOVNC | 6080 | Host port → container noVNC |
AXONOS_PUBLISH_GATE | 8889 | Host port → container gate API |
AXGT_SESSION_LAUNCHER_TOKEN | change-me-launcher-token | Shared secret between gate and launcher |
NVIDIA_DRIVER_PKG_VERSION | (empty) | Pin in-container NVIDIA userspace to the host driver |
For billing/auth (AXGT_RPC_URL, AXGT_CONTRACT_ADDRESS, AXGT_REVENUE_WALLET, …) see
Configuration and Tokenomics.
Lifecycle
docker compose build # build axonos + launcher images
docker compose up -d # start the stack
docker compose ps # service status + health
docker compose logs -f axonos # follow gate logs
docker compose down # stop and remove containers
docker compose down -v # also drop the postgres volume (wipes the ledger!)
docker compose down -v removes axonos_postgres_data — all credit balances,
sessions, and auth tokens are lost. Omit -v for normal restarts.
GPU notes
The base axonos service intentionally reserves no GPUs — the launcher assigns specific devices
to each axgt-session-* desktop with --gpus device=N. If nvidia-smi is available on the host,
the base container auto-detects the GPU pool; otherwise the gate asks the launcher to enumerate GPUs.
Ensure the NVIDIA Container Toolkit is installed on the host (see System Requirements).
Next: understand what the stack is doing under the hood in Architecture.