Skip to main content

Configuration

Miabi is configured entirely through environment variables, loaded from the .env file in the Compose directory (or the process environment). This page covers the variables you are most likely to set; the official image ships with sensible defaults for the rest.

Every service in the shipped Compose files reads that single .env via Docker Compose's env_file directive, so the workflow is: rename .env.example.env, fill in the values, and docker compose up — no per-service edits.

Core

VariableDefaultDescription
MIABI_PORT9000API listen port
MIABI_ENVdevdev or production
MIABI_JWT_SECRETRequired in production. Signs access tokens
MIABI_ENCRYPTION_KEYAES key for secrets at rest (env vars, DB passwords, custom certs). Without it, those values are only base64-encoded
MIABI_WEB_URLPublic URL of your instance (used for links, OAuth callbacks, invitations). Also the CORS allowlist, so it must be a concrete origin
MIABI_CORS_ORIGINS*Comma-separated allowed origins; a * wildcard is rejected in production
MIABI_ADMIN_EMAILadmin@example.comLogin of the platform admin seeded on first boot
MIABI_ADMIN_PASSWORDRequired in production. Password for the seeded platform admin. Miabi refuses to start outside dev while this is empty or left at its built-in default
caution

Generate strong random values for MIABI_JWT_SECRET and MIABI_ENCRYPTION_KEY with openssl rand -hex 32. Keep .env at chmod 600 and out of version control. See Encryption for how secrets are protected at rest.

Enforcement switches

Two similarly named variables that do unrelated things. Both are on by default; turning either off removes a protection:

VariableDefaultDescription
MIABI_PLAN_ENFORCEMENTtrueEnforce per-workspace plan quotas and capability gates. Set false to make every quota check pass and every gate open
MIABI_SECURITY_ENFORCEMENTtrueStop a platform admin from raw-stopping or removing a Miabi-managed container from the admin node view. Set false only as a break-glass escape hatch
MIABI_UPDATE_CHECKtrueDaily check for a newer Miabi release, surfaced as an admin notice. Notify-only — Miabi never upgrades itself. See Upgrades

Database & cache

VariableDefaultDescription
MIABI_DB_HOSTlocalhostPostgreSQL host
MIABI_DB_PORT5432PostgreSQL port
MIABI_DB_USERmiabiPostgreSQL user
MIABI_DB_PASSWORDmiabiPostgreSQL password
MIABI_DB_NAMEmiabiDatabase name
MIABI_DB_SSL_MODEdisablelibpq sslmode (disable, require, verify-full, …)
MIABI_DB_URLFull DSN; overrides every MIABI_DB_* part above
MIABI_REDIS_ADDRlocalhost:6379Redis address (cache, rate limiting, job queue)
MIABI_REDIS_PASSWORDRedis password

Workers, metrics & proxy

VariableDefaultDescription
MIABI_WORKER_CONCURRENCY10Background worker (asynq) concurrency
MIABI_WORKER_MAX_RETRIES5Task retry attempts
MIABI_METRICS_ENABLEDfalsePrometheus /metrics + history scraper. Off by default/metrics is not served until you enable it
MIABI_METRICS_SCRAPE_SECONDS60Metrics sampling interval
MIABI_METRICS_RETENTION_HOURS24Metrics history window
MIABI_PROXY_NETWORKmiabiDocker network shared by the gateway and app containers so the proxy can reach backends (legacy alias: MIABI_GOMA_NETWORK)
MIABI_GOMA_PROVIDER_DIR/etc/goma/providersDirectory where Miabi writes per-route Goma config files that the gateway hot-reloads
MIABI_WEB_DIRDirectory of the built web UI; when set, Miabi serves it as an SPA at /. The official image serves the UI from the embedded binary
DOCKER_HOSTunix:///var/run/docker.sockDocker Engine endpoint

Public app URLs

Miabi can hand every app a ready-to-use public URL under a wildcard base domain (the "one-click URL" feature). Point *.<base> DNS at the gateway and set:

VariableDefaultDescription
MIABI_EXTERNAL_BASE_DOMAINBase domain for one-click app URLs, e.g. apps.example.com (point *.apps.example.com at the gateway)
MIABI_EXTERNAL_BASE_PROVIDERGoma certManager provider used for those app certs (empty = gateway default)

Log store

Deploy, pipeline, job, and backup logs are externalized out of Postgres into a filesystem backend once a run is terminal, keeping only a bounded tail in the database. Mount MIABI_LOG_DIR on a volume so logs survive restarts — and if you run a separate worker service, mount the same volume there so the control plane can read the logs the worker writes.

