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).
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
- Docker/Podman may send a full layer in one request, so set this high enough for your base images
- Default (
95MB) is compatible with Cloudflare and most CDN proxies; increase if pushing very large layers directly
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
130> **Note:** `registry_domain` is supported as a deprecated alias for backwards compatibility.
131
132## Data Directory
133
134The `data_dir` setting controls where Gordon stores data:
135
136```toml
137[server]
138data_dir = "~/.gordon" # Default for user installations
139```
140
141### Directory Structure
142
143```
144~/.gordon/
145├── registry/ # Container images and manifests
146│ ├── blobs/
147│ └── manifests/
148├── env/ # Environment files per domain
149│ ├── app_mydomain_com.env
150│ └── api_mydomain_com.env
151├── logs/ # Application and container logs
152│ ├── gordon.log
153│ ├── proxy.log
154│ └── containers/
155└── secrets/ # Secrets (unsafe backend only)
156```
157
158### Permissions
159
160 Gordon creates directories with secure permissions:
161 - Directories: `0700` (owner only)
162 - Files: `0600` (owner only)
163
164 ## Maximum Proxy Body Size
165
166 The `max_proxy_body_size` setting limits the size of request bodies that Gordon will forward to backend containers:
167
168 ```toml
169 [server]
170 max_proxy_body_size = "512MB" # Default
171 ```
172
173 **Purpose:** Prevents resource exhaustion attacks from extremely large uploads through the proxy.
174
175 **Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
176
177 **Examples:**
178 ```toml
179 max_proxy_body_size = "100MB" # Stricter limit
180 max_proxy_body_size = "1GB" # Allow larger uploads
181 max_proxy_body_size = "0" # No limit (not recommended)
182 ```
183
184 **Behavior:**
185 - When a request exceeds the limit, Gordon returns `413 Request Entity Too Large`
186 - The limit is applied before the request reaches the backend container
187 - Uploads in progress are terminated when the limit is exceeded
188
189 **Use cases:**
190 - File upload services: increase to `1GB` or higher
191 - CI/CD artifact uploads: adjust based on your largest artifacts
192 - Tight security: reduce to `100MB` or lower
193 - Default (512MB): suitable for most applications
194
195 > **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.
196
197## Maximum Registry Blob Chunk Size
198
199The `max_blob_chunk_size` setting limits the size of a single blob upload request to the registry (`PATCH`/`PUT` under `/v2/*/blobs/uploads/*`):
200
201```toml
202[server]
203max_blob_chunk_size = "95MB" # Default
204```
205
206**Purpose:** Prevents excessive memory usage during blob uploads while allowing large real-world image layers.
207
208**Supported units:** B, KB, MB, GB, TB (case-insensitive, decimal/1024-based)
209
210**Examples:**
211
212```toml
213max_blob_chunk_size = "256MB" # Stricter limit
214max_blob_chunk_size = "1GB" # Allow larger layers
215```
216
217**Behavior:**
218- When a blob chunk exceeds the limit, Gordon returns `413 Request Entity Too Large`
219- Docker/Podman may send a full layer in one request, so set this high enough for your base images
220- Default (`95MB`) is compatible with Cloudflare and most CDN proxies; increase if pushing very large layers directly
221
222## Registry IP Allowlist
223
224The `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).
225
226```toml
227[server]
228registry_allowed_ips = [
229 "100.64.0.0/10", # Tailscale CGNAT range
230 "203.0.113.50", # single IP (treated as /32)
231]
232```
233
234**Behavior:**
235- Single IPs are automatically converted to `/32` (IPv4) or `/128` (IPv6)
236- Denied requests receive `403 Forbidden`
237- Localhost (`127.0.0.0/8`, `::1`) is always allowed so Gordon can pull from its own registry
238- Respects `trusted_proxies` for accurate client IP extraction behind reverse proxies
239- Applied before rate limiting and authentication
240- Changes require a Gordon server restart; not picked up by config hot-reload
241
242**Use cases:**
243- Restrict registry to Tailscale network: `["100.64.0.0/10"]`
244- Restrict to private subnets: `["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]`
245- Allow a specific CI server: `["100.64.0.0/10", "203.0.113.50"]`
246
247Via environment variable:
248
249```bash
250GORDON_SERVER_REGISTRY_ALLOWED_IPS=100.64.0.0/10
251```
252
253## Examples
254
255### Development Configuration
256
257```toml
258[server]
259port = 8080
260registry_port = 5000
261gordon_domain = "gordon.local"
262data_dir = "./dev-data"
263```
264
265### Production Configuration
266
267```toml
268[server]
269port = 8080
270registry_port = 5000
271gordon_domain = "gordon.company.com"
272data_dir = "/var/lib/gordon"
273```
274
275### Rootless Container Setup
276
277```toml
278[server]
279port = 8080 # High port for rootless
280registry_port = 5000
281gordon_domain = "gordon.mydomain.com"
282```
283
284With firewall port forwarding:
285```bash
286sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8080
287sudo firewall-cmd --reload
288```
289
290## Related
291
292- [Configuration Overview](./index.md)
293- [Installation Guide](../installation.md)
294- [Routes Configuration](./routes.md)