Docker Reference
Image Contents
Section titled “Image Contents”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).
Exposed Ports
Section titled “Exposed Ports”| 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.
Environment Variables
Section titled “Environment Variables”Required
Section titled “Required”| 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. |
Optional Services
Section titled “Optional Services”| 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. |
Server
Section titled “Server”| 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. |
Admin Credentials
Section titled “Admin Credentials”| 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. |
Data Federation (DuckDB)
Section titled “Data Federation (DuckDB)”| 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.
AI Agent
Section titled “AI Agent”| 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.
Worker
Section titled “Worker”| Variable | Default | Description |
|---|---|---|
WORKER_CONCURRENCY |
5 |
Number of concurrent agent jobs the worker processes. |
MCP Server
Section titled “MCP Server”| Variable | Default | Description |
|---|---|---|
MCP_RATE_LIMIT_MAX |
120 |
Max MCP requests per IP per 60-second window. |
Testing
Section titled “Testing”| Variable | Default | Description |
|---|---|---|
TEST_AGENT_MAX_ITERATIONS |
100 |
Max tool call iterations for playground and batch test agents. |
Security
Section titled “Security”| Variable | Default | Description |
|---|---|---|
ENCRYPTION_KEY |
- | Encrypts database connection passwords and API keys at rest (AES-256-GCM). Generate with openssl rand -base64 32. |
GitHub Integration (Optional)
Section titled “GitHub Integration (Optional)”| Variable | Default | Description |
|---|---|---|
GITHUB_CLIENT_ID |
- | GitHub OAuth app client ID. |
GITHUB_CLIENT_SECRET |
- | GitHub OAuth app client secret. |
Volumes
Section titled “Volumes”| 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 |
Recommended Volume Mount
Section titled “Recommended Volume Mount”-v ~/.archmax:/dataThis 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.
Entrypoint Behavior
Section titled “Entrypoint Behavior”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/archmax3. 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:63794. Start BullMQ worker (background)5. Start API server on port 3000 (background)6. Start nginx on port 8080 (foreground, PID 1)Decision Matrix
Section titled “Decision Matrix”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 |
Health Checks
Section titled “Health Checks”The API exposes a health endpoint you can use for Docker health checks or load balancer probes:
curl -f http://localhost:8080/api/healthDocker HEALTHCHECK example:
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s \ CMD curl -f http://localhost:8080/api/health || exit 1Or in Docker Compose:
services: archmax: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/api/health"] interval: 30s timeout: 5s start_period: 30sCI Verification
Section titled “CI Verification”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.
Resource Requirements
Section titled “Resource Requirements”| 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.
Examples
Section titled “Examples”Docker Compose (Recommended)
Section titled “Docker Compose (Recommended)”git clone https://github.com/archmax-ai/semantics.gitcd semanticscp .env.example .env# Edit .env with your valuesdocker compose up -dSee the docker-compose.yml in the repository root for the full configuration.
Standalone (Embedded MongoDB + Redis)
Section titled “Standalone (Embedded MongoDB + Redis)”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:latestStandalone with External MongoDB
Section titled “Standalone with External MongoDB”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:latestBehind a Reverse Proxy
Section titled “Behind a Reverse Proxy”When archmax semantics is accessible through a custom domain or reverse proxy, set APP_BASE_URL to the public URL:
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:latestWith Custom AI Provider
Section titled “With Custom AI Provider”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:latestUpgrading from archmax
Section titled “Upgrading from archmax”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:
docker pull ghcr.io/archmax-ai/semantics:latestdocker stop archmax && docker rm archmaxdocker run -d --name semantics -p 8080:8080 \ -v ~/.archmax:/data \ ... \ ghcr.io/archmax-ai/semantics:latestKeep the same -v mount, BETTER_AUTH_SECRET and ENCRYPTION_KEY; everything under /data is read unchanged.
Troubleshooting
Section titled “Troubleshooting”Container exits immediately
Section titled “Container exits immediately”Check the logs for the startup error:
docker logs semanticsCommon causes:
- Missing required environment variable (
BETTER_AUTH_SECRETorUI_PASSWORD) BETTER_AUTH_SECRETis shorter than 32 characters- Embedded MongoDB failed to start (check the logs for
mongodstartup errors)
Cannot connect to MongoDB
Section titled “Cannot connect to MongoDB”If using embedded MongoDB, check the mongod log:
docker exec -it semantics cat /var/log/mongod.logIf using an external MongoDB, verify the connection string from inside the container:
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=adminfor authenticated MongoDB instances - When using Docker Compose, ensure the
mongoservice is healthy before archmax semantics starts (depends_on) - Embedded MongoDB fails on corrupted data; delete the
/data/mongodbdirectory and restart
Port 8080 already in use
Section titled “Port 8080 already in use”Map to a different host port:
docker run -d -p 9090:8080 ... ghcr.io/archmax-ai/semantics:latestRedis warns about memory overcommit
Section titled “Redis warns about memory overcommit”/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:
sudo sysctl vm.overcommit_memory=1 # until rebootecho 'vm.overcommit_memory = 1' | sudo tee /etc/sysctl.d/99-redis.conf # persistentDocker Desktop (macOS/Windows) runs a managed Linux VM where this is not user-configurable; the warning is safe to ignore there.
Volume permission errors
Section titled “Volume permission errors”If running as a non-root user or on SELinux-enabled hosts, add the :Z flag:
-v ~/.archmax:/data:ZLocked 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:
- Stop the container.
- Update
UI_PASSWORDto the new value you want. - Start the container again — the admin credential is replaced with the current
UI_PASSWORDand 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.