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
Quick Install (Recommended)
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
User Service (Recommended for Rootless)
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)