Guides: deploy & operate

How to deploy with Docker Compose

This guide shows you how to run DeltaGlider Proxy with Docker Compose using a secret-free, commit-safe config. The files are also in the repo under examples/docker-compose/.

The pattern: the proxy expands ${env:NAME} and ${env:NAME:-default} references inside its config file, in-process, at load time — an in-program replacement for an external envsubst step. You ship a secret-free deltaglider_proxy.yaml with placeholders, supply real values as environment variables, and the proxy fills them at startup. An unset placeholder with no default fails the proxy loudly instead of starting with a blank secret.

The env: prefix is required. It keeps load-time config placeholders distinct from the request-time IAM permission templates (${iam:username}, ${iam:access_key_id}). A bare ${...} is left untouched.

You need three files:

  • deltaglider_proxy.yaml — the config; secret values are ${env:...} placeholders. Commit it.
  • secrets.env — your real secret values (KEY=value). Never commit it.
  • docker-compose.yml — runs the proxy with the config mounted and the secrets supplied via env_file.

1. Write the config

# deltaglider_proxy.yaml — secret-free, safe to commit
storage:
  backends:
    - name: hetzner-fsn1
      type: s3
      endpoint: ${env:S3_ENDPOINT}
      region: ${env:S3_REGION:-us-east-1}
      force_path_style: ${env:S3_PATH_STYLE:-false}   # true for MinIO / non-AWS
      access_key_id: ${env:S3_ACCESS_KEY_ID}
      secret_access_key: ${env:S3_SECRET_ACCESS_KEY}
  default_backend: hetzner-fsn1

access:
  # A single bootstrap SigV4 pair to get started (add per-user IAM later
  # from the admin GUI, or manage users as code — see below).
  access_key_id: ${env:PROXY_ACCESS_KEY_ID}
  secret_access_key: ${env:PROXY_SECRET_ACCESS_KEY}

advanced:
  listen_addr: 0.0.0.0:9000
  max_object_size: 536870912   # 512 MiB

2. Write the secrets file

# secrets.env — your real values; gitignored, never committed.
# This is a docker-compose env_file: KEY=value, taken literally (no shell quoting).

DGP_BOOTSTRAP_PASSWORD_HASH=   # bcrypt hash; see "Set the admin password" below

S3_ENDPOINT=https://s3.eu-central-1.amazonaws.com
S3_REGION=eu-central-1
S3_PATH_STYLE=false
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=

PROXY_ACCESS_KEY_ID=
PROXY_SECRET_ACCESS_KEY=

3. Write the compose file

services:
  # One-time: make the config volume writable by the proxy's non-root user (999)
  # so it can create its encrypted config DB. (A fresh named volume is root-owned.)
  init-perms:
    image: beshultd/deltaglider_proxy:${DGP_IMAGE_TAG:-latest}
    user: "0:0"
    entrypoint: ["/bin/sh", "-c", "chown 999:999 /etc/deltaglider_proxy && chmod 750 /etc/deltaglider_proxy"]
    volumes:
      - dgp-config:/etc/deltaglider_proxy
    restart: "no"

  deltaglider:
    image: beshultd/deltaglider_proxy:${DGP_IMAGE_TAG:-latest}
    depends_on:
      init-perms:
        condition: service_completed_successfully
    env_file:
      - secrets.env
    environment:
      DGP_CONFIG: /etc/deltaglider_proxy/deltaglider_proxy.yaml
    ports:
      - "9000:9000"
    volumes:
      - ./deltaglider_proxy.yaml:/etc/deltaglider_proxy/deltaglider_proxy.yaml:ro
      - dgp-config:/etc/deltaglider_proxy    # encrypted config DB — back this up
      - dgp-data:/data                       # delta/reconstruction scratch
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/_/health"]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s
    restart: unless-stopped

volumes:
  dgp-config:
  dgp-data:

4. Set the admin password

DGP_BOOTSTRAP_PASSWORD_HASH is a bcrypt hash, not plaintext. Generate it:

# inside the image:
docker run --rm beshultd/deltaglider_proxy:latest --set-bootstrap-password
# or with htpasswd:
htpasswd -nbBC 12 "" 'your-password' | tr -d ':\n' | sed 's/^\$2y/\$2b/'

5. Run it

cp secrets.env.example secrets.env   # then fill secrets.env
docker compose up -d
docker compose logs -f deltaglider

If you have the binary locally, validate the config before shipping — it catches a missing ${env:...} early:

deltaglider_proxy config lint deltaglider_proxy.yaml

Filesystem backend instead of S3

For a self-contained deployment with no external object store, replace the storage.backends block with a filesystem backend pointed at the data volume:

storage:
  filesystem: /data

Managing users as code

To manage IAM users and groups from the YAML instead of the admin GUI, set access.iam_mode: declarative — the YAML becomes the source of truth and is reconciled into the encrypted DB on every apply. See How to manage IAM as code.

Persistence and backups

The dgp-config volume holds the encrypted config DB (deltaglider_config.db) — your IAM users, groups, and OAuth providers. Back it up (see How to back up and restore). The dgp-data volume is scratch (caches + delta-reconstruction buffers); object data itself lives in your S3 backend, not in these volumes.

Verify

# Health
curl -fsS http://localhost:9000/_/health

# S3 API answers signed requests
AWS_ACCESS_KEY_ID=$PROXY_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY=$PROXY_SECRET_ACCESS_KEY \
  aws --endpoint-url http://localhost:9000 s3 ls

Then open the admin GUI at http://localhost:9000/_/ and log in with the bootstrap password — the S3 API and the GUI share port 9000.