v2.31.0-dev2 4b72742

server.md RawHistoryFolder

Server Configuration

Core server settings for Gordon.

Configuration

[server]
port = 8088                              # HTTP proxy port
registry_port = 5000                     # Container registry port
tls_port = 8443                          # HTTPS listener port (0 = disabled)
# tls_cert_file = ""                       # Optional: PEM certificate for static TLS
# tls_key_file = ""                        # Optional: PEM key for static TLS
# force_https_redirect = false             # Redirect all HTTP traffic to HTTPS
gordon_domain = "gordon.mydomain.com"    # Gordon domain (required)
# data_dir = "~/.gordon"                 # Data storage directory (default)

Options

Option Type Default Description
port int 8088 HTTP proxy port for routing traffic to containers
registry_port int 5000 Docker registry port for image push/pull
tls_port int 8443 HTTPS listener port with internal CA. Set to 0 to disable TLS entirely
tls_cert_file string "" Path to PEM certificate file. When set (with tls_key_file), this cert is served for matching SNI domains; unmatched domains fall through to the internal CA
tls_key_file string "" Path to PEM private key file. Must be set together with tls_cert_file
force_https_redirect bool false Redirect all HTTP requests to the HTTPS port. For direct-access setups without a TLS-terminating proxy
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)
proxy_allowed_ips []string [] IPs or CIDR ranges allowed to reach the proxy (empty = allow all)
registry_listen_address string "" Bind address for registry (empty = all interfaces)

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

Internal CA and TLS

Gordon includes an internal certificate authority that issues on-demand TLS certificates for proxied domains. The HTTPS listener is enabled by default on tls_port (8443).

[server]
tls_port = 8443   # Default. Set to 0 to disable TLS entirely.

With TLS enabled:

  • Gordon runs an internal CA (root + intermediate) stored in {data_dir}/pki/
  • Leaf certificates are issued on-demand per domain (SNI-based) and cached in memory
  • The intermediate CA auto-renews before expiry
  • An onboarding page at https://<gordon-host>:<tls_port>/ca lets clients download the root CA certificate
  • The root CA is stable across restarts (generated once, persisted to disk)

Custom certificates

