Closes [DOCS-351](https://linear.app/codercom/issue/DOCS-351). > [!WARNING] > **DO NOT MERGE** until [DOCS-349](https://linear.app/codercom/issue/DOCS-349) ([coder.com#877](https://github.com/coder/coder.com/pull/877)) has shipped to production and baked for at least one Vercel cycle. > > Without DOCS-349, the relative links in this PR resolve to broken docs-route URLs (`/docs/helm/coder/values.yaml` -> 404) instead of GitHub URLs tagged with the displayed docs version. DOCS-349 fixes the rewriter to classify these as GitHub blob/tree URLs with the page's resolved ref. ## TL;DR Converts 121 absolute `https://github.com/coder/coder/(blob|tree)/main/<path>` links across 39 docs markdown files to relative paths. After this lands AND DOCS-349 deploys, every one of these links will follow the displayed docs version (mainline tag on bare URLs, explicit tag on `/@vX.Y.Z/`, `main` on `/@main/`) instead of always pointing to `main`. ## Why Today a reader on `/docs/@v2.30.0/install/docker` follows a `compose.yaml` link and arrives at `main`'s `compose.yaml`, which doesn't necessarily match what the docs page describes. Helm values, Terraform templates, and source-code references in particular drift across versions. The fix is to let the coder.com rewriter substitute the page's resolved ref into the URL; that only works on relative links. ## Example payoff (post-DOCS-349) | URL | Today (absolute, always `main`) | After (relative + rewriter) | |---|---|---| | `/docs/install/docker` | `https://github.com/coder/coder/blob/main/compose.yaml` | `https://github.com/coder/coder/blob/v2.34.1/compose.yaml` (today's mainline) | | `/docs/@v2.30.0/install/docker` | same as above | `https://github.com/coder/coder/blob/v2.30.0/compose.yaml` | | `/docs/@main/install/docker` | same as above | `https://github.com/coder/coder/blob/main/compose.yaml` | ## Scope - **121 conversions** across **39 files**. - Verb breakdown: `tree/main` (directories) and `blob/main` (files), both flipped to relative paths. - Line anchors (`#L23-L24`) and query strings preserved verbatim. - Conversion is mechanical: relative path computed from the doc file's directory to the target via `os.path.relpath`. Any path starting at the same directory or below gets a `./` prefix; otherwise `../` chains. ## Rebased on main The branch was rebased onto `main` after the DOCS-350 hotfix ([#26339](https://github.com/coder/coder/pull/26339)) merged. The hotfix repointed 3 `docs-backend-contrib-guide` refs in `backend.md` to `main`, which then needed the same `main` -> relative conversion this PR is doing for the other 121 links. The conflict was resolved by reapplying the mechanical conversion to `backend.md` after taking the hotfix's content. Net result: those 3 links land here as relative, same as everything else. New HEAD `3f501cb622`. ## Inline fix folded in: dead `nix` link - `docs/about/contributing/CONTRIBUTING.md:7` -> `../../../nix` The original absolute URL `https://github.com/coder/coder/tree/main/nix` already returned 404 today. Repointed to `flake.nix` (modern Nix entrypoint, what the prose "Nix environment" semantically refers to). Closes [DOCS-357](https://linear.app/codercom/issue/DOCS-357) here since the `check-docs` Linkspector job surfaced it during rebase; cheaper to fix inline than in a separate single-line PR. ## Out of scope (filed separately) - [DOCS-350](https://linear.app/codercom/issue/DOCS-350): 3 dead `docs-backend-contrib-guide` branch refs in `backend.md` ([#26339](https://github.com/coder/coder/pull/26339), merged). - [DOCS-352](https://linear.app/codercom/issue/DOCS-352): 10 SHA-pinned `(blob|tree)/<sha>` links pending intent review. - [DOCS-355](https://linear.app/codercom/issue/DOCS-355): code-server analog (4 absolute `(blob|tree)/main` links in `coder/code-server`). - [DOCS-356](https://linear.app/codercom/issue/DOCS-356): 2 upstream content bugs in `coder/code-server/docs/CONTRIBUTING.md` (independent of this PR). ## Not triggering `/coder-agents-review` Docs-only edit; per `AGENTS.md` the bot review is reserved for product/CI changes. ## Pre-mortem | Concern | Mitigation | |---|---| | Merging before DOCS-349 deploys regresses ~120 currently-working links into 404s on coder.com | Clear DO-NOT-MERGE banner; tracked as blocker in Linear. | | Relative path computed incorrectly (off-by-one `..`) | Verified all 114 newly-relative non-md/non-image paths resolve to existing files in the repo (only exception is the pre-existing dead `nix` link above). | | Line anchors stripped during conversion | Preserved by the substitution regex; verified `#L<n>-L<m>` cases in `airgap.md` and `speed-up-templates.md`. | | Future code reorgs change file locations | Relative links will start pointing to nothing. Same failure mode as absolute links pointing to renamed files; can be caught with a future link-checker job. | ## Validation ``` $ grep -rE 'github\.com/coder/coder/(blob|tree)/main' docs --include="*.md" | wc -l 0 $ git diff --stat origin/main | tail -1 39 files changed, 118 insertions(+), 118 deletions(-) ``` 114 newly-relative paths verified to resolve to existing repo files (Python `os.path.exists` check on each computed target). <details> <summary>Decision log + planning context</summary> **Why relative over `(blob|tree)/{{currentDocsVersion}}/...` templating**: relative paths require zero markdown-system support and zero upstream churn beyond this one PR. Templating would require a preprocessor on `coder.com` side AND a convention upstream authors have to remember; relative paths just work in a plain editor and `github.com`'s own renderer too. **Why `./` prefix on same-directory targets**: makes the conversion grep-able later (`grep -E '\((\.\./|\./)'`). **Why preserve `#L<n>-L<m>` anchors verbatim**: the anchor is meaningful to the linked file's content, not to the URL form; keeping it as-is preserves authorial intent. If the file later changes such that the line range drifts, that's a different problem the SHA-pin audit ([DOCS-352](https://linear.app/codercom/issue/DOCS-352)) will surface. </details> --- *Generated by Coder Agents on @nickvigilante's behalf.* ## Drive-by external link fix folded in `docs/about/contributing/CONTRIBUTING.md:296` cited `https://reflectoring.io/meaningful-commit-messages/` which is returning HTTP 503 (the host appears to be down site-wide right now). `check-docs` Linkspector flagged it after the rebase. Replaced with `https://cbea.ms/git-commit/` (Chris Beams' canonical "If applied, this commit will..." article, confirmed 200), which is the original source of the rule the prose recites anyway.
16 KiB
Air-gapped Deployments
All Coder features are supported in air-gapped / behind firewalls / disconnected / offline. This is a general comparison. Keep reading for a full tutorial running Coder air-gapped with Kubernetes or Docker.
| Public deployments | Air-gapped deployments | |
|---|---|---|
| Terraform binary | By default, Coder downloads Terraform binary from releases.hashicorp.com | Terraform binary must be included in PATH for the VM or container image. Supported versions |
| Terraform registry | Coder templates will attempt to download providers from registry.terraform.io or custom source addresses specified in each template | Custom source addresses can be specified in each Coder template, or a custom registry/mirror can be used. More details below |
| STUN | By default, Coder uses Google's public STUN server for direct workspace connections | STUN can be safely disabled users can still connect via relayed connections. Alternatively, you can set a custom DERP server |
| DERP | By default, Coder's built-in DERP relay can be used, or Tailscale's public relays. | By default, Coder's built-in DERP relay can be used, or custom relays. |
| PostgreSQL | If no PostgreSQL connection URL is specified, Coder will download Postgres from repo1.maven.org | An external database is required, you must specify a PostgreSQL connection URL |
| Telemetry | Telemetry is on by default, and can be disabled | Telemetry can be disabled |
| Update check | By default, Coder checks for updates from GitHub releases | Update checks can be disabled |
| License validation | License keys are validated locally using cryptographic signatures. No outbound connection to Coder is required | No changes needed. See offline license validation |
| AI Governance Usage Count | By default, deployments with the AI Governance Add On report usage data | Contact us to request a license with usage reporting off. |
Air-gapped container images
The following instructions walk you through how to build a custom Coder server image for Docker or Kubernetes
First, build and push a container image extending our official image with the following:
- CLI config (.tfrc) for Terraform referring to external mirror
- Terraform Providers for templates
- These could also be specified via a volume mount (Docker) or network mirror. See below for details.
Note
Coder includes the latest supported version of Terraform in the official Docker images. If you need to bundle a different version of terraform, you can do so by customizing the image.
Here's an example Dockerfile:
FROM ghcr.io/coder/coder:latest
USER root
RUN apk add curl unzip
# Create directory for the Terraform CLI (and assets)
RUN mkdir -p /opt/terraform
# Terraform is already included in the official Coder image.
# See ../../scripts/Dockerfile.base#L15
# If you need to install a different version of Terraform, you can do so here.
# The below step is optional if you wish to keep the existing version.
# See ../../provisioner/terraform/install.go#L23-L24
# for supported Terraform versions.
ARG TERRAFORM_VERSION=1.11.0
RUN apk update && \
curl -LOs https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
&& unzip -o terraform_${TERRAFORM_VERSION}_linux_amd64.zip \
&& mv terraform /opt/terraform \
&& rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip
ENV PATH=/opt/terraform:${PATH}
# Additionally, a Terraform mirror needs to be configured
# to download the Terraform providers used in Coder templates.
# There are two options:
# Option 1) Use a filesystem mirror.
# We can seed this at build-time or by mounting a volume to
# /opt/terraform/plugins in the container.
# https://developer.hashicorp.com/terraform/cli/config/config-file#filesystem_mirror
# Be sure to add all the providers you use in your templates to /opt/terraform/plugins
RUN mkdir -p /home/coder/.terraform.d/plugins/registry.terraform.io
ADD filesystem-mirror-example.tfrc /home/coder/.terraformrc
# Optionally, we can "seed" the filesystem mirror with common providers.
# Comment out lines 40-49 if you plan on only using a volume or network mirror:
WORKDIR /home/coder/.terraform.d/plugins/registry.terraform.io
ARG CODER_PROVIDER_VERSION=2.2.0
RUN echo "Adding coder/coder v${CODER_PROVIDER_VERSION}" \
&& mkdir -p coder/coder && cd coder/coder \
&& curl -LOs https://github.com/coder/terraform-provider-coder/releases/download/v${CODER_PROVIDER_VERSION}/terraform-provider-coder_${CODER_PROVIDER_VERSION}_linux_amd64.zip
ARG DOCKER_PROVIDER_VERSION=3.0.2
RUN echo "Adding kreuzwerker/docker v${DOCKER_PROVIDER_VERSION}" \
&& mkdir -p kreuzwerker/docker && cd kreuzwerker/docker \
&& curl -LOs https://github.com/kreuzwerker/terraform-provider-docker/releases/download/v${DOCKER_PROVIDER_VERSION}/terraform-provider-docker_${DOCKER_PROVIDER_VERSION}_linux_amd64.zip
ARG KUBERNETES_PROVIDER_VERSION=2.36.0
RUN echo "Adding kubernetes/kubernetes v${KUBERNETES_PROVIDER_VERSION}" \
&& mkdir -p hashicorp/kubernetes && cd hashicorp/kubernetes \
&& curl -LOs https://releases.hashicorp.com/terraform-provider-kubernetes/${KUBERNETES_PROVIDER_VERSION}/terraform-provider-kubernetes_${KUBERNETES_PROVIDER_VERSION}_linux_amd64.zip
ARG AWS_PROVIDER_VERSION=5.89.0
RUN echo "Adding aws/aws v${AWS_PROVIDER_VERSION}" \
&& mkdir -p aws/aws && cd aws/aws \
&& curl -LOs https://releases.hashicorp.com/terraform-provider-aws/${AWS_PROVIDER_VERSION}/terraform-provider-aws_${AWS_PROVIDER_VERSION}_linux_amd64.zip
RUN chown -R coder:coder /home/coder/.terraform*
WORKDIR /home/coder
# Option 2) Use a network mirror.
# https://developer.hashicorp.com/terraform/cli/config/config-file#network_mirror
# Be sure uncomment line 60 and edit network-mirror-example.tfrc to
# specify the HTTPS base URL of your mirror.
# ADD network-mirror-example.tfrc /home/coder/.terraformrc
USER coder
# Use the .terraformrc file to inform Terraform of the locally installed providers.
ENV TF_CLI_CONFIG_FILE=/home/coder/.terraformrc
Note
If you are bundling Terraform providers into your Coder image, be sure the provider version matches any templates or example templates you intend to use.
# filesystem-mirror-example.tfrc
provider_installation {
filesystem_mirror {
path = "/home/coder/.terraform.d/plugins"
}
}
# network-mirror-example.tfrc
provider_installation {
network_mirror {
url = "https://terraform.example.com/providers/"
}
}
Docker
Follow our docker-compose documentation and modify the docker-compose file to specify your custom Coder image. Additionally, you can add a volume mount to add providers to the filesystem mirror without re-building the image.
First, create an empty plugins directory:
mkdir $HOME/plugins
Next, add a volume mount to compose.yaml:
vim compose.yaml
# compose.yaml
services:
coder:
image: registry.example.com/coder:latest
volumes:
- ./plugins:/opt/terraform/plugins
# ...
environment:
CODER_TELEMETRY_ENABLE: "false" # Disable telemetry
CODER_BLOCK_DIRECT: "true" # force SSH traffic through control plane's DERP proxy
CODER_DERP_SERVER_STUN_ADDRESSES: "disable" # Only use relayed connections
CODER_UPDATE_CHECK: "false" # Disable automatic update checks
database:
image: registry.example.com/postgres:17
# ...
The
terraform providers mirror
command can be used to download the required plugins for a Coder template.
This can be uploaded into the plugins directory on your offline server.
Kubernetes
We publish the Helm chart for download on GitHub Releases. Follow our Kubernetes documentation and modify the Helm values to specify your custom Coder image.
# values.yaml
coder:
image:
repo: "registry.example.com/coder"
tag: "latest"
env:
# Disable telemetry
- name: "CODER_TELEMETRY_ENABLE"
value: "false"
# Disable automatic update checks
- name: "CODER_UPDATE_CHECK"
value: "false"
# force SSH traffic through control plane's DERP proxy
- name: CODER_BLOCK_DIRECT
value: "true"
# Only use relayed connections
- name: "CODER_DERP_SERVER_STUN_ADDRESSES"
value: "disable"
# You must set up an external PostgreSQL database
- name: "CODER_PG_CONNECTION_URL"
value: ""
# ...
Air-gapped docs
Coder also provides air-gapped documentation in case you want to host it on your own server. The docs are exported as static files that you can host on any web server, as demonstrated in the example below:
- Go to the release page. In this case, we want to use the latest version.
- Download the documentation files from the "Assets" section. It is named as
coder_docs_<version>.tgz. - Extract the file and move its contents to your server folder.
- If you are using NodeJS, you can execute the following command:
cd docs && npx http-server . - Set the CODER_DOCS_URL environment variable to use the URL of your hosted docs. This way, the Coder UI will reference the documentation from your specified URL.
With these steps, you'll have the Coder documentation hosted on your server and accessible for your team to use.
Coder Modules
To use Coder modules in offline installations, you can either:
- Mirror the Coder Registry with JFrog Artifactory (recommended)
- Manually publish modules to Artifactory or use a private git repository
Firewall exceptions
In restricted internet networks, Coder may require connection to internet. Ensure that the following web addresses are accessible from the machine where Coder is installed.
- code-server.dev (install via AUR)
- open-vsx.org (optional if someone would use code-server)
- registry.terraform.io (to create and push template)
- v2-licensor.coder.com (developing Coder in Coder)
JetBrains IDEs
Gateway, JetBrains' remote development product that works with Coder, has documented offline deployment steps.
Microsoft VS Code Remote - SSH
Installation of the Visual Studio Code Remote - SSH extension (for connecting a local VS Code to a remote Coder workspace) requires that your local machine has outbound HTTPS (port 443) connectivity to:
- update.code.visualstudio.com
- vscode.blob.core.windows.net
- *.vo.msecnd.net