# 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 ### Quick Install (Recommended) ```bash ( 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: ```bash # 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)** ```bash 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. ```bash 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)** ```bash 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)** ```bash 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: ```bash gordon version ``` ### From Source ```bash # 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 ```bash # 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. ```bash # 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 < ip daddr 127.0.0.1 tcp dport 32768-60999 accept meta skuid 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 ```bash # 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 ```bash 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: ```bash # Run once to generate config, then stop gordon serve # Press Ctrl+C # Edit configuration nano ~/.config/gordon/gordon.toml ``` Minimum required configuration: ```toml [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](./getting-started.md#8-deploy-your-first-app)). See [Configuration Reference](./config/index.md) for all options. ## Systemd Service ### User Service (Recommended for Rootless) ```bash mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/gordon.service < **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 ``` See [Hardened systemd user unit](./config/security-hardening.md#hardened-systemd-user-unit) for the recommended sandboxing directives. ### System Service (Root Mode) ```bash sudo cat > /etc/systemd/system/gordon.service < **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](#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`: ```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](./config/server.md#proxy-origin-ip-allowlist) for details. ## Choosing an Install Channel ```bash # Install an exact release curl -fsSL https://bnema.dev/gordon/install | GORDON_VERSION=v3.4.0 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 default stable install resolves the latest tag from the `github.com/bnema/gordon/releases/latest` redirect, so it does not use the rate-limited GitHub API; exact-version installs make no lookup at all. Pre-release lookups still use the GitHub API. 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 ```bash # 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) | ## Related - [Getting Started](./getting-started.md) - [Configuration Reference](./config/index.md) - [Podman Rootless Setup](/wiki/guides/podman-rootless.md)