Docker Deployment#
Tinyauth ships as a multi-stage Docker image that builds a static Go binary (CGO disabled) and packages it into a minimal Alpine runtime. The image exposes port 3000, creates a dedicated tinyauth non-root user, and pre-creates the /data directory subtree used for all persistent state .
The official image is ghcr.io/tinyauthapp/tinyauth:v5 .
Runtime Detection and Path Defaults#
The Dockerfile sets RUNTIME_ENV=docker as a baked-in environment variable . At startup, DetectRuntimeEnv() reads this variable to switch path defaults.
When RUNTIME_ENV=docker, NewDefaultConfiguration() overrides the default (relative) paths with absolute /data-rooted paths:
| Config field | Non-Docker default | Docker default |
|---|---|---|
Database.Path | ./tinyauth.db | /data/tinyauth.db |
Resources.Path | ./resources | /data/resources |
OIDC.PrivateKeyPath | ./tinyauth_oidc_key | /data/oidc/key.pem |
OIDC.PublicKeyPath | ./tinyauth_oidc_key.pub | /data/oidc/key.pub |
The Dockerfile also pre-creates these subdirectories and sets ownership to the tinyauth user :
/data/resources/data/oidc/data/tailscale
Volume Mount Strategy#
A single named volume or host-path bind on /data persists all runtime state. The Dockerfile declares /data as a VOLUME .
The example docker-compose.yml uses a host-path bind:
volumes:
- ./data:/data
This is the recommended pattern for local deployments. The dev compose file follows the same convention .
Configuration in Docker#
Configuration is applied via a three-source loader chain β file β flags β env vars β where environment variables win . In Docker, the practical approach is:
Option A β Environment variables only (most common)
Set TINYAUTH_ prefixed variables directly in the compose environment block. Example from the production compose template :
environment:
- TINYAUTH_APPURL=https://tinyauth.example.com
- TINYAUTH_AUTH_USERS=user:$$2a$$10$...
Note the $$ escaping for $ in bcrypt hashes within Docker Compose files.
Option B β Config file via TINYAUTH_CONFIGFILE
Mount a YAML/TOML/JSON config file and point to it with the env var. The FileLoader checks --traefik.configfile first, then falls back to TINYAUTH_CONFIGFILE. If neither is set, file loading is skipped.
environment:
- TINYAUTH_CONFIGFILE=/data/config.yaml
volumes:
- ./data:/data # config.yaml lives at ./data/config.yaml
Traefik ForwardAuth Integration#
The example compose file shows the standard ForwardAuth middleware wiring :
labels:
traefik.enable: true
traefik.http.routers.tinyauth.rule: Host(`tinyauth.example.com`)
traefik.http.middlewares.tinyauth.forwardauth.address: http://tinyauth:3000/api/auth/traefik
Protected services reference the tinyauth middleware via traefik.http.routers.<service>.middlewares: tinyauth .
For Docker label-based ACLs, the Tinyauth container also needs the Docker socket mounted at /var/run/docker.sock so it can read per-app labels at runtime .
Key Files#
| File | Purpose |
|---|---|
Dockerfile | Image definition, data directory setup, RUNTIME_ENV=docker |
docker-compose.example.yml | Minimal production example with Traefik |
docker-compose.dev.yml | Split frontend/backend dev setup |
internal/model/config.go | DetectRuntimeEnv(), NewDefaultConfiguration() with Docker path overrides |
internal/utils/loaders/loader_file.go | TINYAUTH_CONFIGFILE env var / --traefik.configfile flag resolution |