docs: add preview environments configuration guide
Documents the [auto.preview] config section, naming scheme, CLI commands, GitHub Actions CI example, and lifecycle (TTL, volume cloning, teardown).
- commit
- 9f0ec73fe7b373dd8ac078d0f205fd3e31a3c776
- author
- brice · · 2026-03-19 05:12 UTC
- committer
- brice · · 2026-03-19 05:13 UTC
- parent
- d9532c9
- signature
- unsigned
2 files · +240 -0
A docs/config/preview.md +239 -0
| @@ -0,0 +1,239 @@ | |||
| 1 | + | # Preview Environments | |
| 2 | + | ||
| 3 | + | Push a branch, get a URL. Preview environments give every branch or pull request its own isolated deployment — automatically torn down when it expires. | |
| 4 | + | ||
| 5 | + | Gordon provisions a preview environment when a matching image tag is pushed to the registry. Each preview gets its own subdomain derived from the base route, lives for a configurable TTL, and is cleaned up automatically when the TTL expires. | |
| 6 | + | ||
| 7 | + | ## Configuration | |
| 8 | + | ||
| 9 | + | ```toml | |
| 10 | + | [auto.preview] | |
| 11 | + | enabled = true | |
| 12 | + | ttl = "48h" | |
| 13 | + | separator = "--" | |
| 14 | + | tag_patterns = ["preview-*", "pr-*"] | |
| 15 | + | data_copy = true | |
| 16 | + | ``` | |
| 17 | + | ||
| 18 | + | ## Options | |
| 19 | + | ||
| 20 | + | | Option | Type | Default | Description | | |
| 21 | + | |--------|------|---------|-------------| | |
| 22 | + | | `enabled` | bool | `false` | Enable automatic preview environment creation | | |
| 23 | + | | `ttl` | duration string | `"48h"` | How long a preview environment lives before automatic teardown | | |
| 24 | + | | `separator` | string | `"--"` | String inserted between the base domain and the branch slug | | |
| 25 | + | | `tag_patterns` | string array | `[]` | Glob patterns matched against image tags to trigger preview creation | | |
| 26 | + | | `data_copy` | bool | `true` | Clone the production route's volumes into the preview environment on creation | | |
| 27 | + | ||
| 28 | + | ### `ttl` Format | |
| 29 | + | ||
| 30 | + | The `ttl` field accepts Go duration strings: | |
| 31 | + | ||
| 32 | + | | Value | Meaning | | |
| 33 | + | |-------|---------| | |
| 34 | + | | `"24h"` | 24 hours | | |
| 35 | + | | `"48h"` | 48 hours (default) | | |
| 36 | + | | `"7d"` | 7 days | | |
| 37 | + | | `"0"` | Never expire (manual deletion only) | | |
| 38 | + | ||
| 39 | + | ### `tag_patterns` Matching | |
| 40 | + | ||
| 41 | + | Patterns use standard glob syntax. A tag must match at least one pattern in the list for a preview environment to be created. | |
| 42 | + | ||
| 43 | + | | Pattern | Matches | | |
| 44 | + | |---------|---------| | |
| 45 | + | | `"preview-*"` | `preview-my-feature`, `preview-fix-123` | | |
| 46 | + | | `"pr-*"` | `pr-42`, `pr-123` | | |
| 47 | + | | `"feat/*"` | `feat/new-api`, `feat/dark-mode` | | |
| 48 | + | ||
| 49 | + | ## Naming Scheme | |
| 50 | + | ||
| 51 | + | Preview domains are derived from the base route for the deployed image. Gordon combines the base domain, the separator, and a URL-safe slug of the image tag. | |
| 52 | + | ||
| 53 | + | ``` | |
| 54 | + | <base-domain><separator><tag-slug> | |
| 55 | + | ``` | |
| 56 | + | ||
| 57 | + | For example, with `separator = "--"` and base route `app.example.com`: | |
| 58 | + | ||
| 59 | + | | Image Tag | Preview Domain | | |
| 60 | + | |-----------|----------------| | |
| 61 | + | | `preview-my-feature` | `my-feature--app.example.com` | | |
| 62 | + | | `pr-42` | `pr-42--app.example.com` | | |
| 63 | + | | `preview-fix-login` | `fix-login--app.example.com` | | |
| 64 | + | ||
| 65 | + | The tag prefix matched by `tag_patterns` is stripped to keep domains short. Slashes in tags are replaced with hyphens. | |
| 66 | + | ||
| 67 | + | ## CLI Usage | |
| 68 | + | ||
| 69 | + | ### List Preview Environments | |
| 70 | + | ||
| 71 | + | ```bash | |
| 72 | + | gordon preview list | |
| 73 | + | ``` | |
| 74 | + | ||
| 75 | + | Shows all active preview environments, their domains, TTL remaining, and source route. | |
| 76 | + | ||
| 77 | + | ### Create or Refresh a Preview | |
| 78 | + | ||
| 79 | + | Previews are created automatically on push. To manually create or reset the TTL of an existing preview: | |
| 80 | + | ||
| 81 | + | ```bash | |
| 82 | + | gordon preview create app.example.com --tag preview-my-feature | |
| 83 | + | ``` | |
| 84 | + | ||
| 85 | + | ### Extend a Preview | |
| 86 | + | ||
| 87 | + | Reset the TTL on an existing preview without redeploying: | |
| 88 | + | ||
| 89 | + | ```bash | |
| 90 | + | gordon preview extend my-feature--app.example.com | |
| 91 | + | gordon preview extend my-feature--app.example.com --ttl 24h | |
| 92 | + | ``` | |
| 93 | + | ||
| 94 | + | Without `--ttl`, the configured default TTL is applied from the current time. | |
| 95 | + | ||
| 96 | + | ### Delete a Preview | |
| 97 | + | ||
| 98 | + | ```bash | |
| 99 | + | gordon preview delete my-feature--app.example.com | |
| 100 | + | ``` | |
| 101 | + | ||
| 102 | + | Stops the container, removes the route, and (unless `volumes.preserve = true`) removes any cloned volumes. | |
| 103 | + | ||
| 104 | + | ## CI Usage | |
| 105 | + | ||
| 106 | + | ### GitHub Actions | |
| 107 | + | ||
| 108 | + | Use tag-based deploys to trigger preview environments automatically. | |
| 109 | + | ||
| 110 | + | ```yaml | |
| 111 | + | name: Preview Environment | |
| 112 | + | ||
| 113 | + | on: | |
| 114 | + | pull_request: | |
| 115 | + | types: [opened, synchronize] | |
| 116 | + | ||
| 117 | + | jobs: | |
| 118 | + | deploy-preview: | |
| 119 | + | runs-on: ubuntu-latest | |
| 120 | + | steps: | |
| 121 | + | - uses: actions/checkout@v4 | |
| 122 | + | ||
| 123 | + | - name: Log in to Gordon registry | |
| 124 | + | run: echo "${{ secrets.GORDON_TOKEN }}" | docker login ${{ vars.GORDON_REGISTRY }} -u deploy --password-stdin | |
| 125 | + | ||
| 126 | + | - name: Build and push preview image | |
| 127 | + | env: | |
| 128 | + | TAG: pr-${{ github.event.pull_request.number }} | |
| 129 | + | run: | | |
| 130 | + | docker build -t ${{ vars.GORDON_REGISTRY }}/myapp:$TAG . | |
| 131 | + | docker push ${{ vars.GORDON_REGISTRY }}/myapp:$TAG | |
| 132 | + | ||
| 133 | + | - name: Comment preview URL | |
| 134 | + | uses: actions/github-script@v7 | |
| 135 | + | with: | |
| 136 | + | script: | | |
| 137 | + | github.rest.issues.createComment({ | |
| 138 | + | issue_number: context.issue.number, | |
| 139 | + | owner: context.repo.owner, | |
| 140 | + | repo: context.repo.repo, | |
| 141 | + | body: `Preview deployed: https://pr-${{ github.event.pull_request.number }}--app.example.com` | |
| 142 | + | }) | |
| 143 | + | ``` | |
| 144 | + | ||
| 145 | + | Configure Gordon to match the `pr-*` tag convention: | |
| 146 | + | ||
| 147 | + | ```toml | |
| 148 | + | [auto.preview] | |
| 149 | + | enabled = true | |
| 150 | + | ttl = "72h" | |
| 151 | + | tag_patterns = ["pr-*"] | |
| 152 | + | ``` | |
| 153 | + | ||
| 154 | + | ### Cleanup on PR Close | |
| 155 | + | ||
| 156 | + | ```yaml | |
| 157 | + | name: Teardown Preview | |
| 158 | + | ||
| 159 | + | on: | |
| 160 | + | pull_request: | |
| 161 | + | types: [closed] | |
| 162 | + | ||
| 163 | + | jobs: | |
| 164 | + | teardown: | |
| 165 | + | runs-on: ubuntu-latest | |
| 166 | + | steps: | |
| 167 | + | - name: Delete preview environment | |
| 168 | + | env: | |
| 169 | + | TAG: pr-${{ github.event.pull_request.number }} | |
| 170 | + | run: | | |
| 171 | + | gordon --server ${{ vars.GORDON_SERVER }} preview delete ${TAG}--app.example.com | |
| 172 | + | ``` | |
| 173 | + | ||
| 174 | + | ## Lifecycle | |
| 175 | + | ||
| 176 | + | ### Creation | |
| 177 | + | ||
| 178 | + | When a push matches a `tag_patterns` entry: | |
| 179 | + | ||
| 180 | + | 1. Gordon creates a new route: `<slug>--<base-domain>` → pushed image | |
| 181 | + | 2. If `data_copy = true`, volumes from the base route are cloned into the preview | |
| 182 | + | 3. The preview TTL timer starts | |
| 183 | + | 4. The container is deployed with zero-downtime rules disabled (previews are always cold-starts) | |
| 184 | + | ||
| 185 | + | ### TTL and Automatic Teardown | |
| 186 | + | ||
| 187 | + | Gordon checks preview TTLs on a background schedule. When a preview expires: | |
| 188 | + | ||
| 189 | + | 1. In-flight connections are drained | |
| 190 | + | 2. The container is stopped and removed | |
| 191 | + | 3. The route is removed from the proxy | |
| 192 | + | 4. Cloned volumes are removed (unless `volumes.preserve = true`) | |
| 193 | + | ||
| 194 | + | Use `gordon preview extend` to reset the timer without redeploying. | |
| 195 | + | ||
| 196 | + | ### Volume Cloning | |
| 197 | + | ||
| 198 | + | When `data_copy = true`, Gordon copies the named volumes attached to the base route into fresh volumes for the preview. This gives the preview a realistic dataset without sharing state with production. | |
| 199 | + | ||
| 200 | + | - Cloned volumes are prefixed with the preview slug | |
| 201 | + | - Cloned volumes are removed on preview teardown unless `volumes.preserve = true` | |
| 202 | + | - Set `data_copy = false` to start previews with empty volumes (faster creation, no production data) | |
| 203 | + | ||
| 204 | + | ## Example Config | |
| 205 | + | ||
| 206 | + | ```toml | |
| 207 | + | [server] | |
| 208 | + | gordon_domain = "registry.example.com" | |
| 209 | + | ||
| 210 | + | [auto_route] | |
| 211 | + | enabled = true | |
| 212 | + | ||
| 213 | + | [auto.preview] | |
| 214 | + | enabled = true | |
| 215 | + | ttl = "48h" | |
| 216 | + | separator = "--" | |
| 217 | + | tag_patterns = ["preview-*", "pr-*"] | |
| 218 | + | data_copy = true | |
| 219 | + | ||
| 220 | + | [routes] | |
| 221 | + | "app.example.com" = "myapp:latest" | |
| 222 | + | "api.example.com" = "myapi:latest" | |
| 223 | + | ||
| 224 | + | [volumes] | |
| 225 | + | auto_create = true | |
| 226 | + | preserve = false | |
| 227 | + | ``` | |
| 228 | + | ||
| 229 | + | With this config: | |
| 230 | + | - Pushing `myapp:pr-99` creates `pr-99--app.example.com` with cloned volumes | |
| 231 | + | - Pushing `myapi:preview-auth-refactor` creates `preview-auth-refactor--api.example.com` | |
| 232 | + | - Both previews expire after 48 hours and volumes are removed on teardown | |
| 233 | + | ||
| 234 | + | ## Related | |
| 235 | + | ||
| 236 | + | - [Routes](./routes.md) | |
| 237 | + | - [Auto Route](./auto-route.md) | |
| 238 | + | - [Volumes](./volumes.md) | |
| 239 | + | - [Configuration Overview](./index.md) | |
| @@ -0,0 +1,239 @@ | |||||
| 1 | + | # Preview Environments | |||
| 2 | + | ||||
| 3 | + | Push a branch, get a URL. Preview environments give every branch or pull request its own isolated deployment — automatically torn down when it expires. | |||
| 4 | + | ||||
| 5 | + | Gordon provisions a preview environment when a matching image tag is pushed to the registry. Each preview gets its own subdomain derived from the base route, lives for a configurable TTL, and is cleaned up automatically when the TTL expires. | |||
| 6 | + | ||||
| 7 | + | ## Configuration | |||
| 8 | + | ||||
| 9 | + | ```toml | |||
| 10 | + | [auto.preview] | |||
| 11 | + | enabled = true | |||
| 12 | + | ttl = "48h" | |||
| 13 | + | separator = "--" | |||
| 14 | + | tag_patterns = ["preview-*", "pr-*"] | |||
| 15 | + | data_copy = true | |||
| 16 | + | ``` | |||
| 17 | + | ||||
| 18 | + | ## Options | |||
| 19 | + | ||||
| 20 | + | | Option | Type | Default | Description | | |||
| 21 | + | |--------|------|---------|-------------| | |||
| 22 | + | | `enabled` | bool | `false` | Enable automatic preview environment creation | | |||
| 23 | + | | `ttl` | duration string | `"48h"` | How long a preview environment lives before automatic teardown | | |||
| 24 | + | | `separator` | string | `"--"` | String inserted between the base domain and the branch slug | | |||
| 25 | + | | `tag_patterns` | string array | `[]` | Glob patterns matched against image tags to trigger preview creation | | |||
| 26 | + | | `data_copy` | bool | `true` | Clone the production route's volumes into the preview environment on creation | | |||
| 27 | + | ||||
| 28 | + | ### `ttl` Format | |||
| 29 | + | ||||
| 30 | + | The `ttl` field accepts Go duration strings: | |||
| 31 | + | ||||
| 32 | + | | Value | Meaning | | |||
| 33 | + | |-------|---------| | |||
| 34 | + | | `"24h"` | 24 hours | | |||
| 35 | + | | `"48h"` | 48 hours (default) | | |||
| 36 | + | | `"7d"` | 7 days | | |||
| 37 | + | | `"0"` | Never expire (manual deletion only) | | |||
| 38 | + | ||||
| 39 | + | ### `tag_patterns` Matching | |||
| 40 | + | ||||
| 41 | + | Patterns use standard glob syntax. A tag must match at least one pattern in the list for a preview environment to be created. | |||
| 42 | + | ||||
| 43 | + | | Pattern | Matches | | |||
| 44 | + | |---------|---------| | |||
| 45 | + | | `"preview-*"` | `preview-my-feature`, `preview-fix-123` | | |||
| 46 | + | | `"pr-*"` | `pr-42`, `pr-123` | | |||
| 47 | + | | `"feat/*"` | `feat/new-api`, `feat/dark-mode` | | |||
| 48 | + | ||||
| 49 | + | ## Naming Scheme | |||
| 50 | + | ||||
| 51 | + | Preview domains are derived from the base route for the deployed image. Gordon combines the base domain, the separator, and a URL-safe slug of the image tag. | |||
| 52 | + | ||||
| 53 | + | ``` | |||
| 54 | + | <base-domain><separator><tag-slug> | |||
| 55 | + | ``` | |||
| 56 | + | ||||
| 57 | + | For example, with `separator = "--"` and base route `app.example.com`: | |||
| 58 | + | ||||
| 59 | + | | Image Tag | Preview Domain | | |||
| 60 | + | |-----------|----------------| | |||
| 61 | + | | `preview-my-feature` | `my-feature--app.example.com` | | |||
| 62 | + | | `pr-42` | `pr-42--app.example.com` | | |||
| 63 | + | | `preview-fix-login` | `fix-login--app.example.com` | | |||
| 64 | + | ||||
| 65 | + | The tag prefix matched by `tag_patterns` is stripped to keep domains short. Slashes in tags are replaced with hyphens. | |||
| 66 | + | ||||
| 67 | + | ## CLI Usage | |||
| 68 | + | ||||
| 69 | + | ### List Preview Environments | |||
| 70 | + | ||||
| 71 | + | ```bash | |||
| 72 | + | gordon preview list | |||
| 73 | + | ``` | |||
| 74 | + | ||||
| 75 | + | Shows all active preview environments, their domains, TTL remaining, and source route. | |||
| 76 | + | ||||
| 77 | + | ### Create or Refresh a Preview | |||
| 78 | + | ||||
| 79 | + | Previews are created automatically on push. To manually create or reset the TTL of an existing preview: | |||
| 80 | + | ||||
| 81 | + | ```bash | |||
| 82 | + | gordon preview create app.example.com --tag preview-my-feature | |||
| 83 | + | ``` | |||
| 84 | + | ||||
| 85 | + | ### Extend a Preview | |||
| 86 | + | ||||
| 87 | + | Reset the TTL on an existing preview without redeploying: | |||
| 88 | + | ||||
| 89 | + | ```bash | |||
| 90 | + | gordon preview extend my-feature--app.example.com | |||
| 91 | + | gordon preview extend my-feature--app.example.com --ttl 24h | |||
| 92 | + | ``` | |||
| 93 | + | ||||
| 94 | + | Without `--ttl`, the configured default TTL is applied from the current time. | |||
| 95 | + | ||||
| 96 | + | ### Delete a Preview | |||
| 97 | + | ||||
| 98 | + | ```bash | |||
| 99 | + | gordon preview delete my-feature--app.example.com | |||
| 100 | + | ``` | |||
| 101 | + | ||||
| 102 | + | Stops the container, removes the route, and (unless `volumes.preserve = true`) removes any cloned volumes. | |||
| 103 | + | ||||
| 104 | + | ## CI Usage | |||
| 105 | + | ||||
| 106 | + | ### GitHub Actions | |||
| 107 | + | ||||
| 108 | + | Use tag-based deploys to trigger preview environments automatically. | |||
| 109 | + | ||||
| 110 | + | ```yaml | |||
| 111 | + | name: Preview Environment | |||
| 112 | + | ||||
| 113 | + | on: | |||
| 114 | + | pull_request: | |||
| 115 | + | types: [opened, synchronize] | |||
| 116 | + | ||||
| 117 | + | jobs: | |||
| 118 | + | deploy-preview: | |||
| 119 | + | runs-on: ubuntu-latest | |||
| 120 | + | steps: | |||
| 121 | + | - uses: actions/checkout@v4 | |||
| 122 | + | ||||
| 123 | + | - name: Log in to Gordon registry | |||
| 124 | + | run: echo "${{ secrets.GORDON_TOKEN }}" | docker login ${{ vars.GORDON_REGISTRY }} -u deploy --password-stdin | |||
| 125 | + | ||||
| 126 | + | - name: Build and push preview image | |||
| 127 | + | env: | |||
| 128 | + | TAG: pr-${{ github.event.pull_request.number }} | |||
| 129 | + | run: | | |||
| 130 | + | docker build -t ${{ vars.GORDON_REGISTRY }}/myapp:$TAG . | |||
| 131 | + | docker push ${{ vars.GORDON_REGISTRY }}/myapp:$TAG | |||
| 132 | + | ||||
| 133 | + | - name: Comment preview URL | |||
| 134 | + | uses: actions/github-script@v7 | |||
| 135 | + | with: | |||
| 136 | + | script: | | |||
| 137 | + | github.rest.issues.createComment({ | |||
| 138 | + | issue_number: context.issue.number, | |||
| 139 | + | owner: context.repo.owner, | |||
| 140 | + | repo: context.repo.repo, | |||
| 141 | + | body: `Preview deployed: https://pr-${{ github.event.pull_request.number }}--app.example.com` | |||
| 142 | + | }) | |||
| 143 | + | ``` | |||
| 144 | + | ||||
| 145 | + | Configure Gordon to match the `pr-*` tag convention: | |||
| 146 | + | ||||
| 147 | + | ```toml | |||
| 148 | + | [auto.preview] | |||
| 149 | + | enabled = true | |||
| 150 | + | ttl = "72h" | |||
| 151 | + | tag_patterns = ["pr-*"] | |||
| 152 | + | ``` | |||
| 153 | + | ||||
| 154 | + | ### Cleanup on PR Close | |||
| 155 | + | ||||
| 156 | + | ```yaml | |||
| 157 | + | name: Teardown Preview | |||
| 158 | + | ||||
| 159 | + | on: | |||
| 160 | + | pull_request: | |||
| 161 | + | types: [closed] | |||
| 162 | + | ||||
| 163 | + | jobs: | |||
| 164 | + | teardown: | |||
| 165 | + | runs-on: ubuntu-latest | |||
| 166 | + | steps: | |||
| 167 | + | - name: Delete preview environment | |||
| 168 | + | env: | |||
| 169 | + | TAG: pr-${{ github.event.pull_request.number }} | |||
| 170 | + | run: | | |||
| 171 | + | gordon --server ${{ vars.GORDON_SERVER }} preview delete ${TAG}--app.example.com | |||
| 172 | + | ``` | |||
| 173 | + | ||||
| 174 | + | ## Lifecycle | |||
| 175 | + | ||||
| 176 | + | ### Creation | |||
| 177 | + | ||||
| 178 | + | When a push matches a `tag_patterns` entry: | |||
| 179 | + | ||||
| 180 | + | 1. Gordon creates a new route: `<slug>--<base-domain>` → pushed image | |||
| 181 | + | 2. If `data_copy = true`, volumes from the base route are cloned into the preview | |||
| 182 | + | 3. The preview TTL timer starts | |||
| 183 | + | 4. The container is deployed with zero-downtime rules disabled (previews are always cold-starts) | |||
| 184 | + | ||||
| 185 | + | ### TTL and Automatic Teardown | |||
| 186 | + | ||||
| 187 | + | Gordon checks preview TTLs on a background schedule. When a preview expires: | |||
| 188 | + | ||||
| 189 | + | 1. In-flight connections are drained | |||
| 190 | + | 2. The container is stopped and removed | |||
| 191 | + | 3. The route is removed from the proxy | |||
| 192 | + | 4. Cloned volumes are removed (unless `volumes.preserve = true`) | |||
| 193 | + | ||||
| 194 | + | Use `gordon preview extend` to reset the timer without redeploying. | |||
| 195 | + | ||||
| 196 | + | ### Volume Cloning | |||
| 197 | + | ||||
| 198 | + | When `data_copy = true`, Gordon copies the named volumes attached to the base route into fresh volumes for the preview. This gives the preview a realistic dataset without sharing state with production. | |||
| 199 | + | ||||
| 200 | + | - Cloned volumes are prefixed with the preview slug | |||
| 201 | + | - Cloned volumes are removed on preview teardown unless `volumes.preserve = true` | |||
| 202 | + | - Set `data_copy = false` to start previews with empty volumes (faster creation, no production data) | |||
| 203 | + | ||||
| 204 | + | ## Example Config | |||
| 205 | + | ||||
| 206 | + | ```toml | |||
| 207 | + | [server] | |||
| 208 | + | gordon_domain = "registry.example.com" | |||
| 209 | + | ||||
| 210 | + | [auto_route] | |||
| 211 | + | enabled = true | |||
| 212 | + | ||||
| 213 | + | [auto.preview] | |||
| 214 | + | enabled = true | |||
| 215 | + | ttl = "48h" | |||
| 216 | + | separator = "--" | |||
| 217 | + | tag_patterns = ["preview-*", "pr-*"] | |||
| 218 | + | data_copy = true | |||
| 219 | + | ||||
| 220 | + | [routes] | |||
| 221 | + | "app.example.com" = "myapp:latest" | |||
| 222 | + | "api.example.com" = "myapi:latest" | |||
| 223 | + | ||||
| 224 | + | [volumes] | |||
| 225 | + | auto_create = true | |||
| 226 | + | preserve = false | |||
| 227 | + | ``` | |||
| 228 | + | ||||
| 229 | + | With this config: | |||
| 230 | + | - Pushing `myapp:pr-99` creates `pr-99--app.example.com` with cloned volumes | |||
| 231 | + | - Pushing `myapi:preview-auth-refactor` creates `preview-auth-refactor--api.example.com` | |||
| 232 | + | - Both previews expire after 48 hours and volumes are removed on teardown | |||
| 233 | + | ||||
| 234 | + | ## Related | |||
| 235 | + | ||||
| 236 | + | - [Routes](./routes.md) | |||
| 237 | + | - [Auto Route](./auto-route.md) | |||
| 238 | + | - [Volumes](./volumes.md) | |||
| 239 | + | - [Configuration Overview](./index.md) | |||
M docs/index.md +1 -0
| @@ -50,6 +50,7 @@ Gordon runs on your VPS and provides: | |||
| 50 | 50 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | |
| 51 | 51 | - [Secrets](./config/secrets.md) - Secure credential storage | |
| 52 | 52 | - [Network Isolation](./config/network-isolation.md) - Per-app network isolation | |
| 53 | + | - [Preview Environments](./config/preview.md) - Ephemeral per-branch deployments | |
| 53 | 54 | - [Attachments](./config/attachments.md) - Service dependencies | |
| 54 | 55 | - [Logging](./config/logging.md) - Log collection and rotation | |
| 55 | 56 | - [Environment Variables](./config/env.md) - Per-route environment configuration | |
| @@ -50,6 +50,7 @@ Gordon runs on your VPS and provides: | |||||
| 50 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | 50 | - [Authentication](./config/auth.md) - Registry auth plus remote CLI login/token workflows | ||
| 51 | - [Secrets](./config/secrets.md) - Secure credential storage | 51 | - [Secrets](./config/secrets.md) - Secure credential storage | ||
| 52 | - [Network Isolation](./config/network-isolation.md) - Per-app network isolation | 52 | - [Network Isolation](./config/network-isolation.md) - Per-app network isolation | ||
| 53 | + | - [Preview Environments](./config/preview.md) - Ephemeral per-branch deployments | |||
| 53 | - [Attachments](./config/attachments.md) - Service dependencies | 54 | - [Attachments](./config/attachments.md) - Service dependencies | ||
| 54 | - [Logging](./config/logging.md) - Log collection and rotation | 55 | - [Logging](./config/logging.md) - Log collection and rotation | ||
| 55 | - [Environment Variables](./config/env.md) - Per-route environment configuration | 56 | - [Environment Variables](./config/env.md) - Per-route environment configuration | ||