v2.30.0-pre4 15d9fe3

server.md RawHistoryFolder

Server Configuration

Core server settings for Gordon.

Configuration

[server]
port = 8080                              # HTTP proxy port
registry_port = 5000                     # Container registry port
tls_enabled = false                      # Enable native TLS listener
tls_port = 443                           # HTTPS listener port
tls_cert_file = ""                       # PEM certificate file (required when TLS enabled)
tls_key_file = ""                        # PEM key file (required when TLS enabled)
gordon_domain = "gordon.mydomain.com"    # Gordon domain (required)
# data_dir = "~/.gordon"                 # Data storage directory (default)

Options

Option Type Default Description
port int 80 HTTP proxy port for routing traffic to containers
registry_port int 5000 Docker registry port for image push/pull
tls_enabled bool false Enable native HTTPS listener for proxy traffic
tls_port int 443 HTTPS listener port when tls_enabled is true
tls_cert_file string "" Path to PEM certificate file
tls_key_file string "" Path to PEM private key file
gordon_domain string required Domain for Gordon (registry + admin API)
registry_domain string - Deprecated alias for gordon_domain
data_dir string ~/.gordon Directory for registry data, logs, and env files
max_proxy_body_size string "512MB" Maximum request body size for proxied requests
max_blob_chunk_size string "95MB" Maximum request body size for a single registry blob upload chunk
registry_allowed_ips []string [] IPs or CIDR ranges allowed to access the registry (empty = allow all)

Port Configuration

Proxy Port

The port setting controls where Gordon listens for HTTP traffic:

[server]
port = 8080  # Use 8080 for rootless containers with port forwarding

For rootless containers, you'll typically use a high port and configure firewall port forwarding:

# Forward port 80 to 8080
sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080

Native TLS Listener

Enable native HTTPS directly in Gordon:

[server]
tls_enabled = true
tls_port = 443
tls_cert_file = "/etc/gordon/certs/fullchain.pem"
tls_key_file = "/etc/gordon/certs/privkey.pem"

