v2.31.0-dev13 0d280f4

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

Download Gordon

curl -fsSL https://gordon.bnema.dev/install | bash

This script automatically detects your OS (Linux/macOS) and architecture (amd64/arm64), downloads the appropriate binary from GitHub releases, and installs it to /usr/local/bin.

Manual Installation

Linux (x86_64)

wget https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64.tar.gz
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
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
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
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
curl -fsSL https://get.docker.com | sh

# 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

Firewall Configuration

Gordon needs ports accessible for the registry and proxy.

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 containers, redirect privileged ports
sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8088
sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443

# 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]
port = 8088
registry_port = 5000
gordon_domain = "gordon.yourdomain.com"

[routes]
"app.yourdomain.com" = "myapp:latest"

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 HTTP by default. Cloudflare must connect to your origin over HTTP unless you explicitly enable TLS.

Mode How it works Use when
Flexible Cloudflare terminates TLS; connects to Gordon on HTTP Gordon has no TLS cert (default setup)
Full (Strict) Cloudflare connects to Gordon over HTTPS with a valid cert Set server.tls_port (default 8443) and provide a Cloudflare Origin CA cert via server.tls_cert_file and server.tls_key_file

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

Important: You must also set proxy_allowed_ips with Cloudflare edge IPs — see Proxy Origin Allowlist below.

Rootless note: Unprivileged users can't bind port 80. Forward port 80→8088 (or your configured port) via firewall — see the firewall section above.

Proxy Origin Allowlist

