v2.31.0-dev3 cbca441

upgrading.md RawHistoryFolder

Upgrading Gordon

This guide covers breaking changes and migration steps between major versions.

v2.30.0 to v2.31.0

Breaking: Default Port Changes

Gordon now defaults to unprivileged ports that work without root or firewall rules:

Setting Old default New default
server.port 80 8088
server.registry_port 5000 5000 (unchanged)
server.tls_port (n/a) 8443

If you relied on the old defaults (no explicit port in your config), add the port explicitly:

[server]
port = 80

Or set up firewall port forwarding to the new defaults:

sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8088
sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443
sudo firewall-cmd --reload

New: Internal Certificate Authority

Gordon now includes an internal CA for automatic on-demand TLS. Set tls_port = 0 to disable. See Server Configuration for details.

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 accepted
  • auth.password and auth.password_hash config fields are removed
  • The gordon auth password hash CLI command is removed
  • The gordon auth login command now requires --token (no more interactive password prompt)
  • The /auth/password endpoint now returns 410 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_ttl configures the lifetime of ephemeral access tokens issued by /auth/token (default: "15m")
  • gordon auth show-token prints the stored token for a remote
  • gordon auth logout removes 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:

  1. Before upgrading, generate a token on your current Gordon instance:

    gordon auth token generate --subject deploy --scopes "push,pull" --expiry 0
    

    Save 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.

  2. Update remotes to use the generated token:

    gordon auth login --token <token>
    # or
    gordon remotes set-token prod <token>
    
  3. 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"
    
  4. Update CI/CD pipelines to use GORDON_TOKEN environment variable for authentication. See the deployment guides.

  5. Upgrade the binary and restart:

    curl -fsSL https://gordon.bnema.dev/install | bash
    systemctl --user restart gordon
    
  6. Verify 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
# 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

  1. Read the changelog for your target version
  2. Backup your config before upgrading
  3. Test in staging if possible
  4. Upgrade the binary:
    curl -fsSL https://gordon.bnema.dev/install | bash
    
  5. Restart Gordon:
    systemctl --user restart gordon
    
  6. Check logs for any errors:
    gordon logs
    

Getting Help

