Upgrade guide
How to move between DeltaGlider Proxy versions safely, plus the TOML → YAML migration.
Standard upgrade workflow
The proxy is a single stateful binary. Upgrades are "backup, swap, verify."
-
Back up first. From the admin UI: Full Backup → Export, or via API:
curl -b /tmp/admin.cookies \ "https://dgp.example.com/_/api/admin/backup" \ -o dgp-backup-$(date +%Y%m%d-%H%M%S).zipThe zip is atomic and sha256-verified on restore — see reference/admin-api.md. Store it somewhere the upgrade process itself can't break.
-
Roll the image/binary. For Docker:
docker pull beshultd/deltaglider_proxy:0.8.x docker stop dgp && docker rm dgp docker run -d --name dgp -p 9000:9000 \ -v dgp-data:/data \ -e DGP_BOOTSTRAP_PASSWORD_HASH=... \ beshultd/deltaglider_proxy:0.8.xCoolify, Kubernetes, and systemd have their own "pull + restart" verbs. All that matters:
/datapersists across the swap. -
Verify. Four checks:
# Health curl -s https://dgp.example.com/_/health # Version matches the image you deployed curl -s -b cookies https://dgp.example.com/_/api/whoami | jq .version # A read against an existing object (regression test) aws --endpoint-url https://dgp.example.com s3 ls s3://my-bucket # Admin session still works curl -b cookies https://dgp.example.com/_/api/admin/users | jq '.[] | .name' -
If something broke, the backup zip from step 1 imports atomically:
curl -b cookies -X POST \ -H "Content-Type: application/zip" \ --data-binary @dgp-backup-...zip \ https://dgp.example.com/_/api/admin/backup
Version compatibility
Patch and minor upgrades inside the 0.8.x line are drop-in. The config file format, IAM DB schema, and S3 wire format are stable across 0.8.*.
Across minors: schema migrations run automatically on first start. The config DB is on schema v6 in current builds (v6 adds replication runtime-state tables); any binary 0.8.0+ migrates forward on boot. Forward migrations are one-way — once the DB is upgraded, an older binary may not read it.
Across majors (future 0.x → 1.0): pre-release — expect breaking changes. Always follow the release notes for that version, and always export a Full Backup before trying it.
TOML → YAML migration
YAML is the canonical format as of v0.8.0. TOML still loads but emits a deprecation warning on every startup (suppress with DGP_SILENCE_TOML_DEPRECATION=1). TOML will be removed in a future minor release; migrate at your own pace within the grace window.
One-liner (most installs)
deltaglider_proxy config migrate \
/etc/deltaglider_proxy/config.toml \
--out /etc/deltaglider_proxy/config.yaml
Point the server at the new file (--config flag, DGP_CONFIG env, or via the standard search path) and restart. Done.
Step-by-step
1. Run the migrator.
deltaglider_proxy config migrate /etc/deltaglider_proxy/config.toml \
--out /etc/deltaglider_proxy/config.yaml
Emits one file per section if you pass --split, useful for GitOps setups:
deltaglider_proxy config migrate config.toml --split --out-dir ./config.d/
# writes: admission.yaml, access.yaml, storage.yaml, advanced.yaml
2. Inspect the output. Canonical YAML uses the four-section shape:
admission:
blocks: []
access:
access_key_id: ...
secret_access_key: ...
iam_mode: gui
storage:
backend:
type: s3
endpoint: ...
region: ...
buckets: {}
advanced:
cache_size_mb: 1024
session_ttl_hours: 4
All secrets come through redacted (null) — the migrator intentionally doesn't copy them. Inject them via env vars or the admin UI (see step 4).
3. Validate before applying. The config lint subcommand parses + validates without touching the server:
deltaglider_proxy config lint /etc/deltaglider_proxy/config.yaml
# Exit: 0 = valid, 3 = I/O, 4 = parse, 6 = validation
Wire this into CI so drift is caught in PR.
4. Point the server at the new file. File search order (first match wins):
DGP_CONFIGenv var./deltaglider_proxy.yaml./deltaglider_proxy.yml./deltaglider_proxy.toml(deprecated)/etc/deltaglider_proxy/config.yaml/etc/deltaglider_proxy/config.yml/etc/deltaglider_proxy/config.toml(deprecated)
If you keep both .toml and .yaml in the same directory, .yaml wins.
5. Feed secrets back in. The migrator redacts:
access.access_key_id/access.secret_access_key→ inject viaDGP_ACCESS_KEY_ID/DGP_SECRET_ACCESS_KEYor use the admin UI.- Storage backend creds →
DGP_BE_AWS_ACCESS_KEY_ID/DGP_BE_AWS_SECRET_ACCESS_KEYor the admin UI. advanced.bootstrap_password_hash→DGP_BOOTSTRAP_PASSWORD_HASHenv var (base64-wrapped form avoids$escaping issues in Docker).- OAuth
client_secretvalues — restore via the admin UI, or via a Full Backup zip import (see reference/admin-api.md).
6. Silence the deprecation warning on stragglers. If you can't migrate immediately (e.g. third-party Ansible using TOML):
DGP_SILENCE_TOML_DEPRECATION=1 deltaglider_proxy
The S3-synced IAM database
Entirely separate from the YAML config. deltaglider_config.db (SQLCipher-encrypted SQLite) holds users, groups, OAuth providers, mapping rules. The YAML config never carries IAM state.
When upgrading across instances with DGP_CONFIG_SYNC_BUCKET set, the newer binary uploads after any mutation; older binaries (still running during a rolling upgrade) download but won't understand post-migration schema changes. Either:
- Upgrade all instances before making IAM mutations, or
- Accept that mid-rollout mutations are lost on older-reader downloads until they too upgrade.
Common gotchas
$in Docker env. Bcrypt hashes contain$. Use base64-wrapped form (DGP_BOOTSTRAP_PASSWORD_HASH=JDJ5JDEyJGV...) or single-quote the value in compose files.force_path_style. MinIO needstrue; AWS S3 needsfalse. The migrator preserves whatever the TOML had.- Implicit defaults. Fields absent from YAML take their default. Don't port fields that were already default in TOML — it clutters the canonical shape.
- Admission chain order. Admission blocks are order-significant. The migrator preserves order; review
admission:carefully. iam_mode: declarative. YAML becomes authoritative for IAM users, groups, OAuth providers, and mapping rules. Admin-API IAM mutations return 403;/config/applyreconciles the encrypted DB to YAML atomically. Seed from an existing DB withGET /_/api/admin/config/declarative-iam-export, or author IAM directly in YAML.
v0.9: per-backend encryption (breaking)
v0.9 replaced the single global advanced.encryption_key field with per-backend encryption blocks. If you're upgrading from a pre-0.9 pre-release, the old field is no longer recognized — any YAML still carrying it silently drops the key.
What changed:
| Before (pre-v0.9) | After (v0.9) |
|---|---|
advanced.encryption_key: <hex> | storage.backend_encryption: { mode: aes256-gcm-proxy, key: <hex> } (singleton) or storage.backends[*].encryption: { ... } (list) |
DGP_ENCRYPTION_KEY env var | Same name for singleton path; DGP_BACKEND_<NAME>_ENCRYPTION_KEY for named backends |
Global encryption_enabled in GET /config | Per-backend encryption summary on each BackendInfoResponse |
Dedicated EncryptionPanel page | Subsection inside each backend card on the BackendsPanel |
Mechanical conversion — single-backend deployment, pre-v0.9 YAML:
# OLD (pre-0.9)
advanced:
encryption_key: 0123456789abcdef...
becomes:
# NEW (v0.9+)
storage:
backend_encryption:
mode: aes256-gcm-proxy
key: "${DGP_ENCRYPTION_KEY}" # move the hex to the env
With DGP_ENCRYPTION_KEY in the environment unchanged.
On-disk objects are unaffected. v0.9 reads pre-v0.9 encrypted objects without ceremony — the wire format didn't change, only the config location. The dg-encryption-key-id stamp is new as of v0.9 but OPTIONAL — historical objects without the stamp still decrypt as long as the key material matches.
If you had no encryption configured pre-0.9: nothing to do. Your backends default to encryption: none.
If you want to move from proxy-AES to SSE-KMS as part of the upgrade: do the upgrade first (keep your existing key), then configure the decrypt-only shim to migrate. See reference/encryption-at-rest.md §Rotation recipes recipe (C).
Verification checklist (after any upgrade or migration)
-
/_/healthreturns HTTP 200. -
/_/api/whoamireports the expectedversion. - An existing object downloads byte-identical:
aws s3 cp s3://bucket/known-file ./out && sha256sum outmatches the known checksum. - The admin UI logs in with the bootstrap password (or OAuth) on the first try.
-
/_/admin/diagnostics/auditshows recent entries — the audit ring is populating. - Prometheus scrape returns valid metrics (if monitoring is wired up).
Related
- reference/configuration.md — the complete YAML field reference.
- reference/admin-api.md — Full Backup export/import.
- 20-production-deployment.md — the ops side of running the server.