v3.0.0 f19f453

installation.md RawHistoryFolder

Installation

Detailed installation guide for production environments.

System Requirements

  • OS: Linux (Ubuntu 24.04 LTS, Debian 13 recommended) or macOS
  • Architecture: x86_64 (amd64) or ARM64
  • Memory: 512MB minimum, 1GB recommended
  • Disk: 10GB minimum for registry storage
  • Runtime: Docker or Podman with a Docker-compatible API version 1.40 or later

Download Gordon

(
  set -euo pipefail
  installer="$(mktemp)"
  trap 'rm -f "$installer"' EXIT
  curl -fsSL --output "$installer" https://bnema.dev/gordon/install
  if command -v less >/dev/null 2>&1; then
    less "$installer"
  else
    cat "$installer"
  fi
  bash "$installer"
)

Download and inspect the installer before executing it. The installer verifies the release archive checksum, detects Linux/macOS and amd64/arm64, and installs Gordon to ~/.local/bin without sudo. If that directory is absent from PATH, an interactive install can offer to add an idempotent marker block to Fish (~/.config/fish/config.fish), Bash (~/.bashrc), or Zsh (~/.zshrc). Restart the shell after accepting, or follow the printed command to update the current shell.

For unattended installs, control PATH configuration explicitly:

# Update supported shell configuration without prompting
curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=1 sh

# Never modify shell configuration
curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=0 sh

# Use another user-local directory
curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh

# Explicit global installation (may request sudo)
curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh

GORDON_INSTALL_DIR accepts arbitrary safe absolute destinations, including "$HOME/bin", "$HOME/.local/bin", and /usr/local/bin. PATH detection and shell configuration use that effective directory. Relative paths, PATH separators, and control characters are rejected. GORDON_UPDATE_PATH accepts only 0 or 1. Do not run the default installer through sudo: it refuses to infer a user home and install silently under /root.

Manual Installation

Manual archive installation requires downloading the matching checksums.txt release asset and verifying the archive's SHA-256 checksum before extraction. The checksum-verifying installer above is recommended.

Linux (x86_64)

wget https://github.com/bnema/gordon/releases/latest/download/{gordon_linux_amd64.tar.gz,checksums.txt}
grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_linux_amd64\.tar\.gz$' checksums.txt | sha256sum --check --strict
tar -xzf gordon_linux_amd64.tar.gz
chmod +x gordon
sudo mv gordon /usr/local/bin/

Linux (ARM64) - for Raspberry Pi 4, AWS Graviton, Oracle Ampere, etc.

wget https://github.com/bnema/gordon/releases/latest/download/{gordon_linux_arm64.tar.gz,checksums.txt}
grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_linux_arm64\.tar\.gz$' checksums.txt | sha256sum --check --strict
tar -xzf gordon_linux_arm64.tar.gz
chmod +x gordon
sudo mv gordon /usr/local/bin/

macOS (Apple Silicon)

curl -LO https://github.com/bnema/gordon/releases/latest/download/{gordon_darwin_arm64.tar.gz,checksums.txt}
grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_darwin_arm64\.tar\.gz$' checksums.txt | shasum -a 256 --check
tar -xzf gordon_darwin_arm64.tar.gz
chmod +x gordon
sudo mv gordon /usr/local/bin/

macOS (Intel)

curl -LO https://github.com/bnema/gordon/releases/latest/download/{gordon_darwin_amd64.tar.gz,checksums.txt}
grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_darwin_amd64\.tar\.gz$' checksums.txt | shasum -a 256 --check
tar -xzf gordon_darwin_amd64.tar.gz
chmod +x gordon
sudo mv gordon /usr/local/bin/

Verify installation:

gordon version

From Source

# Requires Go 1.21+
git clone https://github.com/bnema/gordon.git
cd gordon
make build
sudo mv gordon /usr/local/bin/

Container Runtime Setup

Docker

# Install Docker from your distribution's signed package repository.
sudo apt update
sudo apt install docker.io

# Add user to docker group
sudo usermod -aG docker $USER
newgrp docker

# Verify
docker run hello-world

Podman (Rootless)

Podman rootless mode provides enhanced security by running containers without root privileges.

# Install Podman
sudo apt update
sudo apt install -y podman