VariableDefaultDescription
MIABI_LOG_BACKENDfilesystemfilesystem or off (keep only the DB tail)
MIABI_LOG_DIR/var/lib/miabi/logsRoot directory for externalized logs
MIABI_LOG_RETENTION_DAYS30Days to keep externalized logs (0 = forever)
MIABI_LOG_MAX_BYTES33554432Per-log cap (32 MiB); middle-truncated past it
MIABI_LOG_TAIL_BYTES16384Bounded tail (16 KiB) kept in the database
MIABI_LOG_COMPRESSIONgzipgzip or none

See Log storage for the full model.

The background worker

Miabi runs an asynq worker that executes deploys, database provisioning, backups, and other long-running jobs. By default the worker is embedded in the control plane process — no separate container required. For production you can run a dedicated worker process so the API and background processing scale independently:

# API server
miabi server

# Worker (separate process / container)
miabi worker

Multiple worker instances share the same Redis queue, so you can scale them horizontally.

Reverse proxy & TLS

Routing and TLS termination are handled by Goma Gateway, configured through goma/goma.yml. Miabi drives the local gateway purely through the watched file-provider directory (MIABI_GOMA_PROVIDER_DIR) — it writes per-route files there and Goma hot-reloads them, with no API endpoint or token involved.

Gateways on remote nodes work differently: they poll a token-authenticated HTTP provider endpoint on the control plane for their routes.

goma.yml itself supports ${VAR} environment-variable substitution in any field — hosts, redis.password, certManager.acme.email, and so on — so the shipped config reads your domain and ACME email straight from the same .env. Only the braced ${VAR} form is expanded; unset variables are left literal and a bare $ (bcrypt hashes, regex) is untouched.

Prefer Traefik as the edge proxy? Miabi ships a Traefik variant (compose.traefik.yaml) — see Reverse proxy & Traefik for its trade-offs (label-based routing; rolling/canary and the built-in registry require Goma). See TLS Certificates for the certificate model.

Outbound email (SMTP)

Used for invitations, password resets, and welcome mails. Without a host and a from-address those emails are silently skipped — nothing fails, they simply never arrive.

VariableDefaultDescription
MIABI_SMTP_HOSTSMTP server hostname. Unset ⇒ platform email disabled
MIABI_SMTP_PORT587SMTP port
MIABI_SMTP_USERNAMESMTP auth username
MIABI_SMTP_PASSWORDSMTP auth password
MIABI_SMTP_FROMFrom address, e.g. Miabi <no-reply@example.com>
MIABI_SMTP_ENCRYPTIONstarttlsstarttls, tls, or none
MIABI_APP_NAMEMiabiProduct name shown in those emails

Certificates & DNS

VariableDefaultDescription
MIABI_ACME_EMAILContact address registered with Let's Encrypt (Goma + node gateways)
MIABI_ACME_DIRECTORY_URLACME directory for managed DNS-01 certs. Empty = Let's Encrypt production; point at staging while testing to avoid rate limits
MIABI_CERT_RENEW_DAYS30Renew a managed certificate this many days before expiry
MIABI_DNS_RECONCILE_MINUTES30Cadence of the managed-DNS reconcile sweep

Encryption & key rotation