When Gordon's internal CA is enabled (default: tls_port = 8443), HTTP requests from non-localhost IPs are restricted to certificate onboarding paths only. 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.

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/env/ Environment files
~/.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
12
13## Download Gordon
14
15### Quick Install (Recommended)
16
17```bash
18curl -fsSL https://gordon.bnema.dev/install | bash
19```
20
21This script automatically detects your OS (Linux/macOS) and architecture (amd64/arm64), downloads the appropriate binary from GitHub releases, and installs it to `/usr/local/bin`.
22
23### Manual Installation
24
25**Linux (x86_64)**
26```bash
27wget https://github.com/bnema/gordon/releases/latest/download/gordon_linux_amd64.tar.gz
28tar -xzf gordon_linux_amd64.tar.gz
29chmod +x gordon
30sudo mv gordon /usr/local/bin/
31```
32
33**Linux (ARM64)** - for Raspberry Pi 4, AWS Graviton, Oracle Ampere, etc.
34```bash
35wget https://github.com/bnema/gordon/releases/latest/download/gordon_linux_arm64.tar.gz
36tar -xzf gordon_linux_arm64.tar.gz
37chmod +x gordon
38sudo mv gordon /usr/local/bin/
39```
40
41**macOS (Apple Silicon)**
42```bash
43curl -LO https://github.com/bnema/gordon/releases/latest/download/gordon_darwin_arm64.tar.gz
44tar -xzf gordon_darwin_arm64.tar.gz
45chmod +x gordon
46sudo mv gordon /usr/local/bin/
47```
48
49**macOS (Intel)**
50```bash
51curl -LO https://github.com/bnema/gordon/releases/latest/download/gordon_darwin_amd64.tar.gz
52tar -xzf gordon_darwin_amd64.tar.gz
53chmod +x gordon
54sudo mv gordon /usr/local/bin/
55```
56
57Verify installation:
58```bash
59gordon version
60```
61
62### From Source
63
64```bash
65# Requires Go 1.21+
66git clone https://github.com/bnema/gordon.git
67cd gordon
68make build
69sudo mv gordon /usr/local/bin/
70```
71
72## Container Runtime Setup
73
74### Docker
75
76```bash
77# Install Docker
78curl -fsSL https://get.docker.com | sh
79
80# Add user to docker group
81sudo usermod -aG docker $USER
82newgrp docker
83
84# Verify
85docker run hello-world
86```
87
88### Podman (Rootless)
89
90Podman rootless mode provides enhanced security by running containers without root privileges.
91
92```bash
93# Install Podman
94sudo apt update
95sudo apt install -y podman
96
97# Enable user namespaces
98echo 'user.max_user_namespaces=28633' | sudo tee -a /etc/sysctl.conf
99sudo sysctl -p
100
101# Setup subuid/subgid
102sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER
103
104# Enable Podman socket
105systemctl --user enable --now podman.socket
106
107# Configure insecure localhost registry (required — Podman blocks HTTP registries by default)
108mkdir -p ~/.config/containers/registries.conf.d
109cat > ~/.config/containers/registries.conf.d/gordon.conf <<EOF
110[[registry]]
111location = "localhost:5000"
112insecure = true
113EOF
114```
115
116## Firewall Configuration
117
118Gordon needs ports accessible for the registry and proxy.
119
120### Using firewalld
121
122```bash
123# Install and enable firewalld
124sudo apt install -y firewalld
125sudo systemctl enable --now firewalld
126
127# Allow HTTP/HTTPS
128sudo firewall-cmd --permanent --add-service=http
129sudo firewall-cmd --permanent --add-service=https
130
131# For rootless containers, redirect privileged ports
132sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=8088
133sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=8443
134
135# Apply changes
136sudo firewall-cmd --reload
137
138# Verify
139sudo firewall-cmd --list-all
140```
141
142### Using ufw
143
144```bash
145sudo ufw allow 80/tcp
146sudo ufw allow 443/tcp
147sudo ufw allow 5000/tcp  # Registry port (if accessing directly)
148sudo ufw enable
149```
150
151## Configuration
152
153Gordon creates a default configuration on first run:
154
155```bash
156# Run once to generate config, then stop
157gordon serve
158# Press Ctrl+C
159
160# Edit configuration
161nano ~/.config/gordon/gordon.toml
162```
163
164Minimum required configuration:
165
166```toml
167[server]
168port = 8088
169registry_port = 5000
170gordon_domain = "gordon.yourdomain.com"
171
172[routes]
173"app.yourdomain.com" = "myapp:latest"
174```
175
176See [Configuration Reference](./config/index.md) for all options.
177
178## Systemd Service
179
180### User Service (Recommended for Rootless)
181
182```bash
183mkdir -p ~/.config/systemd/user
184cat > ~/.config/systemd/user/gordon.service <<EOF
185[Unit]
186Description=Gordon Container Platform
187After=podman.socket
188
189[Service]
190Type=simple
191Restart=always
192RestartSec=5
193# Required for Podman rootless — tells Gordon where to find the Podman socket
194Environment=XDG_RUNTIME_DIR=/run/user/%U
195Environment=DOCKER_HOST=unix:///run/user/%U/podman/podman.sock
196ExecStart=/usr/local/bin/gordon serve
197
198[Install]
199WantedBy=default.target
200EOF
201
202> **Docker users:** Omit the two `Environment=` lines above — Docker's socket path is set automatically.
203
204# Enable and start
205systemctl --user daemon-reload
206systemctl --user enable --now gordon
207
208# Enable linger (keep service running after logout)
209sudo loginctl enable-linger $USER
210
211# Check status
212systemctl --user status gordon
213```
214
215### System Service (Root Mode)
216
217```bash
218sudo cat > /etc/systemd/system/gordon.service <<EOF
219[Unit]
220Description=Gordon Container Platform
221After=docker.service
222Requires=docker.service
223
224[Service]
225Type=simple
226Restart=always
227RestartSec=5
228ExecStart=/usr/local/bin/gordon serve
229User=root
230
231[Install]
232WantedBy=multi-user.target
233EOF
234
235sudo systemctl daemon-reload
236sudo systemctl enable --now gordon
237```
238
239## DNS Configuration
240
241Point your domains to your server:
242
243| Type | Name | Content | Proxy |
244|------|------|---------|-------|
245| A | `app` | `SERVER_IP` | Yes (Cloudflare) |
246| A | `registry` | `SERVER_IP` | Yes (Cloudflare) |
247
248> **Note:** Enable Cloudflare proxy (orange cloud) for automatic HTTPS. Gordon receives HTTP traffic from Cloudflare.
249
250## Cloudflare SSL Mode
251
252Gordon serves HTTP by default. Cloudflare must connect to your origin over HTTP unless you explicitly enable TLS.
253
254| Mode | How it works | Use when |
255|------|-------------|----------|
256| **Flexible** | Cloudflare terminates TLS; connects to Gordon on HTTP | Gordon has no TLS cert (default setup) |
257| **Full (Strict)** | Cloudflare connects to Gordon over HTTPS with a valid cert | Set `server.tls_port` (default 8443) and provide a Cloudflare Origin CA cert via `server.tls_cert_file` and `server.tls_key_file` |
258
259Wrong mode causes: **521** (Cloudflare can't connect) or **525** (TLS handshake failed).
260
261> **Important:** You must also set `proxy_allowed_ips` with Cloudflare edge IPs — see [Proxy Origin Allowlist](#proxy-origin-allowlist) below.
262
263> **Rootless note:** Unprivileged users can't bind port 80. Forward port 80→8088 (or your configured port) via firewall — see the firewall section above.
264
265## Proxy Origin Allowlist
266
267When Gordon's internal CA is enabled (default: `tls_port = 8443`), HTTP requests from non-localhost IPs are restricted to certificate onboarding paths only. Cloudflare and other reverse proxies must be listed in `proxy_allowed_ips` to reach your applications.
268
269Add Cloudflare edge IPs to your `gordon.toml`:
270
271```toml
272[server]
273proxy_allowed_ips = [
274  "173.245.48.0/20", "103.21.244.0/22", "103.22.200.0/22",
275  "103.31.4.0/22", "141.101.64.0/18", "108.162.192.0/18",
276  "190.93.240.0/20", "188.114.96.0/20", "197.234.240.0/22",
277  "198.41.128.0/17", "162.158.0.0/15", "104.16.0.0/13",
278  "104.24.0.0/14", "172.64.0.0/13", "131.0.72.0/22",
279]
280```
281
282Without this setting, Cloudflare traffic receives `403 Forbidden: Only certificate onboarding is available over HTTP`.
283
284> **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.
285
286## Verify Installation
287
288```bash
289# Check Gordon is running
290systemctl --user status gordon
291
292# View logs
293journalctl --user -u gordon -f
294
295# Test registry (from local machine)
296docker login registry.yourdomain.com
297docker pull alpine
298docker tag alpine registry.yourdomain.com/test:latest
299docker push registry.yourdomain.com/test:latest
300```
301
302## Data Directories
303
304Gordon stores data in the following locations:
305
306| Path | Purpose |
307|------|---------|
308| `~/.config/gordon/gordon.toml` | Configuration file |
309| `~/.gordon/` | Default data directory |
310| `~/.gordon/registry/` | Container images |
311| `~/.gordon/env/` | Environment files |
312| `~/.gordon/logs/` | Application logs |
313| `~/.gordon/secrets/` | Secrets (unsafe backend only) |
314
315## Related
316
317- [Getting Started](./getting-started.md)
318- [Configuration Reference](./config/index.md)
319- [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