// daemon
Environment variables
All configuration is environment-based — no config file for the daemon itself.
| Variable | Default | Description |
|---|---|---|
OXID_DATA_DIR | /data | State directory: audit.sqlite, git-cache/, secret.key. |
OXID_ADDR | 0.0.0.0:8080 | Bind address. |
OXID_GC_INTERVAL_SECS | 30 | Scheduler tick for GC / deploy-queue retries. |
OXID_MASTER_KEY | generated | 64-hex master key for secret encryption; generated + persisted to secret.key (0600) when unset. |
OXID_API_TOKEN | unset | Bearer token required on /api/v1/*. Unset = open API (fine on localhost) — or set OXID_AUTO_TOKEN=1 to auto-generate and persist it (printed once to logs). |
OXID_ALLOW_OPEN_API | 0 | 1 to let a non-loopback daemon start without OXID_API_TOKEN (explicit opt-in to an unauthenticated API). |
OXID_AUTO_TOKEN | 0 | 1 for zero-config starts: any of OXID_API_TOKEN / OXID_WEBHOOK_SECRET not set is generated (64 hex), persisted under {data}/ (0600) and printed once — the shipped docker-compose.yml uses this so docker compose up -d works with no .env. |
OXID_WEBHOOK_SECRET | unset | HMAC-SHA256 secret for GitHub/GitLab/Gitea/Gogs webhooks; webhooks rejected while unset (or auto-generated with OXID_AUTO_TOKEN=1). |
OXID_DOCKER_NETWORK | unset | Shared network with Traefik: containers get subdomains instead of host ports, and scale-to-zero wake-on-request activates. The wizard's infra step bootstraps this with one click (POST /api/v1/infra/bootstrap). |
OXID_DAEMON_URL | http://oxid-daemon:8080 | The daemon's own address inside OXID_DOCKER_NETWORK (Traefik forwardAuth labels). |
OXID_POSTGRES_URL | unset | Admin connection string for a shared Postgres — per-branch logical databases for projects declaring the dependency. |
OXID_REDIS_URL | unset | Base URL of a shared Redis; per-branch logical databases. |
OXID_REDIS_POOL_SIZE | 16 | Leasable Redis logical databases. |
OXID_DEFAULT_MEMORY_LIMIT_MB | 512 | Fallback container memory limit; 0 disables. |
OXID_DEFAULT_CPU_LIMIT_MILLICORES | 1000 | Fallback container CPU limit; 0 disables. |
OXID_RESERVED_MEMORY_MB | 1024 | Host memory reserved before admission control starts queueing deploys; 0 disables queueing. |
OXID_TLS_CERT / OXID_TLS_KEY | unset | PEM paths — when both are set the daemon serves HTTPS directly. |
OXID_ALLOW_RESTORE | 0 | 1 to accept POST /api/v1/backup/restore uploads at all (staged, applied on next restart). |
OXID_BACKUP_INTERVAL_SECS | unset | When set (e.g. 300), periodic VACUUM INTO snapshots to {data}/backups/. |
OXID_BACKUP_KEEP | 7 | Newest snapshots to keep when backups are enabled. |
OXID_RATE_LIMIT_PER_SECOND / _BURST | unset | When both are set, token-bucket rate limit on protected routes (per client IP). |
RUST_LOG | info | Tracing filter, e.g. oxid_daemon=debug,info. |
OXID_LOG_FORMAT | pretty | pretty or json (one object per line — use in production). |
On startup the daemon reconciles its database against Docker's actual state before
serving any request, and drains in-flight requests for up to 10s on
SIGTERM/Ctrl+C instead of dying mid-request.
Data layout
Everything lives under OXID_DATA_DIR — back this up (or use oxid backup) and you have the whole system.
/data ├── audit.sqlite # all state + audit trail (WAL mode) ├── secret.key # AES-GCM master key, mode 0600 ├── api-token # auto-generated when OXID_AUTO_TOKEN=1 (0600) ├── webhook-secret # auto-generated when OXID_AUTO_TOKEN=1 (0600) ├── git-cache/ # cached clones, one dir per project └── backups/ # VACUUM INTO snapshots when OXID_BACKUP_INTERVAL_SECS is set
A restore never touches the live database in place — an upload is staged and applied on the next daemon startup.