Skip to content
archmax.ai

Docker Reference

The ghcr.io/archmax-ai/semantics Docker image bundles the application components needed to run archmax:

Component Description
API server Hono HTTP server on port 3000 (internal)
BullMQ worker Background job processor for AI agent tasks
Frontend SPA React admin UI served as static files
nginx Reverse proxy on port 8080; routes /api/ and /mcp/ to the API, serves SPA for everything else
MongoDB Embedded mongod; starts automatically when MONGODB_URI is not set
Redis Embedded redis-server; starts automatically when REDIS_URL is not set

Base image: node:25-slim (Debian Bookworm).

Port Protocol Description
8080 HTTP nginx reverse proxy (the only port you need to expose)

Internal services (API on 3000, MongoDB on 27017, Redis on 6379) bind to 127.0.0.1 and are not accessible from outside the container.

Variable Description
BETTER_AUTH_SECRET Session encryption secret. Min 32 characters. Generate with openssl rand -base64 32. Save this value and reuse it across container restarts and upgrades. Changing or losing it invalidates all existing sessions and authentication data.
UI_PASSWORD Admin password. The current value is reapplied to the admin account on every container start. Update it and restart the container to rotate the password.
Variable Default Docker Behavior
MONGODB_URI (embedded) Optional. When omitted, the entrypoint starts an embedded mongod at mongodb://127.0.0.1:27017/archmax with persistent data at /data/mongodb. Set this to use an external MongoDB instance.
REDIS_URL (embedded) Optional. When omitted, the entrypoint starts an embedded redis-server at redis://127.0.0.1:6379 with ephemeral data at /tmp/redis. Set this to use an external Redis instance.
Variable Default Description
APP_BASE_URL - Public URL of this instance (e.g. https://semantics.example.com). Set this when running behind a reverse proxy or on a cloud host. Automatically configures CORS and auth origins.
PORT 3000 Internal API server port. Normally not changed; nginx proxies port 8080 to this.
CORS_ORIGINS (derived) Comma-separated allowed origins. Defaults to APP_BASE_URL when set. Override only if you need additional origins.
AUTH_BASE_URL (derived) Auth callback URL. Defaults to APP_BASE_URL when set, otherwise http://localhost:PORT.
Variable Default Description
UI_USERNAME admin Admin username (used to seed on first run).
UI_PASSWORD - Required. Admin password. Reapplied to the admin account on every container start; any password changed via the admin UI is overwritten on restart unless UI_PASSWORD is updated to match.
Variable Default Description
SEMANTICS_DATA_DIR /data Root data directory for all persistent application data. Normally not changed in Docker.
ARCHMAX_DATA_DIR - Deprecated. Pre-rename alias for SEMANTICS_DATA_DIR. Still honoured (with a startup warning) so existing deployments keep working; SEMANTICS_DATA_DIR wins when both are set.
Variable Default Description
QUERY_TIMEOUT_MS 30000 Per-query DuckDB timeout in milliseconds. Applies to MCP, agent, data browser, and connection-test queries. On timeout the query is cancelled via interrupt().
MAX_CONCURRENT_QUERIES 10 Max concurrent DuckDB queries per project. Additional requests wait up to QUERY_TIMEOUT_MS for a slot.

DuckDB extensions are loaded only from the core and community registries. Unsigned extensions are never permitted, and there is no setting that enables them.

Variable Default Description
AGENT_API_BASE_URL https://openrouter.ai/api/v1 OpenAI-compatible API endpoint. Change this when using a provider other than OpenRouter.
AGENT_API_KEY - Required for agent features. API key for your chosen provider.
AGENT_MODEL anthropic/claude-sonnet-4 Model identifier (must match your provider’s naming convention).
AGENT_TITLE_MODEL anthropic/claude-haiku-4-5-20250929 Cheap/fast model for conversation title generation.

Supported providers: OpenRouter (default), OpenAI, Azure OpenAI, Ollama, or any OpenAI-compatible endpoint.

Variable Default Description
WORKER_CONCURRENCY 5 Number of concurrent agent jobs the worker processes.
Variable Default Description
MCP_RATE_LIMIT_MAX 120 Max MCP requests per IP per 60-second window.
Variable Default Description
TEST_AGENT_MAX_ITERATIONS 100 Max tool call iterations for playground and batch test agents.
Variable Default Description
ENCRYPTION_KEY - Encrypts database connection passwords and API keys at rest (AES-256-GCM). Generate with openssl rand -base64 32.
Variable Default Description
GITHUB_CLIENT_ID - GitHub OAuth app client ID.
GITHUB_CLIENT_SECRET - GitHub OAuth app client secret.
Container Path Contents Persistent? Notes
/data/projects/ Semantic model YAML files Yes Core application data
/data/mongodb/ Embedded MongoDB data files Yes Only used when MONGODB_URI is not set
/data/.duckdb/ DuckDB extension cache Yes Created when DuckDB loads extensions
/tmp/redis/ Embedded Redis data No Ephemeral by design; queue data is transient
Terminal window
-v ~/.archmax:/data

This bind mount maps the container’s data directory to ~/.archmax on the host, including project files (semantic model YAMLs), the DuckDB extension cache (.duckdb/), and embedded MongoDB data. When using Docker Compose with an external MongoDB service, the mongodb/ directory is unused and MongoDB data is managed by the Compose mongo service volume.

The container entrypoint (/entrypoint.sh) follows this startup sequence:

1. Set SEMANTICS_DATA_DIR (default: /data)
2. If MONGODB_URI is not set:
├── Create $SEMANTICS_DATA_DIR/mongodb (if missing)
├── Start mongod (fork, bind 127.0.0.1, data at $SEMANTICS_DATA_DIR/mongodb)
├── Wait for readiness (ping loop, max ~10s)
└── Export MONGODB_URI=mongodb://127.0.0.1:27017/archmax
3. If REDIS_URL is not set:
├── Create /tmp/redis (if missing)
├── Start redis-server (daemonize, bind 127.0.0.1, persistence disabled, log at /var/log/redis.log)
└── Export REDIS_URL=redis://127.0.0.1:6379
4. Start BullMQ worker (background)
5. Start API server on port 3000 (background)
6. Start nginx on port 8080 (foreground, PID 1)
MONGODB_URI set? REDIS_URL set? Embedded MongoDB Embedded Redis
No No Started Started
Yes No Skipped Started
No Yes Started Skipped
Yes Yes Skipped Skipped

The API exposes a health endpoint you can use for Docker health checks or load balancer probes:

Terminal window
curl -f http://localhost:8080/api/health

Docker HEALTHCHECK example:

HEALTHCHECK --interval=30s --timeout=5s --start-period=30s \
CMD curl -f http://localhost:8080/api/health || exit 1

Or in Docker Compose:

services:
archmax:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"]
interval: 30s
timeout: 5s
start_period: 30s

After the Docker image is built in CI, Playwright end-to-end tests run against the image (started via docker-compose.ci.yml with local MongoDB and Redis) to validate login, navigation, and health before merge.

Deployment Min RAM Min Disk Recommended CPU
Standalone (embedded MongoDB + Redis) 512 MB 2 GB 1 vCPU
Standalone (external MongoDB) 256 MB 1 GB 1 vCPU
Docker Compose (small team) 1 GB total 5 GB 1 vCPU
Docker Compose (production) 2 GB total 10 GB 2 vCPU

The embedded MongoDB adds ~200 MB RAM overhead. When using external MongoDB via MONGODB_URI, the container has a smaller memory footprint. The AI agent runs remotely via API calls and does not consume local GPU/CPU.

Terminal window
git clone https://github.com/archmax-ai/semantics.git
cd semantics
cp .env.example .env
# Edit .env with your values
docker compose up -d

See the docker-compose.yml in the repository root for the full configuration.

Terminal window
docker run -d \
--name semantics \
-p 8080:8080 \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
-e UI_USERNAME=admin \
-e UI_PASSWORD=changeme \
-e AGENT_API_KEY=your-api-key \
-v ~/.archmax:/data \
ghcr.io/archmax-ai/semantics:latest
Terminal window
docker run -d \
--name semantics \
-p 8080:8080 \
-e MONGODB_URI=mongodb://mongo.example.com:27017/archmax \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
-e UI_USERNAME=admin \
-e UI_PASSWORD=changeme \
-e AGENT_API_KEY=your-api-key \
-v ~/.archmax:/data \
ghcr.io/archmax-ai/semantics:latest

When archmax semantics is accessible through a custom domain or reverse proxy, set APP_BASE_URL to the public URL:

Terminal window
docker run -d \
--name semantics \
-p 8080:8080 \
-e APP_BASE_URL=https://semantics.example.com \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
-e UI_USERNAME=admin \
-e UI_PASSWORD=changeme \
-e AGENT_API_KEY=your-api-key \
-v ~/.archmax:/data \
ghcr.io/archmax-ai/semantics:latest
Terminal window
docker run -d \
--name semantics \
-p 8080:8080 \
-e BETTER_AUTH_SECRET=$(openssl rand -base64 32) \
-e UI_USERNAME=admin \
-e UI_PASSWORD=changeme \
-e AGENT_API_KEY=sk-your-openai-key \
-e AGENT_API_BASE_URL=https://api.openai.com/v1 \
-e AGENT_MODEL=gpt-4o \
-v ~/.archmax:/data \
ghcr.io/archmax-ai/semantics:latest

Releases before the rename shipped as ghcr.io/archmaxai/archmax. Upgrading to ghcr.io/archmax-ai/semantics is a tag change: nothing that stores state was renamed, so no data migration is needed.

Identifier Status
Image ghcr.io/archmaxai/archmax → ghcr.io/archmax-ai/semantics. Update your docker run command or docker-compose.yml.
ARCHMAX_DATA_DIR Deprecated alias for SEMANTICS_DATA_DIR. Still works; the container logs a warning until you rename it.
MongoDB database name Unchanged (archmax). Existing projects, connections and MCP tokens are picked up as-is.
Compose service archmax and volume archmax-data Unchanged. docker compose pull && docker compose up -d recreates the container in place and reattaches the existing volume.
Container user archmax Unchanged. File ownership on /data needs no repair.
Auth cookies Unchanged prefix. Existing sessions stay signed in.

For a standalone container that is still named archmax, stop and remove it by its old name before starting the new image:

Terminal window
docker pull ghcr.io/archmax-ai/semantics:latest
docker stop archmax && docker rm archmax
docker run -d --name semantics -p 8080:8080 \
-v ~/.archmax:/data \
... \
ghcr.io/archmax-ai/semantics:latest

Keep the same -v mount, BETTER_AUTH_SECRET and ENCRYPTION_KEY; everything under /data is read unchanged.

Check the logs for the startup error:

Terminal window
docker logs semantics

Common causes:

  • Missing required environment variable (BETTER_AUTH_SECRET or UI_PASSWORD)
  • BETTER_AUTH_SECRET is shorter than 32 characters
  • Embedded MongoDB failed to start (check the logs for mongod startup errors)

If using embedded MongoDB, check the mongod log:

Terminal window
docker exec -it semantics cat /var/log/mongod.log

If using an external MongoDB, verify the connection string from inside the container:

Terminal window
docker exec -it semantics node -e "
const { MongoClient } = require('mongodb');
MongoClient.connect(process.env.MONGODB_URI).then(() => console.log('OK')).catch(e => console.error(e.message));
"

Common causes:

  • Network/firewall blocking the connection
  • DNS resolution failure (use IP address or ensure Docker DNS resolves the hostname)
  • Missing ?authSource=admin for authenticated MongoDB instances
  • When using Docker Compose, ensure the mongo service is healthy before archmax semantics starts (depends_on)
  • Embedded MongoDB fails on corrupted data; delete the /data/mongodb directory and restart

Map to a different host port:

Terminal window
docker run -d -p 9090:8080 ... ghcr.io/archmax-ai/semantics:latest

/var/log/redis.log inside the container may contain WARNING Memory overcommit must be enabled!. It refers to a host kernel setting (vm.overcommit_memory) that Redis wants for background snapshot saves. The embedded Redis runs with persistence disabled (--save "" --appendonly no) because queue data is ephemeral by design, so nothing forks for a background save and the warning has no effect on this image.

The setting is not namespaced, so it cannot be changed from inside the container (docker run --sysctl rejects it). If you want to silence it at the source on a Linux host:

Terminal window
sudo sysctl vm.overcommit_memory=1 # until reboot
echo 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/99-redis.conf # persistent

Docker Desktop (macOS/Windows) runs a managed Linux VM where this is not user-configurable; the warning is safe to ignore there.

If running as a non-root user or on SELinux-enabled hosts, add the :Z flag:

Terminal window
-v ~/.archmax:/data:Z

Locked out of the admin UI / forgot the admin password

Section titled “Locked out of the admin UI / forgot the admin password”

UI_PASSWORD is reapplied to the admin account on every container start. To recover access:

  1. Stop the container.
  2. Update UI_PASSWORD to the new value you want.
  3. Start the container again — the admin credential is replaced with the current UI_PASSWORD and you can log in with it immediately.

Note that any password you change through the admin UI is overwritten on the next restart unless UI_PASSWORD is updated to match. Keep the env var as the source of truth, or accept that UI-side rotations are not durable across restarts.