With TLS enabled:

  • Gordon terminates HTTPS on tls_port
  • Host-based routing still works (apps, /v2/*, /auth/*, /admin/*)
  • port remains available for plain HTTP unless you restrict it externally
  • If tls_cert_file/tls_key_file are empty, Gordon auto-generates a self-signed pair in {data_dir}/tls/

For rootless user services, do not bind directly to 443. Use an unprivileged TLS port (for example 8443) and forward 443 to it at the firewall or edge proxy.

[server]
tls_enabled = true
tls_port = 8443

With firewalld and Tailscale:

# Verify tailscale0 is in trusted zone
sudo firewall-cmd --get-zone-of-interface=tailscale0

# If needed, place tailscale0 in trusted
sudo firewall-cmd --permanent --zone=trusted --add-interface=tailscale0
sudo firewall-cmd --reload

# Forward 443 -> 8443 permanently (IPv4 + IPv6)
sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443'
sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv6 forward-port port=443 protocol=tcp to-port=8443'
sudo firewall-cmd --reload

Registry Port

The registry_port setting controls where Gordon accepts image pushes:

[server]
registry_port = 5000

Docker/Podman clients push to this port:

docker push registry.mydomain.com:5000/myapp:latest

If the registry is served over plain HTTP (no TLS), clients must be configured to allow insecure access. See Troubleshooting: insecure registry for Docker and Podman instructions.

Gordon Domain

The gordon_domain is required and must match your DNS configuration:

[server]
gordon_domain = "gordon.mydomain.com"

This domain is used for:

  • Docker login and image push/pull operations
  • Admin API access (/admin/* endpoints)
  • CLI remote targeting (gordon routes --remote https://gordon.mydomain.com)
  • Authentication endpoints (/auth/*)

When requests arrive on the proxy port with this domain as the Host header, Gordon routes them to the backend services (registry and admin API).

Security note:

  • Direct access to /admin/* on registry_port is blocked for non-loopback clients.
  • Admin API traffic should go through the main proxy listener (server.port/server.tls_port).

Note: registry_domain is supported as a deprecated alias for backwards compatibility.

Data Directory

The data_dir setting controls where Gordon stores data:

[server]
data_dir = "~/.gordon"  # Default for user installations

Directory Structure

~/.gordon/
├── registry/           # Container images and manifests
│   ├── blobs/
│   └── manifests/
├── env/                # Environment files per domain
│   ├── app_mydomain_com.env
│   └── api_mydomain_com.env
├── logs/               # Application and container logs
│   ├── gordon.log
│   ├── proxy.log
│   └── containers/
└── secrets/            # Secrets (unsafe backend only)

Permissions

Gordon creates directories with secure permissions:

  • Directories: 0700 (owner only)
  • Files: 0600 (owner only)

Maximum Proxy Body Size

The max_proxy_body_size setting limits the size of request bodies that Gordon will forward to backend containers:

[server]
max_proxy_body_size = "512MB"  # Default

Purpose: Prevents resource exhaustion attacks from extremely large uploads through the proxy.

Supported units: B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)

Examples:

max_proxy_body_size = "100MB"   # Stricter limit
max_proxy_body_size = "1GB"     # Allow larger uploads
max_proxy_body_size = "0"       # No limit (not recommended)

Behavior:

  • When a request exceeds the limit, Gordon returns 413 Request Entity Too Large
  • The limit is applied before the request reaches the backend container
  • Uploads in progress are terminated when the limit is exceeded

Use cases:

  • File upload services: increase to 1GB or higher
  • CI/CD artifact uploads: adjust based on your largest artifacts
  • Tight security: reduce to 100MB or lower
  • Default (512MB): suitable for most applications

Warning: Setting this to 0 (no limit) allows unlimited upload sizes, which can lead to disk exhaustion and DoS vulnerabilities. Always set a reasonable limit for production deployments.

Maximum Registry Blob Chunk Size

The max_blob_chunk_size setting limits the size of a single blob upload request to the registry (PATCH/PUT under /v2/*/blobs/uploads/*):

[server]
max_blob_chunk_size = "95MB"  # Default

Purpose: Prevents excessive memory usage during blob uploads while allowing large real-world image layers.

Supported units: B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)

Examples:

max_blob_chunk_size = "256MB"  # Stricter limit
max_blob_chunk_size = "1GB"    # Allow larger layers

Behavior:

  • When a blob chunk exceeds the limit, Gordon returns 413 Request Entity Too Large
  • Gordon CLI uploads image layers in 50MB chunks by default, and this setting caps the maximum chunk accepted per request
  • Keep this below Cloudflare's 100MB per-request limit when operating behind Cloudflare; the default (95MB) is fine
  • Increase it only if you expect larger direct registry uploads from other clients

Registry IP Allowlist

The registry_allowed_ips setting restricts registry access to specific IPs or IP ranges. Accepts both CIDR notation (100.64.0.0/10) and individual IPs (203.0.113.50). When set, only requests from listed addresses (plus localhost) can reach registry and auth endpoints. An empty list allows all traffic (default).

[server]
registry_allowed_ips = [
  "100.64.0.0/10",   # Tailscale CGNAT range
  "203.0.113.50",    # single IP (treated as /32)
]

Behavior:

  • Single IPs are automatically converted to /32 (IPv4) or /128 (IPv6)
  • Denied requests receive 403 Forbidden
  • Localhost (127.0.0.0/8, ::1) is always allowed so Gordon can pull from its own registry
  • Respects trusted_proxies for accurate client IP extraction behind reverse proxies
  • Applied before rate limiting and authentication
  • Changes require a Gordon server restart; not picked up by config hot-reload

Use cases:

  • Restrict registry to Tailscale network: ["100.64.0.0/10"]
  • Restrict to private subnets: ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]
  • Allow a specific CI server: ["100.64.0.0/10", "203.0.113.50"]

Via environment variable:

GORDON_SERVER_REGISTRY_ALLOWED_IPS=100.64.0.0/10

Examples

Development Configuration

[server]
port = 8080
registry_port = 5000
gordon_domain = "gordon.local"
data_dir = "./dev-data"

Production Configuration

[server]
port = 8080
registry_port = 5000
gordon_domain = "gordon.company.com"
data_dir = "/var/lib/gordon"

Rootless Container Setup

[server]
port = 8080      # High port for rootless
registry_port = 5000
gordon_domain = "gordon.mydomain.com"

With firewall port forwarding:

sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
sudo firewall-cmd --reload
source
1# Server Configuration
2
3Core server settings for Gordon.
4
5## Configuration
6
7```toml
8[server]
9port = 8080                              # HTTP proxy port
10registry_port = 5000                     # Container registry port
11tls_enabled = false                      # Enable native TLS listener
12tls_port = 443                           # HTTPS listener port
13tls_cert_file = ""                       # PEM certificate file (required when TLS enabled)
14tls_key_file = ""                        # PEM key file (required when TLS enabled)
15gordon_domain = "gordon.mydomain.com"    # Gordon domain (required)
16# data_dir = "~/.gordon"                 # Data storage directory (default)
17```
18
19## Options
20
21| Option | Type | Default | Description |
22|--------|------|---------|-------------|
23| `port` | int | `80` | HTTP proxy port for routing traffic to containers |
24| `registry_port` | int | `5000` | Docker registry port for image push/pull |
25| `tls_enabled` | bool | `false` | Enable native HTTPS listener for proxy traffic |
26| `tls_port` | int | `443` | HTTPS listener port when `tls_enabled` is true |
27| `tls_cert_file` | string | `""` | Path to PEM certificate file |
28| `tls_key_file` | string | `""` | Path to PEM private key file |
29| `gordon_domain` | string | **required** | Domain for Gordon (registry + admin API) |
30| `registry_domain` | string | - | Deprecated alias for `gordon_domain` |
31| `data_dir` | string | `~/.gordon` | Directory for registry data, logs, and env files |
32| `max_proxy_body_size` | string | `"512MB"` | Maximum request body size for proxied requests |
33| `max_blob_chunk_size` | string | `"95MB"` | Maximum request body size for a single registry blob upload chunk |
34| `registry_allowed_ips` | []string | `[]` | IPs or CIDR ranges allowed to access the registry (empty = allow all) |
35
36## Port Configuration
37
38### Proxy Port
39
40The `port` setting controls where Gordon listens for HTTP traffic:
41
42```toml
43[server]
44port = 8080  # Use 8080 for rootless containers with port forwarding
45```
46
47For rootless containers, you'll typically use a high port and configure firewall port forwarding:
48
49```bash
50# Forward port 80 to 8080
51sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
52```
53
54### Native TLS Listener
55
56Enable native HTTPS directly in Gordon:
57
58```toml
59[server]
60tls_enabled = true
61tls_port = 443
62tls_cert_file = "/etc/gordon/certs/fullchain.pem"
63tls_key_file = "/etc/gordon/certs/privkey.pem"
64```
65
66With TLS enabled:
67- Gordon terminates HTTPS on `tls_port`
68- Host-based routing still works (apps, `/v2/*`, `/auth/*`, `/admin/*`)
69- `port` remains available for plain HTTP unless you restrict it externally
70- If `tls_cert_file`/`tls_key_file` are empty, Gordon auto-generates a self-signed pair in `{data_dir}/tls/`
71
72For rootless user services, do not bind directly to `443`. Use an unprivileged TLS port (for example `8443`) and forward `443` to it at the firewall or edge proxy.
73
74```toml
75[server]
76tls_enabled = true
77tls_port = 8443
78```
79
80With firewalld and Tailscale:
81
82```bash
83# Verify tailscale0 is in trusted zone
84sudo firewall-cmd --get-zone-of-interface=tailscale0
85
86# If needed, place tailscale0 in trusted
87sudo firewall-cmd --permanent --zone=trusted --add-interface=tailscale0
88sudo firewall-cmd --reload
89
90# Forward 443 -> 8443 permanently (IPv4 + IPv6)
91sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443'
92sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv6 forward-port port=443 protocol=tcp to-port=8443'
93sudo firewall-cmd --reload
94```
95
96### Registry Port
97
98The `registry_port` setting controls where Gordon accepts image pushes:
99
100```toml
101[server]
102registry_port = 5000
103```
104
105Docker/Podman clients push to this port:
106
107```bash
108docker push registry.mydomain.com:5000/myapp:latest
109```
110
111If the registry is served over plain HTTP (no TLS), clients must be configured to allow insecure access. See [Troubleshooting: insecure registry](../reference/troubleshooting.md#server-gave-http-response-to-https-client) for Docker and Podman instructions.
112
113## Gordon Domain
114
115The `gordon_domain` is required and must match your DNS configuration:
116
117```toml
118[server]
119gordon_domain = "gordon.mydomain.com"
120```
121
122This domain is used for:
123- Docker login and image push/pull operations
124- Admin API access (`/admin/*` endpoints)
125- CLI remote targeting (`gordon routes --remote https://gordon.mydomain.com`)
126- Authentication endpoints (`/auth/*`)
127
128When requests arrive on the proxy port with this domain as the Host header, Gordon routes them to the backend services (registry and admin API).
129
130Security note:
131- Direct access to `/admin/*` on `registry_port` is blocked for non-loopback clients.
132- Admin API traffic should go through the main proxy listener (`server.port`/`server.tls_port`).
133
134> **Note:** `registry_domain` is supported as a deprecated alias for backwards compatibility.
135
136## Data Directory
137
138The `data_dir` setting controls where Gordon stores data:
139
140```toml
141[server]
142data_dir = "~/.gordon"  # Default for user installations
143```
144
145### Directory Structure
146
147```
148~/.gordon/
149├── registry/           # Container images and manifests
150│   ├── blobs/
151│   └── manifests/
152├── env/                # Environment files per domain
153│   ├── app_mydomain_com.env
154│   └── api_mydomain_com.env
155├── logs/               # Application and container logs
156│   ├── gordon.log
157│   ├── proxy.log
158│   └── containers/
159└── secrets/            # Secrets (unsafe backend only)
160```
161
162### Permissions
163
164 Gordon creates directories with secure permissions:
165 - Directories: `0700` (owner only)
166 - Files: `0600` (owner only)
167
168 ## Maximum Proxy Body Size
169
170 The `max_proxy_body_size` setting limits the size of request bodies that Gordon will forward to backend containers:
171
172 ```toml
173 [server]
174 max_proxy_body_size = "512MB"  # Default
175 ```
176
177 **Purpose:** Prevents resource exhaustion attacks from extremely large uploads through the proxy.
178
179 **Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
180
181 **Examples:**
182 ```toml
183 max_proxy_body_size = "100MB"   # Stricter limit
184 max_proxy_body_size = "1GB"     # Allow larger uploads
185 max_proxy_body_size = "0"       # No limit (not recommended)
186 ```
187
188 **Behavior:**
189 - When a request exceeds the limit, Gordon returns `413 Request Entity Too Large`
190 - The limit is applied before the request reaches the backend container
191 - Uploads in progress are terminated when the limit is exceeded
192
193 **Use cases:**
194 - File upload services: increase to `1GB` or higher
195 - CI/CD artifact uploads: adjust based on your largest artifacts
196 - Tight security: reduce to `100MB` or lower
197 - Default (512MB): suitable for most applications
198
199 > **Warning:** Setting this to `0` (no limit) allows unlimited upload sizes, which can lead to disk exhaustion and DoS vulnerabilities. Always set a reasonable limit for production deployments.
200
201## Maximum Registry Blob Chunk Size
202
203The `max_blob_chunk_size` setting limits the size of a single blob upload request to the registry (`PATCH`/`PUT` under `/v2/*/blobs/uploads/*`):
204
205```toml
206[server]
207max_blob_chunk_size = "95MB"  # Default
208```
209
210**Purpose:** Prevents excessive memory usage during blob uploads while allowing large real-world image layers.
211
212**Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
213
214**Examples:**
215
216```toml
217max_blob_chunk_size = "256MB"  # Stricter limit
218max_blob_chunk_size = "1GB"    # Allow larger layers
219```
220
221**Behavior:**
222- When a blob chunk exceeds the limit, Gordon returns `413 Request Entity Too Large`
223- Gordon CLI uploads image layers in 50MB chunks by default, and this setting caps the maximum chunk accepted per request
224- Keep this below Cloudflare's 100MB per-request limit when operating behind Cloudflare; the default (`95MB`) is fine
225- Increase it only if you expect larger direct registry uploads from other clients
226
227## Registry IP Allowlist
228
229The `registry_allowed_ips` setting restricts registry access to specific IPs or IP ranges. Accepts both CIDR notation (`100.64.0.0/10`) and individual IPs (`203.0.113.50`). When set, only requests from listed addresses (plus localhost) can reach registry and auth endpoints. An empty list allows all traffic (default).
230
231```toml
232[server]
233registry_allowed_ips = [
234  "100.64.0.0/10",   # Tailscale CGNAT range
235  "203.0.113.50",    # single IP (treated as /32)
236]
237```
238
239**Behavior:**
240- Single IPs are automatically converted to `/32` (IPv4) or `/128` (IPv6)
241- Denied requests receive `403 Forbidden`
242- Localhost (`127.0.0.0/8`, `::1`) is always allowed so Gordon can pull from its own registry
243- Respects `trusted_proxies` for accurate client IP extraction behind reverse proxies
244- Applied before rate limiting and authentication
245- Changes require a Gordon server restart; not picked up by config hot-reload
246
247**Use cases:**
248- Restrict registry to Tailscale network: `["100.64.0.0/10"]`
249- Restrict to private subnets: `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]`
250- Allow a specific CI server: `["100.64.0.0/10", "203.0.113.50"]`
251
252Via environment variable:
253
254```bash
255GORDON_SERVER_REGISTRY_ALLOWED_IPS=100.64.0.0/10
256```
257
258## Examples
259
260### Development Configuration
261
262```toml
263[server]
264port = 8080
265registry_port = 5000
266gordon_domain = "gordon.local"
267data_dir = "./dev-data"
268```
269
270### Production Configuration
271
272```toml
273[server]
274port = 8080
275registry_port = 5000
276gordon_domain = "gordon.company.com"
277data_dir = "/var/lib/gordon"
278```
279
280### Rootless Container Setup
281
282```toml
283[server]
284port = 8080      # High port for rootless
285registry_port = 5000
286gordon_domain = "gordon.mydomain.com"
287```
288
289With firewall port forwarding:
290```bash
291sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
292sudo firewall-cmd --reload
293```
294
295## Related
296
297- [Configuration Overview](./index.md)
298- [Installation Guide](../installation.md)
299- [Routes Configuration](./routes.md)

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