# Enable user namespaces
echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Setup subuid/subgid
sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER

# Enable Podman socket
systemctl --user enable --now podman.socket

# Configure insecure localhost registry (required — Podman blocks HTTP registries by default)
mkdir -p ~/.config/containers/registries.conf.d
cat > ~/.config/containers/registries.conf.d/gordon.conf <<EOF
[[registry]]
location = "localhost:5000"
insecure = true
EOF

Podman assigns loopback backend ports from the host's ephemeral port range when Gordon publishes managed service ports. If an nftables output policy restricts loopback access, allow the Gordon daemon's primary UID—not its subordinate container UIDs—to connect to that range for the protocols used by managed services:

# Confirm the range with: sysctl net.ipv4.ip_local_port_range
meta skuid <gordon-uid> ip daddr 127.0.0.1 tcp dport 32768-60999 accept
meta skuid <gordon-uid> ip daddr 127.0.0.1 udp dport 32768-60999 accept

Place these rules before any broader loopback rejection. Keep public entrypoint and administrative-port policy separate; these rules only let Gordon reach rootless Podman backends on the local host.

Firewall Configuration

Gordon needs ports accessible for the registry and the public edge entrypoint.

Using firewalld

# Install and enable firewalld
sudo apt install -y firewalld
sudo systemctl enable --now firewalld

# Allow HTTP/HTTPS
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https

# For rootless services, bind entrypoints.edge.address to a high port (for example :9000)
# and redirect the external TCP edge ports your deployment uses.
sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=9000
sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=9000

# Apply changes
sudo firewall-cmd --reload

# Verify
sudo firewall-cmd --list-all

Using ufw

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw allow 5000/tcp  # Registry port (if accessing directly)
sudo ufw enable

Configuration

Gordon creates a default configuration on first run:

# Run once to generate config, then stop
gordon serve
# Press Ctrl+C

# Edit configuration
nano ~/.config/gordon/gordon.toml

Minimum required configuration:

[server]
registry_port = 5000
gordon_domain = "gordon.yourdomain.com"

[entrypoints.edge]
address = ":443"
protocol = "smart_tcp"

Application workloads live in standalone app files, not in gordon.toml (see Getting Started).

See Configuration Reference for all options.

Systemd Service

mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/gordon.service <<EOF
[Unit]
Description=Gordon Container Platform
After=podman.socket

[Service]
Type=simple
Restart=always
RestartSec=5
# Required for Podman rootless — tells Gordon where to find the Podman socket
Environment=XDG_RUNTIME_DIR=/run/user/%U
Environment=DOCKER_HOST=unix:///run/user/%U/podman/podman.sock
ExecStart=/usr/local/bin/gordon serve

[Install]
WantedBy=default.target
EOF

> **Docker users:** Omit the two `Environment=` lines above — Docker's socket path is set automatically.

# Enable and start
systemctl --user daemon-reload
systemctl --user enable --now gordon

# Enable linger (keep service running after logout)
sudo loginctl enable-linger $USER

# Check status
systemctl --user status gordon

System Service (Root Mode)

sudo cat > /etc/systemd/system/gordon.service <<EOF
[Unit]
Description=Gordon Container Platform
After=docker.service
Requires=docker.service

[Service]
Type=simple
Restart=always
RestartSec=5
ExecStart=/usr/local/bin/gordon serve
User=root

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now gordon

DNS Configuration

Point your domains to your server:

Type Name Content Proxy
A app SERVER_IP Yes (Cloudflare)
A registry SERVER_IP Yes (Cloudflare)

Note: Enable Cloudflare proxy (orange cloud) for automatic HTTPS. Gordon receives HTTP traffic from Cloudflare.

Cloudflare SSL Mode

Gordon serves public application traffic through HTTP-capable entrypoints such as entrypoints.edge with protocol = "smart_tcp". Choose the Cloudflare mode that matches how you want Cloudflare to reach your origin.

Mode How it works Use when
Flexible Cloudflare terminates TLS; connects to Gordon with cleartext HTTP You want edge HTTPS only
Full (Strict) Cloudflare connects to Gordon over HTTPS with a valid cert You want end-to-end HTTPS using Gordon's public ACME certs or a static cert (tls_cert_file / tls_key_file)