To use your own certificate (e.g. from Tailscale, Let's Encrypt, or a corporate CA) alongside the internal CA:

[server]
tls_cert_file = "/etc/gordon/tls/cert.pem"
tls_key_file = "/etc/gordon/tls/key.pem"

The static certificate is served for SNI-matching domains (including wildcards). All other domains get on-demand certs from the internal CA.

Direct HTTP Onboarding

When tls_port is non-zero, direct HTTP clients (those not arriving through a trusted proxy) are restricted to CA onboarding paths only:

  • /, /ca, /ca.crt, /ca.mobileconfig — serve the onboarding page and CA certificate downloads
  • /.well-known/acme-challenge/* — returns 404 Not Found (reserved for future ACME support)
  • All other paths return 403 Forbidden

This lets new clients discover and trust the internal CA over plain HTTP without exposing the full application. Trusted proxy traffic (e.g. from Cloudflare) continues through the normal HTTP proxy path unaffected.

The onboarding page is also available on HTTPS at /ca.

HTTP to HTTPS redirect

When clients connect directly (no Cloudflare or reverse proxy in front), enable force_https_redirect to redirect all HTTP traffic to the HTTPS port. Direct HTTP onboarding paths are still served even with this flag enabled.

[server]
force_https_redirect = true

When proxy_allowed_ips is configured, non-proxy clients are redirected automatically even without this flag — trusted proxy IPs pass through to serve Cloudflare-proxied traffic.

Disabling TLS

For setups where TLS is handled entirely by an external proxy (Cloudflare, nginx, etc.):

[server]
tls_port = 0   # No HTTPS listener, no internal CA generated

Firewall port forwarding

For rootless user services, forward 443 to the high port at the firewall:

# Forward 443 -> 8443
sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443
sudo firewall-cmd --reload

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

Proxy Origin IP Allowlist

The proxy_allowed_ips setting restricts which IPs can reach the proxy server. This prevents direct-to-origin attacks that bypass CDN protections (e.g. Cloudflare WAF, DDoS mitigation). When set, only connections from listed CIDRs (plus localhost) are accepted.

[server]
# Only accept proxy traffic from Cloudflare edge IPs
proxy_allowed_ips = [
  "173.245.48.0/20", "103.21.244.0/22", "103.22.200.0/22",
  "103.31.4.0/22", "141.101.64.0/18", "108.162.192.0/18",
  "190.93.240.0/20", "188.114.96.0/20", "197.234.240.0/22",
  "198.41.128.0/17", "162.158.0.0/15", "104.16.0.0/13",
  "104.24.0.0/14", "172.64.0.0/13", "131.0.72.0/22",
]

Behavior:

  • Checks the direct connection IP (RemoteAddr), not X-Forwarded-For
  • Localhost is always allowed
  • Denied requests receive 403 Forbidden
  • An empty list allows all traffic (default)

Important: Cloudflare publishes their IP ranges at cloudflare.com/ips. Keep your allowlist updated when Cloudflare adds new ranges.

Registry Listen Address

The registry_listen_address controls which interface the registry server binds to. By default it binds to all interfaces. Set to 127.0.0.1 to restrict registry access to localhost only, preventing containers from reaching the registry via the Docker bridge gateway.

[server]
registry_listen_address = "127.0.0.1"  # Loopback only

HSTS

HSTS headers are sent automatically on the HTTPS listener (when r.TLS != nil). When Gordon runs behind a TLS-terminating proxy (Cloudflare, Tailscale) and only receives plain HTTP, HSTS is not sent — the edge proxy is expected to handle it.

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 = 8088                              # HTTP proxy port
10registry_port = 5000                     # Container registry port
11tls_port = 8443                          # HTTPS listener port (0 = disabled)
12# tls_cert_file = ""                       # Optional: PEM certificate for static TLS
13# tls_key_file = ""                        # Optional: PEM key for static TLS
14# force_https_redirect = false             # Redirect all HTTP traffic to HTTPS
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 | `8088` | HTTP proxy port for routing traffic to containers |
24| `registry_port` | int | `5000` | Docker registry port for image push/pull |
25| `tls_port` | int | `8443` | HTTPS listener port with internal CA. Set to `0` to disable TLS entirely |
26| `tls_cert_file` | string | `""` | Path to PEM certificate file. When set (with `tls_key_file`), this cert is served for matching SNI domains; unmatched domains fall through to the internal CA |
27| `tls_key_file` | string | `""` | Path to PEM private key file. Must be set together with `tls_cert_file` |
28| `force_https_redirect` | bool | `false` | Redirect all HTTP requests to the HTTPS port. For direct-access setups without a TLS-terminating proxy |
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| `proxy_allowed_ips` | []string | `[]` | IPs or CIDR ranges allowed to reach the proxy (empty = allow all) |
36| `registry_listen_address` | string | `""` | Bind address for registry (empty = all interfaces) |
37
38## Port Configuration
39
40### Proxy Port
41
42The `port` setting controls where Gordon listens for HTTP traffic:
43
44```toml
45[server]
46port = 8080  # Use 8080 for rootless containers with port forwarding
47```
48
49For rootless containers, you'll typically use a high port and configure firewall port forwarding:
50
51```bash
52# Forward port 80 to 8080
53sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
54```
55
56### Internal CA and TLS
57
58Gordon includes an internal certificate authority that issues on-demand TLS certificates for proxied domains. The HTTPS listener is enabled by default on `tls_port` (8443).
59
60```toml
61[server]
62tls_port = 8443   # Default. Set to 0 to disable TLS entirely.
63```
64
65With TLS enabled:
66- Gordon runs an internal CA (root + intermediate) stored in `{data_dir}/pki/`
67- Leaf certificates are issued on-demand per domain (SNI-based) and cached in memory
68- The intermediate CA auto-renews before expiry
69- An onboarding page at `https://<gordon-host>:<tls_port>/ca` lets clients download the root CA certificate
70- The root CA is stable across restarts (generated once, persisted to disk)
71
72#### Custom certificates
73
74To use your own certificate (e.g. from Tailscale, Let's Encrypt, or a corporate CA) alongside the internal CA:
75
76```toml
77[server]
78tls_cert_file = "/etc/gordon/tls/cert.pem"
79tls_key_file = "/etc/gordon/tls/key.pem"
80```
81
82The static certificate is served for SNI-matching domains (including wildcards). All other domains get on-demand certs from the internal CA.
83
84#### Direct HTTP Onboarding
85
86When `tls_port` is non-zero, direct HTTP clients (those not arriving through a trusted proxy) are restricted to CA onboarding paths only:
87
88- `/`, `/ca`, `/ca.crt`, `/ca.mobileconfig` — serve the onboarding page and CA certificate downloads
89- `/.well-known/acme-challenge/*` — returns `404 Not Found` (reserved for future ACME support)
90- All other paths return `403 Forbidden`
91
92This lets new clients discover and trust the internal CA over plain HTTP without exposing the full application. Trusted proxy traffic (e.g. from Cloudflare) continues through the normal HTTP proxy path unaffected.
93
94The onboarding page is also available on HTTPS at `/ca`.
95
96#### HTTP to HTTPS redirect
97
98When clients connect directly (no Cloudflare or reverse proxy in front), enable `force_https_redirect` to redirect all HTTP traffic to the HTTPS port. Direct HTTP onboarding paths are still served even with this flag enabled.
99
100```toml
101[server]
102force_https_redirect = true
103```
104
105When `proxy_allowed_ips` is configured, non-proxy clients are redirected automatically even without this flag — trusted proxy IPs pass through to serve Cloudflare-proxied traffic.
106
107#### Disabling TLS
108
109For setups where TLS is handled entirely by an external proxy (Cloudflare, nginx, etc.):
110
111```toml
112[server]
113tls_port = 0   # No HTTPS listener, no internal CA generated
114```
115
116#### Firewall port forwarding
117
118For rootless user services, forward 443 to the high port at the firewall:
119
120```bash
121# Forward 443 -> 8443
122sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443
123sudo firewall-cmd --reload
124```
125
126With firewalld and Tailscale:
127
128```bash
129# Verify tailscale0 is in trusted zone
130sudo firewall-cmd --get-zone-of-interface=tailscale0
131
132# If needed, place tailscale0 in trusted
133sudo firewall-cmd --permanent --zone=trusted --add-interface=tailscale0
134sudo firewall-cmd --reload
135
136# Forward 443 -> 8443 permanently (IPv4 + IPv6)
137sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv4 forward-port port=443 protocol=tcp to-port=8443'
138sudo firewall-cmd --permanent --zone=trusted --add-rich-rule='rule family=ipv6 forward-port port=443 protocol=tcp to-port=8443'
139sudo firewall-cmd --reload
140```
141
142### Registry Port
143
144The `registry_port` setting controls where Gordon accepts image pushes:
145
146```toml
147[server]
148registry_port = 5000
149```
150
151Docker/Podman clients push to this port:
152
153```bash
154docker push registry.mydomain.com:5000/myapp:latest
155```
156
157If 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.
158
159## Gordon Domain
160
161The `gordon_domain` is required and must match your DNS configuration:
162
163```toml
164[server]
165gordon_domain = "gordon.mydomain.com"
166```
167
168This domain is used for:
169- Docker login and image push/pull operations
170- Admin API access (`/admin/*` endpoints)
171- CLI remote targeting (`gordon routes --remote https://gordon.mydomain.com`)
172- Authentication endpoints (`/auth/*`)
173
174When requests arrive on the proxy port with this domain as the Host header, Gordon routes them to the backend services (registry and admin API).
175
176Security note:
177- Direct access to `/admin/*` on `registry_port` is blocked for non-loopback clients.
178- Admin API traffic should go through the main proxy listener (`server.port`/`server.tls_port`).
179
180> **Note:** `registry_domain` is supported as a deprecated alias for backwards compatibility.
181
182## Data Directory
183
184The `data_dir` setting controls where Gordon stores data:
185
186```toml
187[server]
188data_dir = "~/.gordon"  # Default for user installations
189```
190
191### Directory Structure
192
193```
194~/.gordon/
195├── registry/           # Container images and manifests
196│   ├── blobs/
197│   └── manifests/
198├── env/                # Environment files per domain
199│   ├── app_mydomain_com.env
200│   └── api_mydomain_com.env
201├── logs/               # Application and container logs
202│   ├── gordon.log
203│   ├── proxy.log
204│   └── containers/
205└── secrets/            # Secrets (unsafe backend only)
206```
207
208### Permissions
209
210 Gordon creates directories with secure permissions:
211 - Directories: `0700` (owner only)
212 - Files: `0600` (owner only)
213
214 ## Maximum Proxy Body Size
215
216 The `max_proxy_body_size` setting limits the size of request bodies that Gordon will forward to backend containers:
217
218 ```toml
219 [server]
220 max_proxy_body_size = "512MB"  # Default
221 ```
222
223 **Purpose:** Prevents resource exhaustion attacks from extremely large uploads through the proxy.
224
225 **Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
226
227 **Examples:**
228 ```toml
229 max_proxy_body_size = "100MB"   # Stricter limit
230 max_proxy_body_size = "1GB"     # Allow larger uploads
231 max_proxy_body_size = "0"       # No limit (not recommended)
232 ```
233
234 **Behavior:**
235 - When a request exceeds the limit, Gordon returns `413 Request Entity Too Large`
236 - The limit is applied before the request reaches the backend container
237 - Uploads in progress are terminated when the limit is exceeded
238
239 **Use cases:**
240 - File upload services: increase to `1GB` or higher
241 - CI/CD artifact uploads: adjust based on your largest artifacts
242 - Tight security: reduce to `100MB` or lower
243 - Default (512MB): suitable for most applications
244
245 > **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.
246
247## Maximum Registry Blob Chunk Size
248
249The `max_blob_chunk_size` setting limits the size of a single blob upload request to the registry (`PATCH`/`PUT` under `/v2/*/blobs/uploads/*`):
250
251```toml
252[server]
253max_blob_chunk_size = "95MB"  # Default
254```
255
256**Purpose:** Prevents excessive memory usage during blob uploads while allowing large real-world image layers.
257
258**Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
259
260**Examples:**
261
262```toml
263max_blob_chunk_size = "256MB"  # Stricter limit
264max_blob_chunk_size = "1GB"    # Allow larger layers
265```
266
267**Behavior:**
268- When a blob chunk exceeds the limit, Gordon returns `413 Request Entity Too Large`
269- Gordon CLI uploads image layers in 50MB chunks by default, and this setting caps the maximum chunk accepted per request
270- Keep this below Cloudflare's 100MB per-request limit when operating behind Cloudflare; the default (`95MB`) is fine
271- Increase it only if you expect larger direct registry uploads from other clients
272
273## Registry IP Allowlist
274
275The `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).
276
277```toml
278[server]
279registry_allowed_ips = [
280  "100.64.0.0/10",   # Tailscale CGNAT range
281  "203.0.113.50",    # single IP (treated as /32)
282]
283```
284
285**Behavior:**
286- Single IPs are automatically converted to `/32` (IPv4) or `/128` (IPv6)
287- Denied requests receive `403 Forbidden`
288- Localhost (`127.0.0.0/8`, `::1`) is always allowed so Gordon can pull from its own registry
289- Respects `trusted_proxies` for accurate client IP extraction behind reverse proxies
290- Applied before rate limiting and authentication
291- Changes require a Gordon server restart; not picked up by config hot-reload
292
293**Use cases:**
294- Restrict registry to Tailscale network: `["100.64.0.0/10"]`
295- Restrict to private subnets: `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]`
296- Allow a specific CI server: `["100.64.0.0/10", "203.0.113.50"]`
297
298Via environment variable:
299
300```bash
301GORDON_SERVER_REGISTRY_ALLOWED_IPS=100.64.0.0/10
302```
303
304## Proxy Origin IP Allowlist
305
306The `proxy_allowed_ips` setting restricts which IPs can reach the proxy server. This prevents direct-to-origin attacks that bypass CDN protections (e.g. Cloudflare WAF, DDoS mitigation). When set, only connections from listed CIDRs (plus localhost) are accepted.
307
308```toml
309[server]
310# Only accept proxy traffic from Cloudflare edge IPs
311proxy_allowed_ips = [
312  "173.245.48.0/20", "103.21.244.0/22", "103.22.200.0/22",
313  "103.31.4.0/22", "141.101.64.0/18", "108.162.192.0/18",
314  "190.93.240.0/20", "188.114.96.0/20", "197.234.240.0/22",
315  "198.41.128.0/17", "162.158.0.0/15", "104.16.0.0/13",
316  "104.24.0.0/14", "172.64.0.0/13", "131.0.72.0/22",
317]
318```
319
320**Behavior:**
321- Checks the direct connection IP (`RemoteAddr`), not `X-Forwarded-For`
322- Localhost is always allowed
323- Denied requests receive `403 Forbidden`
324- An empty list allows all traffic (default)
325
326**Important:** Cloudflare publishes their IP ranges at [cloudflare.com/ips](https://www.cloudflare.com/ips/). Keep your allowlist updated when Cloudflare adds new ranges.
327
328## Registry Listen Address
329
330The `registry_listen_address` controls which interface the registry server binds to. By default it binds to all interfaces. Set to `127.0.0.1` to restrict registry access to localhost only, preventing containers from reaching the registry via the Docker bridge gateway.
331
332```toml
333[server]
334registry_listen_address = "127.0.0.1"  # Loopback only
335```
336
337## HSTS
338
339HSTS headers are sent automatically on the HTTPS listener (when `r.TLS != nil`). When Gordon runs behind a TLS-terminating proxy (Cloudflare, Tailscale) and only receives plain HTTP, HSTS is not sent — the edge proxy is expected to handle it.
340
341## Examples
342
343### Development Configuration
344
345```toml
346[server]
347port = 8080
348registry_port = 5000
349gordon_domain = "gordon.local"
350data_dir = "./dev-data"
351```
352
353### Production Configuration
354
355```toml
356[server]
357port = 8080
358registry_port = 5000
359gordon_domain = "gordon.company.com"
360data_dir = "/var/lib/gordon"
361```
362
363### Rootless Container Setup
364
365```toml
366[server]
367port = 8080      # High port for rootless
368registry_port = 5000
369gordon_domain = "gordon.mydomain.com"
370```
371
372With firewall port forwarding:
373```bash
374sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
375sudo firewall-cmd --reload
376```
377
378## Related
379
380- [Configuration Overview](./index.md)
381- [Installation Guide](../installation.md)
382- [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