# Getting Started Deploy your first app with Gordon in under 5 minutes. ## Prerequisites - A Linux VPS with Docker or Podman installed - A domain pointing to your VPS (DNS A record) - HTTPS setup: Cloudflare proxy, Tailscale, or Gordon's internal CA (`server.tls_port = 8443`) - [pass](https://www.passwordstore.org/) (password manager) with GPG key initialized ## 1. Install Gordon ```bash curl -fsSL https://gordon.bnema.dev/install | bash ``` This script automatically detects your OS and architecture, downloads the appropriate binary, and installs it to `/usr/local/bin`. ## 2. Initialize Configuration ```bash # First run creates the default config gordon serve # Press Ctrl+C to stop ``` Config is created at `~/.config/gordon/gordon.toml`. ## 3. Set Up Authentication Gordon requires a `token_secret` for JWT authentication. You can store it in `pass` or provide it via the `GORDON_AUTH_TOKEN_SECRET` environment variable. We recommend using `pass` to store secrets securely. > **Local development?** If you just want to try Gordon locally, you can disable auth temporarily: > ```toml > [auth] > enabled = false > ``` > Skip to [Step 4](#4-configure-your-gordon-domain). For production, continue below. **Initialize pass (if not already done):** ```bash # Generate a GPG key if you don't have one gpg --gen-key # Initialize pass with your GPG key ID pass init ``` **Create the JWT token secret:** ```bash # Generate and store a random 32-character secret openssl rand -base64 32 | pass insert -m gordon/auth/token_secret ``` **Or set it via environment variable:** ```bash export GORDON_AUTH_TOKEN_SECRET="your-32-character-secret-here" ``` **Update your config** (`~/.config/gordon/gordon.toml`): ```toml [auth] enabled = true secrets_backend = "pass" token_secret = "gordon/auth/token_secret" ``` ## 4. Configure Your Gordon Domain Edit `~/.config/gordon/gordon.toml`: ```toml [server] port = 8080 # Proxy port (use with Cloudflare/rootless) registry_port = 5000 # Registry port gordon_domain = "gordon.mydomain.com" # Registry + Admin API domain [routes] "app.mydomain.com" = "myapp:latest" # Domain → Image mapping ``` ## 5. Set Up DNS (Including Wildcard) `gordon_domain` is the single domain used by both the registry and admin API. In Cloudflare (or your DNS provider), create: | Type | Name | Content | Proxy | |------|------|---------|-------| | A | `gordon` | `YOUR_SERVER_IP` | Yes | | A/CNAME | `*` | `YOUR_SERVER_IP` or `gordon.mydomain.com` | Yes | Why wildcard (`*`)? - It automatically covers app routes like `app.mydomain.com`, `api.mydomain.com`, `demo.mydomain.com`, etc. - You can add new domains in `[routes]` without creating DNS records one by one. If your DNS provider supports wildcard CNAME flattening (Cloudflare does), `* -> gordon.mydomain.com` is usually the cleanest option. ## 6. Start Gordon as a Service ```bash # Create systemd user service mkdir -p ~/.config/systemd/user cat > ~/.config/systemd/user/gordon.service < gordon remotes use prod # Recommended first-time setup gordon bootstrap app.example.com myapp:latest --attachment postgres:18 --env APP_ENV=production # Then build, push, and deploy gordon push app.example.com --build --no-confirm ``` What this command does: - `gordon bootstrap` creates or updates the route, applies requested attachments, and stores environment variables. - This is the recommended path for first deploys because it does not require the route to exist ahead of time. - Run `gordon push` separately after bootstrap to build, upload, and deploy the image. If the route already exists and you only need to push a new image version, use: ```bash gordon push app.example.com --build --no-confirm ``` `gordon push` still requires the route to already exist so it can resolve the target image. Your app is now live at `https://app.mydomain.com`! ## 9. Update Your App Push a new image to deploy with zero downtime: ```bash # Make changes, then build + push + deploy gordon push myapp --build --no-confirm ``` Gordon automatically: 1. Starts the new container 2. Waits for it to be ready 3. Routes traffic to the new container 4. Stops the old container ## Next Steps - [Installation Guide](./installation.md) - Production setup with firewall and rootless containers - [Configuration Reference](./config/index.md) - All configuration options - [Authentication](./config/auth.md) - Secure your registry - [Environment Variables](./config/env.md) - Configure per-app settings ## Related - [First Deploy Tutorial](/wiki/tutorials/first-deploy.md) - [Podman Rootless Setup](/wiki/guides/podman-rootless.md)