VariableDefaultDescription
MIABI_KEY_AUTO_ROTATEfalseEnable the per-workspace encryption-key rotation cron
MIABI_KEY_ROTATE_MONTHS6Max age of an active key before rotation (re-encrypts the workspace's secrets)
GOMA_CONFIG_ENCRYPTION_KEYInjected into every edge gateway so Goma encrypts sensitive config (middleware rules, TLS material) at rest

Builds & runners

VariableDefaultDescription
MIABI_RUNNER_IMAGEmiabi/runner:latestImage shown in the runner enrollment command. Versions independently of the panel
MIABI_BUILD_TIMEOUT_MINUTES30Platform-wide cap on a single image build
MIABI_RUNNER_WAIT_TIMEOUT_MINUTES30How long a build waits for a free runner before failing. There is no local-build fallback
MIABI_JOB_API_TOKEN_ENABLEDtrueInject a short-lived MIABI_JOB_TOKEN into pipeline steps

Built-in registry

Every one of these is a one-way override: a non-empty value pins that setting and the UI can no longer change it. MIABI_REGISTRY_ENABLED=false is not an off switch — it is simply ignored. Leave them all empty to manage the registry from the UI. See Registry.

VariableDefaultDescription
MIABI_REGISTRY_ENABLEDfalseForce the built-in OCI registry on
MIABI_REGISTRY_HOSTRegistry hostname. Empty ⇒ registry.<MIABI_EXTERNAL_BASE_DOMAIN>; with neither, image distribution fails
MIABI_REGISTRY_STORAGEfilesystem or s3 (S3 is an Enterprise feature)
MIABI_REGISTRY_IMAGEOverride the registry image (default registry:3)
MIABI_REGISTRY_AUTH_URLhttp://miabi:9000Where the gateway reaches Miabi's registry auth endpoint
MIABI_REGISTRY_PLATFORM_TOKENPin the platform token (otherwise derived from the master encryption key)
MIABI_REGISTRY_S3_ENDPOINTS3 endpoint URL (set it for MinIO; leave empty for Amazon S3)
MIABI_REGISTRY_S3_BUCKETS3 bucket
MIABI_REGISTRY_S3_REGIONS3 region
MIABI_REGISTRY_S3_ACCESS_KEYS3 access key
MIABI_REGISTRY_S3_SECRET_KEYS3 secret key (encrypted at rest)
MIABI_REGISTRY_S3_FORCE_PATH_STYLEfalsePath-style addressing (MinIO and most S3-compatible stores)

Nodes, networks & port forwarding

VariableDefaultDescription
MIABI_NODE_GATEWAY_IMAGEjkaninda/goma-gateway:latestGoma image deployed on edge-gateway nodes. The shipped compose drives this from GOMA_IMAGE so it always matches the local gateway
MIABI_CONTROL_URLfalls back to MIABI_API_URLPublic URL remote nodes reach the control plane at
MIABI_NETWORK_POOL_CIDR10.64.0.0/12Address pool workspace networks are carved from
MIABI_NETWORK_SUBNET_PREFIX24Prefix length per workspace network (a /12 pool ⇒ 4096 networks)
MIABI_HOST_PORT_MIN1024Lowest host port Miabi may allocate
MIABI_HOST_PORT_MAX65535Highest host port Miabi may allocate
MIABI_FORWARD_TTL_MINUTES30How long a temporary database port-forward lives
MIABI_FORWARD_BIND_ADDR127.0.0.1Address the forward relay binds to
MIABI_FORWARD_ADVERTISE_HOSTHost shown to the user in the forward's connection string
MIABI_FORWARD_RELAY_IMAGEalpine/socat:latestImage used for the forward relay container
MIABI_HOST_PROC/host/procprocfs path for real host CPU/memory. The compose binds /proc:/host/proc:ro

Container security profile

VariableDefaultDescription
MIABI_FORCE_NON_ROOT_USERfalseForce every app & job container to a non-root UID regardless of plan
MIABI_RESTRICTED_UID100000The UID used by the restricted profile
MIABI_SECURITY_INIT_IMAGEbusybox:latestInit image used to prepare restricted containers

Licensing

VariableDefaultDescription
MIABI_LICENSE_FILEPath to a signed license token auto-installed on boot (air-gapped / IaC friendly). A newer DB-installed license still wins
MIABI_LICENSE_PUBLIC_KEYBase64 Ed25519 key used to verify a license offline. Normally baked into the binary; this override is for dev/test

Advanced

VariableDefaultDescription
MIABI_DEV_MODEfalseRelax production guards. Never enable on a public instance
MIABI_OPENAPI_DOCStrueServe the interactive API reference at /docs
MIABI_MARKETPLACE_URLthe marketplace repo's latest release assetWhere templates are synced from. Set to an explicit empty value to disable syncing (offline kill switch)
MIABI_DELETION_GRACE_DAYS7Days an admin-scheduled account deletion waits before the data is purged
MIABI_RESTORE_MAX_MB1024Max size of an uploaded database dump for restore
MIABI_STORAGE_USAGE_ENABLEDtruePeriodically measure each volume's real on-disk usage (docker system df) and cache it, so the UI shows declared-vs-used. Off ⇒ no filesystem walks; the UI shows declared sizes only
MIABI_STORAGE_USAGE_MINUTES30Cadence of that measurement sweep. Raise it on nodes with many/large volumes where the df walk is heavy
MIABI_WEBHOOK_ALLOW_PRIVATE_TARGETSfalseAllow outbound webhooks to RFC1918/ULA addresses. Loopback and link-local (incl. cloud metadata) are always blocked
MIABI_ALLOW_DOWNGRADEfalseBoot even when the binary is older than the version recorded in the database
MIABI_API_URLPublic base URL of the API, when it differs from MIABI_WEB_URL

Platform roles

Per-workspace roles are Owner > Admin > Developer > Viewer. The platform admin is seeded on first boot from MIABI_ADMIN_EMAIL / MIABI_ADMIN_PASSWORD; that account manages nodes and platform-wide settings. See Roles & Permissions and Platform Admin.

Next steps