Closes [DOCS-415](https://linear.app/codercom/issue/DOCS-415). ## TL;DR Repoints 7 broken links across 5 docs files that the 2026-06-22 weekly `check-docs.yml` Linkspector run flagged. Two other links from the same run (the dead `nix` ref and the dead `reflectoring.io` ref in `CONTRIBUTING.md`) were already folded into [#26341](https://github.com/coder/coder/pull/26341). ## Why Broken external and anchor links degrade reader trust, leak SEO juice, and make the docs look stale. The weekly `check-docs` job exists precisely to catch this kind of rot before customers do; the surfacing-to-fix turnaround on these 7 is one PR. Run that surfaced them: [actions/runs/27948011619 job 82697664858](https://github.com/coder/coder/actions/runs/27948011619/job/82697664858). ## Scope | File | Line(s) | Old target | New target | Why | |------|---------|-----------|------------|-----| | `docs/tutorials/best-practices/organizations.md` | 62 | anchor `#update-template-metadata-by-id` | `#update-template-settings-by-id` | API endpoint renamed in [#19228](https://github.com/coder/coder/pull/19228) (Aug 2025). New heading at line 1105 of `docs/reference/api/templates.md`. | | `docs/install/registry-mirror-artifactory.md` | 197 | JFrog `terraform-registry` | `terraform-opentofu-and-terraform-backend-repositories` | JFrog consolidated their Terraform / OpenTofu / Backend docs into a single page. | | `docs/admin/templates/extending-templates/modules.md` | 76, 206 | JFrog `set-up-a-terraform-module/provider-registry` and `terraform-registry` | same consolidated JFrog page (root, no anchor) | Same JFrog consolidation. Anchor dropped, see decision log. | | `docs/admin/integrations/dx-data-cloud.md` | 84 | `https://help.getdx.com/en/` | `https://docs.getdx.com/` | DX migrated their help center to a separate docs domain. | | `docs/about/contributing/frontend.md` | 37, 71 | `https://reactrouter.com/en/main` | `https://reactrouter.com/` | React Router dropped the `/en/main` prefix. | ## Validation - All 7 replacement URLs return HTTP 200 (manual `curl -L -o /dev/null -w '%{http_code}'` per URL; linkspector's puppeteer crashed in the agent env, so it was run case-by-case) - `make lint/markdown lint/emdash` clean locally - Pre-commit hook (`scripts/githooks/pre-commit` -> `make pre-commit-light`) clean - No `/docs/` route changes; pure markdown content ## Not triggering `/coder-agents-review` Docs-only markdown edit, no CI or build config changes; per `AGENTS.md` the bot review is reserved for product / CI changes. `doc-check` handles this category. ## Pre-mortem | Concern | Mitigation | |---|---| | Replacement URL also turns out to be broken later | All 7 verified HTTP 200 today; next weekly `check-docs` run will catch any future regression. | | JFrog anchor drop on `modules.md` (76, 206) loses navigation context | Verified the consolidated JFrog page has no clean section anchor for the original target; linking the root page is the honest fix. If JFrog ships a better TOC anchor later, a follow-up can reattach. | | Anchor rename in `organizations.md` was actually a different rename | Confirmed via PR #19228 (Aug 2025) which is the exact rename that produced `## Update template settings by ID`. | <details> <summary>Decision log</summary> **Why drop the anchor on the JFrog `modules.md` links (76 + 206)**: JFrog's new consolidated page (`/terraform-opentofu-and-terraform-backend-repositories`) doesn't expose the original `set-up-a-terraform-module/provider-registry` section as a fragment-link target. The honest fix is to link the page root; readers can scroll. The `registry-mirror-artifactory.md:197` reference uses the same root link for symmetry. **Why DX `docs.getdx.com` over `help.getdx.com`**: DX's help center at `help.getdx.com/en/` now returns 404. They moved to a separate `docs.getdx.com` domain with a different content structure. Linking the docs root is the closest analog to the original "browse our docs" intent. **Why React Router root over `/en/main`**: React Router unified their docs under the root URL. The `/en/main` prefix is no longer routable. The root URL is the canonical successor. </details> <details> <summary>CI: <code>audit-docs-paths</code> failure (pre-existing, unrelated)</summary> The `audit-docs-paths` job in `.github/workflows/weekly-docs.yaml` fails on this PR because its `Fetch redirects.json` step issues an unauthenticated `curl` to a file in private `coder/coder.com` and gets a 404 (exit code 22). Same failure on every recent PR in this repo. Tracked in [DOCS-409](https://linear.app/codercom/issue/DOCS-409) and fixed in [#26571](https://github.com/coder/coder/pull/26571), which authenticates the fetch through the Contents API. My changes are docs-content only (5 markdown files, 7 line changes) and don't touch the TS/TSX paths or `redirects.json` that the audit examines, so this is a pre-existing CI break, not a regression introduced here. </details> --- *Generated by Coder Agents on @nickvigilante's behalf.*
6.7 KiB
Reusing template code
To reuse code across different Coder templates, such as common scripts or resource definitions, we suggest using Terraform Modules.
You can store these modules externally from your Coder deployment, like in a git repository or a Terraform registry. This example shows how to reference a module from your template:
data "coder_workspace" "me" {}
module "coder-base" {
source = "github.com/my-organization/coder-base"
# Modules take in variables and can provision infrastructure
vpc_name = "devex-3"
subnet_tags = { "name": data.coder_workspace.me.name }
code_server_version = 4.14.1
}
resource "coder_agent" "dev" {
# Modules can provide outputs, such as helper scripts
startup_script=<<EOF
#!/bin/sh
${module.coder-base.code_server_install_command}
EOF
}
Learn more about creating modules and module sources in the Terraform documentation.
Coder modules
Coder publishes plenty of modules that can be used to simplify some common tasks across templates. Some of the modules we publish are,
For a full list of available modules please check Coder module registry.
Offline installations
In offline and restricted deployments, there are three ways to fetch modules.
- Artifactory Remote Terraform Repository (Recommended)
- Artifactory Local Repository (manual publishing)
- Private git repository
Artifactory Remote Terraform Repository (Recommended)
Configure Artifactory as a Remote Terraform Repository that proxies and caches the Coder registry. This approach provides automatic updates and requires no manual synchronization.
See Mirror the Coder Registry with JFrog Artifactory for complete setup instructions.
Artifactory Local Repository
Air-gapped users can clone the coder/registry repo and publish a local terraform module repository to resolve modules via Artifactory.
-
Create a local-terraform-repository with name
coder-modules-local -
Create a virtual repository with name
tf -
Follow the below instructions to publish coder modules to Artifactory
git clone https://github.com/coder/registry cd registry/registry/coder/modules jf tfc jf tf p --namespace="coder" --provider="coder" --tag="1.0.0" -
Generate a token with access to the
tfrepo and set anENVvariableTF_TOKEN_example.jfrog.io="XXXXXXXXXXXXXXX"on the Coder provisioner. -
Create a file
.terraformrcwith following content and mount at/home/coder/.terraformrcwithin the Coder provisioner.provider_installation { direct { exclude = ["registry.terraform.io/*/*"] } network_mirror { url = "https://example.jfrog.io/artifactory/api/terraform/tf/providers/" } } -
Update module source as:
module "module-name" { source = "https://example.jfrog.io/tf__coder/module-name/coder" version = "1.0.0" agent_id = coder_agent.example.id ... }Replace
example.jfrog.iowith your Artifactory URL
Based on the instructions here.
Example template
We have an example template here that uses our JFrog Docker template as the underlying module.
Private git repository
If you are importing a module from a private git repository, the Coder server or provisioner needs git credentials. Since this token will only be used for cloning your repositories with modules, it is best to create a token with access limited to the repository and no extra permissions. In GitHub, you can generate a fine-grained token with read only access to the necessary repos.
If you are running Coder on a VM, make sure that you have git installed and
the coder user has access to the following files:
# /home/coder/.gitconfig
[credential]
helper = store
# /home/coder/.git-credentials
# GitHub example:
https://your-github-username:your-github-pat@github.com
If you are running Coder on Docker or Kubernetes, git is pre-installed in the
Coder image. However, you still need to mount credentials. This can be done via
a Docker volume mount or Kubernetes secrets.
Passing git credentials in Kubernetes
First, create a .gitconfig and .git-credentials file on your local machine.
You might want to do this in a temporary directory to avoid conflicting with
your own git credentials.
Next, create the secret in Kubernetes. Be sure to do this in the same namespace that Coder is installed in.
export NAMESPACE=coder
kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
name: git-secrets
namespace: $NAMESPACE
type: Opaque
data:
.gitconfig: $(cat .gitconfig | base64 | tr -d '\n')
.git-credentials: $(cat .git-credentials | base64 | tr -d '\n')
EOF
Then, modify Coder's Helm values to mount the secret.
coder:
volumes:
- name: git-secrets
secret:
secretName: git-secrets
volumeMounts:
- name: git-secrets
mountPath: "/home/coder/.gitconfig"
subPath: .gitconfig
readOnly: true
- name: git-secrets
mountPath: "/home/coder/.git-credentials"
subPath: .git-credentials
readOnly: true