source
1# Upgrading Gordon
2
3This guide covers breaking changes and migration steps between major versions.
4
5## v2.30.0 to v2.31.0
6
7### Breaking: Default Port Changes
8
9Gordon now defaults to unprivileged ports that work without root or firewall rules:
10
11| Setting | Old default | New default |
12|---------|-------------|-------------|
13| `server.port` | `80` | `8088` |
14| `server.registry_port` | `5000` | `5000` (unchanged) |
15| `server.tls_port` | *(n/a)* | `8443` |
16
17**If you relied on the old defaults** (no explicit `port` in your config), add the port explicitly:
18
19```toml
20[server]
21port = 80
22```
23
24Or set up firewall port forwarding to the new defaults:
25
26```bash
27sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8088
28sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443
29sudo firewall-cmd --reload
30```
31
32### New: Internal Certificate Authority
33
34Gordon now includes an internal CA for automatic on-demand TLS. Set `tls_port = 0` to disable. See [Server Configuration](./config/server.md#internal-ca-and-tls) for details.
35
36## v2.16.0 to v2.30.0
37
38### Breaking: Password Authentication Removed
39
40Gordon v2.30.0 removes password-based authentication entirely. Only token-based authentication is supported.
41
42**What changed:**
43
44- `auth.type = "password"` is no longer accepted
45- `auth.password` and `auth.password_hash` config fields are removed
46- The `gordon auth password hash` CLI command is removed
47- The `gordon auth login` command now requires `--token` (no more interactive password prompt)
48- The `/auth/password` endpoint now returns `410 Gone`
49- Long-lived tokens are no longer accepted on admin/registry endpoints — they must be exchanged for ephemeral tokens via `/auth/token`
50
51**New features:**
52
53- `auth.access_token_ttl` configures the lifetime of ephemeral access tokens issued by `/auth/token` (default: `"15m"`)
54- `gordon auth show-token` prints the stored token for a remote
55- `gordon auth logout` removes the stored token (with optional `--revoke`)
56- Automatic token exchange: the CLI transparently exchanges long-lived tokens for ephemeral ones before API calls
57- Admin scopes (`admin:*:*`, `admin:routes:read`, etc.) allow fine-grained access control for remote CLI operations
58
59**Migration steps:**
60
611. **Before upgrading**, generate a token on your current Gordon instance:
62
63   ```bash
64   gordon auth token generate --subject deploy --scopes "push,pull" --expiry 0
65   ```
66
67   Save 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.
68
692. **Update remotes** to use the generated token:
70
71   ```bash
72   gordon auth login --token <token>
73   # or
74   gordon remotes set-token prod <token>
75   ```
76
773. **Update your config** to remove password fields:
78
79   **Before (v2.16.0):**
80
81   ```toml
82   [auth]
83   enabled = true
84   secrets_backend = "pass"
85   username = "deploy"
86   password_hash = "gordon/auth/password_hash"
87   token_secret = "gordon/auth/token_secret"
88   ```
89
90   **After (v2.30.0):**
91
92   ```toml
93   [auth]
94   enabled = true
95   secrets_backend = "pass"
96   token_secret = "gordon/auth/token_secret"
97   access_token_ttl = "15m"
98   ```
99
1004. **Update CI/CD pipelines** to use `GORDON_TOKEN` environment variable for authentication. See the [deployment guides](./deployment/index.md).
101
1025. **Upgrade the binary** and restart:
103
104   ```bash
105   curl -fsSL https://gordon.bnema.dev/install | bash
106   systemctl --user restart gordon
107   ```
108
1096. **Verify** the server starts without errors:
110
111   ```bash
112   journalctl --user -u gordon -f
113   ```
114
115### New: Configurable Access Token TTL
116
117Ephemeral access tokens issued by `/auth/token` now have a configurable lifetime via `auth.access_token_ttl` (default `"15m"`, maximum `"1h"`).
118
119Tokens 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`.
120
121```toml
122[auth]
123access_token_ttl = "30m"
124```
125
126### New: Admin Scopes
127
128Tokens can now include fine-grained admin scopes for remote CLI operations:
129
130```bash
131# Full admin access
132gordon auth token generate --subject admin --scopes "push,pull,admin:*:*" --expiry 0
133
134# Read-only monitoring
135gordon auth token generate --subject monitor --scopes "admin:status:read" --expiry 30d
136
137# CI deploy with route read + config write
138gordon auth token generate --subject ci --scopes "push,pull,admin:routes:read,admin:config:write" --expiry 0
139```
140
141See [Token Scopes](./config/auth.md#token-scopes) for the full list.
142
143## v2.6.0 to v2.7.0
144
145### Breaking: Token Secret Required
146
147Gordon v2.7.0 requires a `token_secret` for JWT authentication. The server will not start without it configured.
148
149**Error you'll see:**
150```
151Error: token_secret is required for JWT token generation; set GORDON_AUTH_TOKEN_SECRET environment variable or configure auth.token_secret
152```
153
154**Choose one of these migration options:**
155
156#### Option A: Environment Variable (simplest)
157
158```bash
159# Generate a random secret
160export GORDON_AUTH_TOKEN_SECRET="$(openssl rand -base64 32)"
161
162# Add to your shell profile or systemd service
163echo 'export GORDON_AUTH_TOKEN_SECRET="your-secret"' >> ~/.bashrc
164```
165
166For systemd services:
167```bash
168mkdir -p ~/.config/systemd/user/gordon.service.d
169cat > ~/.config/systemd/user/gordon.service.d/token.conf << EOF
170[Service]
171Environment="GORDON_AUTH_TOKEN_SECRET=$(openssl rand -base64 32)"
172EOF
173systemctl --user daemon-reload
174systemctl --user restart gordon
175```
176
177#### Option B: Config File with Pass (recommended for production)
178
179```bash
180# Generate and store secret in pass
181openssl rand -base64 32 | pass insert -e gordon/auth/token_secret
182
183# Update your gordon.toml
184```
185
186```toml
187[auth]
188enabled = true
189secrets_backend = "pass"
190token_secret = "gordon/auth/token_secret"
191```
192
193#### Option C: Config File with Unsafe Backend (development only)
194
195```bash
196# Generate secret file
197mkdir -p ~/.gordon/secrets
198openssl rand -base64 32 > ~/.gordon/secrets/token_secret
199chmod 600 ~/.gordon/secrets/token_secret
200```
201
202```toml
203[auth]
204enabled = true
205secrets_backend = "unsafe"
206token_secret = "token_secret"
207```
208
209### Breaking: Unsafe Token Store Warning
210
211Using `secrets_backend = "unsafe"` now logs a warning on startup:
212```
213WRN using unsafe secrets backend - secrets are stored in plain text
214```
215
216This is intentional to encourage secure secret storage in production. The warning can be ignored for development.
217
218### New Features
219
220- **Attachment secrets discovery**: `gordon secrets list <domain>` now shows secrets for attachment containers
221- **Auth login command**: `gordon auth login --remote <name>` for token authentication
222- **Rate limiting**: Configurable rate limits under `[api.rate_limit]`
223
224### Security Improvements
225
226v2.7.0 includes a comprehensive security audit with:
227
228- JWT tokens now include "not before" (nbf) claim
229- SSRF protection for external routes
230- Security headers middleware
231- Rate limiting on registry and token endpoints
232- Command injection prevention in pass provider
233- Path traversal prevention in secrets store
234
235## v2.5.0 to v2.6.0
236
237### Breaking: Config Restructure
238
239The `[secrets]` and `[registry_auth]` sections were merged into `[auth]`.
240
241**Before (v2.5.0):**
242```toml
243[secrets]
244backend = "pass"
245
246[registry_auth]
247enabled = true
248type = "password"
249password_hash = "gordon/registry/password_hash"
250```
251
252**After (v2.6.0+):**
253```toml
254[auth]
255enabled = true
256secrets_backend = "pass"
257password_hash = "gordon/auth/password_hash"
258```
259
260### Breaking: Auth Enabled by Default
261
262Gordon keeps auth enabled by default. If you set `auth.enabled = false`, Gordon runs in local-only mode (`/admin/*` disabled, `/v2/*` loopback-only).
263
264### Breaking: Secret Paths Changed
265
266If using pass or sops, update your secret paths:
267- `gordon/registry/*` → `gordon/auth/*`
268
269## General Upgrade Process
270
2711. **Read the changelog** for your target version
2722. **Backup your config** before upgrading
2733. **Test in staging** if possible
2744. **Upgrade the binary**:
275   ```bash
276   curl -fsSL https://gordon.bnema.dev/install | bash
277   ```
2785. **Restart Gordon**:
279   ```bash
280   systemctl --user restart gordon
281   ```
2826. **Check logs** for any errors:
283   ```bash
284   gordon logs
285   ```
286
287## Getting Help
288
289- [GitHub Issues](https://github.com/bnema/gordon/issues)
290- [Documentation](https://gordon.bnema.dev/docs)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close