v2.31.0-dev23 58a92f3

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 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"

[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 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.

Installing a Specific Version or Pre-Release

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

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

By default, the installer resolves latest to the newest stable release and verifies the downloaded checksum before installing.

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 the public edge entrypoint.
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 services, bind entrypoints.edge.address to a high port (for example :9000)
132# and redirect the external TCP edge ports your deployment uses.
133sudo firewall-cmd --permanent --add-forward-port=port=80:proto=tcp:toport=9000
134sudo firewall-cmd --permanent --add-forward-port=port=443:proto=tcp:toport=9000
135
136# Apply changes
137sudo firewall-cmd --reload
138
139# Verify
140sudo firewall-cmd --list-all
141```
142
143### Using ufw
144
145```bash
146sudo ufw allow 80/tcp
147sudo ufw allow 443/tcp
148sudo ufw allow 5000/tcp  # Registry port (if accessing directly)
149sudo ufw enable
150```
151
152## Configuration
153
154Gordon creates a default configuration on first run:
155
156```bash
157# Run once to generate config, then stop
158gordon serve
159# Press Ctrl+C
160
161# Edit configuration
162nano ~/.config/gordon/gordon.toml
163```
164
165Minimum required configuration:
166
167```toml
168[server]
169registry_port = 5000
170gordon_domain = "gordon.yourdomain.com"
171
172[entrypoints.edge]
173address = ":443"
174protocol = "smart_tcp"
175
176[routes]
177"app.yourdomain.com" = "myapp:latest"
178```
179
180See [Configuration Reference](./config/index.md) for all options.
181
182## Systemd Service
183
184### User Service (Recommended for Rootless)
185
186```bash
187mkdir -p ~/.config/systemd/user
188cat > ~/.config/systemd/user/gordon.service <<EOF
189[Unit]
190Description=Gordon Container Platform
191After=podman.socket
192
193[Service]
194Type=simple
195Restart=always
196RestartSec=5
197# Required for Podman rootless — tells Gordon where to find the Podman socket
198Environment=XDG_RUNTIME_DIR=/run/user/%U
199Environment=DOCKER_HOST=unix:///run/user/%U/podman/podman.sock
200ExecStart=/usr/local/bin/gordon serve
201
202[Install]
203WantedBy=default.target
204EOF
205
206> **Docker users:** Omit the two `Environment=` lines above — Docker's socket path is set automatically.
207
208# Enable and start
209systemctl --user daemon-reload
210systemctl --user enable --now gordon
211
212# Enable linger (keep service running after logout)
213sudo loginctl enable-linger $USER
214
215# Check status
216systemctl --user status gordon
217```
218
219### System Service (Root Mode)
220
221```bash
222sudo cat > /etc/systemd/system/gordon.service <<EOF
223[Unit]
224Description=Gordon Container Platform
225After=docker.service
226Requires=docker.service
227
228[Service]
229Type=simple
230Restart=always
231RestartSec=5
232ExecStart=/usr/local/bin/gordon serve
233User=root
234
235[Install]
236WantedBy=multi-user.target
237EOF
238
239sudo systemctl daemon-reload
240sudo systemctl enable --now gordon
241```
242
243## DNS Configuration
244
245Point your domains to your server:
246
247| Type | Name | Content | Proxy |
248|------|------|---------|-------|
249| A | `app` | `SERVER_IP` | Yes (Cloudflare) |
250| A | `registry` | `SERVER_IP` | Yes (Cloudflare) |
251
252> **Note:** Enable Cloudflare proxy (orange cloud) for automatic HTTPS. Gordon receives HTTP traffic from Cloudflare.
253
254## Cloudflare SSL Mode
255
256Gordon 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.
257
258| Mode | How it works | Use when |
259|------|-------------|----------|
260| **Flexible** | Cloudflare terminates TLS; connects to Gordon with cleartext HTTP | You want edge HTTPS only |
261| **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`) |
262
263Wrong mode causes: **521** (Cloudflare can't connect) or **525** (TLS handshake failed).
264
265> **Important:** For Cloudflare-proxied HTTP paths, set `proxy_allowed_ips` with Cloudflare edge IPs — see [Proxy Origin Allowlist](#proxy-origin-allowlist) below.
266>
267> **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.
268
269## Proxy Origin Allowlist
270
271When 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.
272
273Add Cloudflare edge IPs to your `gordon.toml`:
274
275```toml
276[server]
277proxy_allowed_ips = [
278  "173.245.48.0/20", "103.21.244.0/22", "103.22.200.0/22",
279  "103.31.4.0/22", "141.101.64.0/18", "108.162.192.0/18",
280  "190.93.240.0/20", "188.114.96.0/20", "197.234.240.0/22",
281  "198.41.128.0/17", "162.158.0.0/15", "104.16.0.0/13",
282  "104.24.0.0/14", "172.64.0.0/13", "131.0.72.0/22",
283]
284```
285
286Without this setting, Cloudflare traffic receives `403 Forbidden: Only certificate onboarding is available over HTTP`.
287
288> **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.
289
290## Installing a Specific Version or Pre-Release
291
292```bash
293# Install an exact version
294curl -fsSL https://gordon.bnema.dev/install | GORDON_VERSION=v2.30.1 bash
295
296# Install the latest pre-release instead of the latest stable release
297curl -fsSL https://gordon.bnema.dev/install | GORDON_PRERELEASE=1 bash
298```
299
300By default, the installer resolves `latest` to the newest stable release and verifies the downloaded checksum before installing.
301
302## Verify Installation
303
304```bash
305# Check Gordon is running
306systemctl --user status gordon
307
308# View logs
309journalctl --user -u gordon -f
310
311# Test registry (from local machine)
312docker login registry.yourdomain.com
313docker pull alpine
314docker tag alpine registry.yourdomain.com/test:latest
315docker push registry.yourdomain.com/test:latest
316```
317
318## Data Directories
319
320Gordon stores data in the following locations:
321
322| Path | Purpose |
323|------|---------|
324| `~/.config/gordon/gordon.toml` | Configuration file |
325| `~/.gordon/` | Default data directory |
326| `~/.gordon/registry/` | Container images |
327| `~/.gordon/env/` | Environment files |
328| `~/.gordon/logs/` | Application logs |
329| `~/.gordon/secrets/` | Secrets (unsafe backend only) |
330
331## Related
332
333- [Getting Started](./getting-started.md)
334- [Configuration Reference](./config/index.md)
335- [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