Wrong mode causes: 521 (Cloudflare can't connect) or 525 (TLS handshake failed).

Important: For Cloudflare-proxied HTTP paths, set proxy_allowed_ips with Cloudflare edge IPs — see Proxy Origin Allowlist below.

Rootless note: Unprivileged users can't bind privileged ports. Bind entrypoints.edge.address to a high port (for example :9000) and forward/map external ports to it via firewall or container settings.

Proxy Origin Allowlist

When Gordon serves HTTP paths through a smart TCP edge, direct non-localhost HTTP requests can be restricted to certificate onboarding paths. Cloudflare and other reverse proxies must be listed in proxy_allowed_ips to reach your applications.

Add Cloudflare edge IPs to your gordon.toml:

[server]
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",
]

Without this setting, Cloudflare traffic receives 403 Forbidden: Only certificate onboarding is available over HTTP.

Note: This is separate from [api.rate_limit] trusted_proxies, which controls IP extraction from X-Forwarded-For. Both should list your proxy IPs. See Proxy Origin IP Allowlist for details.

Choosing an Install Channel

# Install an exact release
curl -fsSL https://bnema.dev/gordon/install | GORDON_VERSION=v2.30.1 sh

# Install the latest pre-release
curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh

# Build the current next branch commit from source
curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh

Stable, exact-version, and pre-release installs download release binaries and verify their published checksums. The next channel is an unverified development source build: it resolves the branch through the GitHub API, pins the resulting commit SHA, downloads that exact source snapshot, and builds it locally for the detected platform. It requires the Go version declared by that commit's go.mod, is not covered by release checksums, and may be unstable. Do not combine GORDON_CHANNEL=next with GORDON_VERSION or GORDON_PRERELEASE.

Verify Installation

# Check Gordon is running
systemctl --user status gordon

# View logs
journalctl --user -u gordon -f

# Test registry (from local machine)
docker login registry.yourdomain.com
docker pull alpine
docker tag alpine registry.yourdomain.com/test:latest
docker push registry.yourdomain.com/test:latest

Data Directories

Gordon stores data in the following locations:

Path Purpose
~/.config/gordon/gordon.toml Configuration file
~/.gordon/ Default data directory
~/.gordon/registry/ Container images
~/.gordon/logs/ Application logs
~/.gordon/secrets/ Secrets (unsafe backend only)
source
1# Installation
2
3Detailed installation guide for production environments.
4
5## System Requirements
6
7- **OS**: Linux (Ubuntu 24.04 LTS, Debian 13 recommended) or macOS
8- **Architecture**: x86_64 (amd64) or ARM64
9- **Memory**: 512MB minimum, 1GB recommended
10- **Disk**: 10GB minimum for registry storage
11- **Runtime**: Docker or Podman with a Docker-compatible API version 1.40 or later
12
13## Download Gordon
14
15### Quick Install (Recommended)
16
17```bash
18(
19  set -euo pipefail
20  installer="$(mktemp)"
21  trap 'rm -f "$installer"' EXIT
22  curl -fsSL --output "$installer" https://bnema.dev/gordon/install
23  if command -v less >/dev/null 2>&1; then
24    less "$installer"
25  else
26    cat "$installer"
27  fi
28  bash "$installer"
29)
30```
31
32Download and inspect the installer before executing it. The installer verifies the release archive checksum, detects Linux/macOS and amd64/arm64, and installs Gordon to `~/.local/bin` without `sudo`. If that directory is absent from `PATH`, an interactive install can offer to add an idempotent marker block to Fish (`~/.config/fish/config.fish`), Bash (`~/.bashrc`), or Zsh (`~/.zshrc`). Restart the shell after accepting, or follow the printed command to update the current shell.
33
34For unattended installs, control PATH configuration explicitly:
35
36```bash
37# Update supported shell configuration without prompting
38curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=1 sh
39
40# Never modify shell configuration
41curl -fsSL https://bnema.dev/gordon/install | GORDON_UPDATE_PATH=0 sh
42
43# Use another user-local directory
44curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR="$HOME/bin" GORDON_UPDATE_PATH=1 sh
45
46# Explicit global installation (may request sudo)
47curl -fsSL https://bnema.dev/gordon/install | GORDON_INSTALL_DIR=/usr/local/bin GORDON_UPDATE_PATH=0 sh
48```
49
50`GORDON_INSTALL_DIR` accepts arbitrary safe absolute destinations, including `"$HOME/bin"`, `"$HOME/.local/bin"`, and `/usr/local/bin`. PATH detection and shell configuration use that effective directory. Relative paths, PATH separators, and control characters are rejected. `GORDON_UPDATE_PATH` accepts only `0` or `1`. Do not run the default installer through `sudo`: it refuses to infer a user home and install silently under `/root`.
51
52### Manual Installation
53
54Manual archive installation requires downloading the matching `checksums.txt` release asset and verifying the archive's SHA-256 checksum before extraction. The checksum-verifying installer above is recommended.
55
56**Linux (x86_64)**
57
58```bash
59wget https://github.com/bnema/gordon/releases/latest/download/{gordon_linux_amd64.tar.gz,checksums.txt}
60grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_linux_amd64\.tar\.gz$' checksums.txt | sha256sum --check --strict
61tar -xzf gordon_linux_amd64.tar.gz
62chmod +x gordon
63sudo mv gordon /usr/local/bin/
64```
65
66**Linux (ARM64)** - for Raspberry Pi 4, AWS Graviton, Oracle Ampere, etc.
67
68```bash
69wget https://github.com/bnema/gordon/releases/latest/download/{gordon_linux_arm64.tar.gz,checksums.txt}
70grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_linux_arm64\.tar\.gz$' checksums.txt | sha256sum --check --strict
71tar -xzf gordon_linux_arm64.tar.gz
72chmod +x gordon
73sudo mv gordon /usr/local/bin/
74```
75
76**macOS (Apple Silicon)**
77
78```bash
79curl -LO https://github.com/bnema/gordon/releases/latest/download/{gordon_darwin_arm64.tar.gz,checksums.txt}
80grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_darwin_arm64\.tar\.gz$' checksums.txt | shasum -a 256 --check
81tar -xzf gordon_darwin_arm64.tar.gz
82chmod +x gordon
83sudo mv gordon /usr/local/bin/
84```
85
86**macOS (Intel)**
87
88```bash
89curl -LO https://github.com/bnema/gordon/releases/latest/download/{gordon_darwin_amd64.tar.gz,checksums.txt}
90grep -E '^[[:xdigit:]]{64} ([* ]?)gordon_darwin_amd64\.tar\.gz$' checksums.txt | shasum -a 256 --check
91tar -xzf gordon_darwin_amd64.tar.gz
92chmod +x gordon
93sudo mv gordon /usr/local/bin/
94```
95
96Verify installation:
97
98```bash
99gordon version
100```
101
102### From Source
103
104```bash
105# Requires Go 1.21+
106git clone https://github.com/bnema/gordon.git
107cd gordon
108make build
109sudo mv gordon /usr/local/bin/
110```
111
112## Container Runtime Setup
113
114### Docker
115
116```bash
117# Install Docker from your distribution's signed package repository.
118sudo apt update
119sudo apt install docker.io
120
121# Add user to docker group
122sudo usermod -aG docker $USER
123newgrp docker
124
125# Verify
126docker run hello-world
127```
128
129### Podman (Rootless)
130
131Podman rootless mode provides enhanced security by running containers without root privileges.
132
133```bash
134# Install Podman
135sudo apt update
136sudo apt install -y podman
137
138# Enable user namespaces
139echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.conf
140sudo sysctl -p
141
142# Setup subuid/subgid
143sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
144
145# Enable Podman socket
146systemctl --user enable --now podman.socket
147
148# Configure insecure localhost registry (required — Podman blocks HTTP registries by default)
149mkdir -p ~/.config/containers/registries.conf.d
150cat > ~/.config/containers/registries.conf.d/gordon.conf <<EOF
151[[registry]]
152location = "localhost:5000"
153insecure = true
154EOF
155```
156
157Podman assigns loopback backend ports from the host's ephemeral port range when Gordon publishes managed service ports. If an nftables output policy restricts loopback access, allow the Gordon daemon's primary UID—not its subordinate container UIDs—to connect to that range for the protocols used by managed services:
158
159```nftables
160# Confirm the range with: sysctl net.ipv4.ip_local_port_range
161meta skuid <gordon-uid> ip daddr 127.0.0.1 tcp dport 32768-60999 accept
162meta skuid <gordon-uid> ip daddr 127.0.0.1 udp dport 32768-60999 accept
163```
164
165Place these rules before any broader loopback rejection. Keep public entrypoint and administrative-port policy separate; these rules only let Gordon reach rootless Podman backends on the local host.
166
167## Firewall Configuration
168
169Gordon needs ports accessible for the registry and the public edge entrypoint.
170
171### Using firewalld
172
173```bash
174# Install and enable firewalld
175sudo apt install -y firewalld
176sudo systemctl enable --now firewalld
177
178# Allow HTTP/HTTPS
179sudo firewall-cmd --permanent --add-service=http
180sudo firewall-cmd --permanent --add-service=https
181
182# For rootless services, bind entrypoints.edge.address to a high port (for example :9000)
183# and redirect the external TCP edge ports your deployment uses.
184sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=9000
185sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=9000
186
187# Apply changes
188sudo firewall-cmd --reload
189
190# Verify
191sudo firewall-cmd --list-all
192```
193
194### Using ufw
195
196```bash
197sudo ufw allow 80/tcp
198sudo ufw allow 443/tcp
199sudo ufw allow 5000/tcp  # Registry port (if accessing directly)
200sudo ufw enable
201```
202
203## Configuration
204
205Gordon creates a default configuration on first run:
206
207```bash
208# Run once to generate config, then stop
209gordon serve
210# Press Ctrl+C
211
212# Edit configuration
213nano ~/.config/gordon/gordon.toml
214```
215
216Minimum required configuration:
217
218```toml
219[server]
220registry_port = 5000
221gordon_domain = "gordon.yourdomain.com"
222
223[entrypoints.edge]
224address = ":443"
225protocol = "smart_tcp"
226```
227
228Application workloads live in standalone app files, not in `gordon.toml` (see [Getting Started](./getting-started.md#8-deploy-your-first-app)).
229
230See [Configuration Reference](./config/index.md) for all options.
231
232## Systemd Service
233
234### User Service (Recommended for Rootless)
235
236```bash
237mkdir -p ~/.config/systemd/user
238cat > ~/.config/systemd/user/gordon.service <<EOF
239[Unit]
240Description=Gordon Container Platform
241After=podman.socket
242
243[Service]
244Type=simple
245Restart=always
246RestartSec=5
247# Required for Podman rootless — tells Gordon where to find the Podman socket
248Environment=XDG_RUNTIME_DIR=/run/user/%U
249Environment=DOCKER_HOST=unix:///run/user/%U/podman/podman.sock
250ExecStart=/usr/local/bin/gordon serve
251
252[Install]
253WantedBy=default.target
254EOF
255
256> **Docker users:** Omit the two `Environment=` lines above — Docker's socket path is set automatically.
257
258# Enable and start
259systemctl --user daemon-reload
260systemctl --user enable --now gordon
261
262# Enable linger (keep service running after logout)
263sudo loginctl enable-linger $USER
264
265# Check status
266systemctl --user status gordon
267```
268
269### System Service (Root Mode)
270
271```bash
272sudo cat > /etc/systemd/system/gordon.service <<EOF
273[Unit]
274Description=Gordon Container Platform
275After=docker.service
276Requires=docker.service
277
278[Service]
279Type=simple
280Restart=always
281RestartSec=5
282ExecStart=/usr/local/bin/gordon serve
283User=root
284
285[Install]
286WantedBy=multi-user.target
287EOF
288
289sudo systemctl daemon-reload
290sudo systemctl enable --now gordon
291```
292
293## DNS Configuration
294
295Point your domains to your server:
296
297| Type | Name | Content | Proxy |
298|------|------|---------|-------|
299| A | `app` | `SERVER_IP` | Yes (Cloudflare) |
300| A | `registry` | `SERVER_IP` | Yes (Cloudflare) |
301
302> **Note:** Enable Cloudflare proxy (orange cloud) for automatic HTTPS. Gordon receives HTTP traffic from Cloudflare.
303
304## Cloudflare SSL Mode
305
306Gordon serves public application traffic through HTTP-capable entrypoints such as `entrypoints.edge` with `protocol = "smart_tcp"`. Choose the Cloudflare mode that matches how you want Cloudflare to reach your origin.
307
308| Mode | How it works | Use when |
309|------|-------------|----------|
310| **Flexible** | Cloudflare terminates TLS; connects to Gordon with cleartext HTTP | You want edge HTTPS only |
311| **Full (Strict)** | Cloudflare connects to Gordon over HTTPS with a valid cert | You want end-to-end HTTPS using Gordon's public ACME certs or a static cert (`tls_cert_file` / `tls_key_file`) |
312
313Wrong mode causes: **521** (Cloudflare can't connect) or **525** (TLS handshake failed).
314
315> **Important:** For Cloudflare-proxied HTTP paths, set `proxy_allowed_ips` with Cloudflare edge IPs — see [Proxy Origin Allowlist](#proxy-origin-allowlist) below.
316>
317> **Rootless note:** Unprivileged users can't bind privileged ports. Bind `entrypoints.edge.address` to a high port (for example `:9000`) and forward/map external ports to it via firewall or container settings.
318
319## Proxy Origin Allowlist
320
321When Gordon serves HTTP paths through a smart TCP edge, direct non-localhost HTTP requests can be restricted to certificate onboarding paths. Cloudflare and other reverse proxies must be listed in `proxy_allowed_ips` to reach your applications.
322
323Add Cloudflare edge IPs to your `gordon.toml`:
324
325```toml
326[server]
327proxy_allowed_ips = [
328  "173.245.48.0/20", "103.21.244.0/22", "103.22.200.0/22",
329  "103.31.4.0/22", "141.101.64.0/18", "108.162.192.0/18",
330  "190.93.240.0/20", "188.114.96.0/20", "197.234.240.0/22",
331  "198.41.128.0/17", "162.158.0.0/15", "104.16.0.0/13",
332  "104.24.0.0/14", "172.64.0.0/13", "131.0.72.0/22",
333]
334```
335
336Without this setting, Cloudflare traffic receives `403 Forbidden: Only certificate onboarding is available over HTTP`.
337
338> **Note:** This is separate from `[api.rate_limit] trusted_proxies`, which controls IP extraction from `X-Forwarded-For`. Both should list your proxy IPs. See [Proxy Origin IP Allowlist](./config/server.md#proxy-origin-ip-allowlist) for details.
339
340## Choosing an Install Channel
341
342```bash
343# Install an exact release
344curl -fsSL https://bnema.dev/gordon/install | GORDON_VERSION=v2.30.1 sh
345
346# Install the latest pre-release
347curl -fsSL https://bnema.dev/gordon/install | GORDON_PRERELEASE=1 sh
348
349# Build the current next branch commit from source
350curl -fsSL https://bnema.dev/gordon/install | GORDON_CHANNEL=next sh
351```
352
353Stable, exact-version, and pre-release installs download release binaries and verify their published checksums. The `next` channel is an **unverified development source build**: it resolves the branch through the GitHub API, pins the resulting commit SHA, downloads that exact source snapshot, and builds it locally for the detected platform. It requires the Go version declared by that commit's `go.mod`, is not covered by release checksums, and may be unstable. Do not combine `GORDON_CHANNEL=next` with `GORDON_VERSION` or `GORDON_PRERELEASE`.
354
355## Verify Installation
356
357```bash
358# Check Gordon is running
359systemctl --user status gordon
360
361# View logs
362journalctl --user -u gordon -f
363
364# Test registry (from local machine)
365docker login registry.yourdomain.com
366docker pull alpine
367docker tag alpine registry.yourdomain.com/test:latest
368docker push registry.yourdomain.com/test:latest
369```
370
371## Data Directories
372
373Gordon stores data in the following locations:
374
375| Path | Purpose |
376|------|---------|
377| `~/.config/gordon/gordon.toml` | Configuration file |
378| `~/.gordon/` | Default data directory |
379| `~/.gordon/registry/` | Container images |
380| `~/.gordon/logs/` | Application logs |
381| `~/.gordon/secrets/` | Secrets (unsafe backend only) |
382
383## Related
384
385- [Getting Started](./getting-started.md)
386- [Configuration Reference](./config/index.md)
387- [Podman Rootless Setup](/wiki/guides/podman-rootless.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