Upgrading Gordon
This guide covers breaking changes and migration steps between major versions.
v2.16.0 to v2.30.0
Breaking: Password Authentication Removed
Gordon v2.30.0 removes password-based authentication entirely. Only token-based authentication is supported.
What changed:
auth.type = "password"is no longer acceptedauth.passwordandauth.password_hashconfig fields are removed- The
gordon auth password hashCLI command is removed - The
gordon auth logincommand now requires--token(no more interactive password prompt) - The
/auth/passwordendpoint now returns410 Gone - Long-lived tokens are no longer accepted on admin/registry endpoints — they must be exchanged for ephemeral tokens via
/auth/token
New features:
auth.access_token_ttlconfigures the lifetime of ephemeral access tokens issued by/auth/token(default:"15m")gordon auth show-tokenprints the stored token for a remotegordon auth logoutremoves the stored token (with optional--revoke)- Automatic token exchange: the CLI transparently exchanges long-lived tokens for ephemeral ones before API calls
- Admin scopes (
admin:*:*,admin:routes:read, etc.) allow fine-grained access control for remote CLI operations
Migration steps:
Before upgrading, generate a token on your current Gordon instance:
gordon auth token generate --subject deploy --scopes "push,pull" --expiry 0Save this token securely. You will need it after upgrading. Admin scopes (
admin:*:*) are only available after upgrading to v2.30.0 — regenerate your token with admin scopes after the upgrade if needed.Update remotes to use the generated token:
gordon auth login --token <token> # or gordon remotes set-token prod <token>Update your config to remove password fields:
Before (v2.16.0):
[auth] enabled = true secrets_backend = "pass" username = "deploy" password_hash = "gordon/auth/password_hash" token_secret = "gordon/auth/token_secret"After (v2.30.0):
[auth] enabled = true secrets_backend = "pass" token_secret = "gordon/auth/token_secret" access_token_ttl = "15m"Update CI/CD pipelines to use
GORDON_TOKENenvironment variable for authentication. See the deployment guides.Upgrade the binary and restart:
curl -fsSL https://gordon.bnema.dev/install | bash systemctl --user restart gordonVerify the server starts without errors:
journalctl --user -u gordon -f
New: Configurable Access Token TTL
Ephemeral access tokens issued by /auth/token now have a configurable lifetime via auth.access_token_ttl (default "15m", maximum "1h").
Tokens with a lifetime at or below MaxAccessTokenLifetime (1 hour) are treated as ephemeral: they skip token store validation for performance, which means they cannot be individually revoked. They become invalid only when they naturally expire. Shortening auth.access_token_ttl only reduces the exposure window; it does not enable per-token revocation. If you need explicit revocation, use a stored long-lived token instead of /auth/token.
[auth]
access_token_ttl = "30m"
New: Admin Scopes
Tokens can now include fine-grained admin scopes for remote CLI operations:
# Full admin access
gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
# Read-only monitoring
gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
# CI deploy with route read + config write
gordon auth token generate --subject ci --scopes "push,pull,admin:routes:read,admin:config:write" --expiry 0
See Token Scopes for the full list.
v2.6.0 to v2.7.0
Breaking: Token Secret Required
Gordon v2.7.0 requires a token_secret for JWT authentication. The server will not start without it configured.
Error you'll see:
Error: token_secret is required for JWT token generation; set GORDON_AUTH_TOKEN_SECRET environment variable or configure auth.token_secret
Choose one of these migration options:
Option A: Environment Variable (simplest)
# Generate a random secret
export GORDON_AUTH_TOKEN_SECRET="$(openssl rand -base64 32)"
# Add to your shell profile or systemd service
echo 'export GORDON_AUTH_TOKEN_SECRET="your-secret"' >> ~/.bashrc
For systemd services:
mkdir -p ~/.config/systemd/user/gordon.service.d
cat > ~/.config/systemd/user/gordon.service.d/token.conf << EOF
[Service]
Environment="GORDON_AUTH_TOKEN_SECRET=$(openssl rand -base64 32)"
EOF
systemctl --user daemon-reload
systemctl --user restart gordon
Option B: Config File with Pass (recommended for production)
# Generate and store secret in pass
openssl rand -base64 32 | pass insert -e gordon/auth/token_secret
# Update your gordon.toml
[auth]
enabled = true
secrets_backend = "pass"
token_secret = "gordon/auth/token_secret"
Option C: Config File with Unsafe Backend (development only)
# Generate secret file
mkdir -p ~/.gordon/secrets
openssl rand -base64 32 > ~/.gordon/secrets/token_secret
chmod 600 ~/.gordon/secrets/token_secret
[auth]
enabled = true
secrets_backend = "unsafe"
token_secret = "token_secret"
Breaking: Unsafe Token Store Warning
Using secrets_backend = "unsafe" now logs a warning on startup:
WRN using unsafe secrets backend - secrets are stored in plain text
This is intentional to encourage secure secret storage in production. The warning can be ignored for development.
New Features
- Attachment secrets discovery:
gordon secrets list <domain>now shows secrets for attachment containers - Auth login command:
gordon auth login --remote <name>for token authentication - Rate limiting: Configurable rate limits under
[api.rate_limit]
Security Improvements
v2.7.0 includes a comprehensive security audit with:
- JWT tokens now include "not before" (nbf) claim
- SSRF protection for external routes
- Security headers middleware
- Rate limiting on registry and token endpoints
- Command injection prevention in pass provider
- Path traversal prevention in secrets store
v2.5.0 to v2.6.0
Breaking: Config Restructure
The [secrets] and [registry_auth] sections were merged into [auth].
Before (v2.5.0):
[secrets]
backend = "pass"
[registry_auth]
enabled = true
type = "password"
password_hash = "gordon/registry/password_hash"
After (v2.6.0+):
[auth]
enabled = true
secrets_backend = "pass"
password_hash = "gordon/auth/password_hash"
Breaking: Auth Enabled by Default
Gordon keeps auth enabled by default. If you set auth.enabled = false, Gordon runs in local-only mode (/admin/* disabled, /v2/* loopback-only).
Breaking: Secret Paths Changed
If using pass or sops, update your secret paths:
gordon/registry/*→gordon/auth/*
General Upgrade Process
- Read the changelog for your target version
- Backup your config before upgrading
- Test in staging if possible
- Upgrade the binary:
curl -fsSL https://gordon.bnema.dev/install | bash - Restart Gordon:
systemctl --user restart gordon - Check logs for any errors:
gordon logs