Self-Hosting & Development/Self-Hosting/Docker Compose

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.

Two ways to run AxonOS

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

bash
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

ServiceImage / buildRole
axonosDockerfileaxonos:public-betaGate server + billing + session orchestration entrypoint
axonos-launcherdocker/launcher/DockerfileHTTP launcher that spawns per-session desktop containers
postgrespostgres:15-alpineChallenges, auth tokens, sessions, and the deposit/credit ledger
coturncoturn/coturn:4.6.2-alpineTURN/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.

Why a separate launcher?

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:

yaml
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: {}
Use the repo file, not this one

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.

VariableDefaultPurpose
AXONOS_VNC_PASSWORD(required)Build arg PASSWORD — VNC + in-container sudo
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DBaxonos_gate / axonos_gate_secret / axonos_gateBundled Postgres credentials
AXONOS_PUBLISH_NOVNC6080Host port → container noVNC
AXONOS_PUBLISH_GATE8889Host port → container gate API
AXGT_SESSION_LAUNCHER_TOKENchange-me-launcher-tokenShared 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

bash
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!)
down -v destroys 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.