Files
coder/q5vault/index.md

7.5 KiB

title, description, source, reviewed
title description source reviewed
🏗️ Coder SSOT Single source of truth for the self-hosted Coder control plane at https://code.loca.zone, its private postgres, its deliberate auth model, and its operations. verified deployment on the loca operator host, 2026-08-19; first user, template and first workspace verified 2026-08-20 2026-08-20

🏗️ Coder SSOT

Self-hosted Coder control plane (a workspace manager, not an editor) running as a pinned docker compose stack in /home/loca/dev/coder, reverse-proxied by Nginx, published loopback-only on 127.0.0.1:52226, backed by a private postgres container. Coder owns its own identity, so this vhost is deliberately not behind Authelia.

Sibling stack: the single-user browser IDE at cdsr.loca.zone is a different deployment and is documented in its own wiki.

🚀 Quick start

  • open: https://code.loca.zone
    • the Coder dashboard runs its own login; there is no auth.loca.zone redirect on this host
    • wiki (public, no login): https://wiki.code.loca.zone
  • stack root: /home/loca/dev/coder
    • compose: docker-compose.yml, image pin ghcr.io/coder/coder:v2.35.3, database postgres:17
    • runtime pin: config/runtime-version.txt contains v2.35.3
    • nginx source of truth: deploy/code.nginx.conf, installed as /etc/nginx/sites-available/code.loca.zone
    • secrets: .env (mode 600, git-ignored); it holds CODER_PG_PASSWORD and its contents are never read into docs
    • admin login: .admin-credentials (mode 600, git-ignored); it holds the initial Owner login and a CLI session token, and its contents are never read into docs, a ticket or a chat message
  • lifecycle, all of it needs sudo -n because loca is not in the docker group:
    • bring up: cd /home/loca/dev/coder && sudo -n docker compose up -d
    • status: sudo -n docker compose ps
    • logs: sudo -n docker compose logs -f coder
    • restart server only: sudo -n docker compose restart coder
    • stop: sudo -n docker compose down (containers go, the postgres volume stays)
  • loopback health, from the host shell:
    • curl -sf http://127.0.0.1:52226/healthz returns OK
    • curl -sf http://127.0.0.1:52226/api/v2/buildinfo returns version v2.35.3+65e2bfb, dashboard_url https://code.loca.zone, telemetry false
  • port 52226 is the only host-visible socket, bound on 127.0.0.1 inside the 51000-53000 loca.zone app range; container-internal listener is 0.0.0.0:7080

🔐 Auth model in two lines

  • Coder authenticates users itself: the browser gets a host-scoped coder_session_token cookie, while the coder CLI and every workspace agent authenticate with the Coder-Session-Token header, so nginx passes all traffic through untouched with no auth_request.
  • Authelia default_policy is bypass and no rule names code.loca.zone, so nothing gates this vhost; adding a rule would answer every cookie-less agent and CLI request with a 302 to auth.loca.zone and break the deployment. Full reasoning: operations/auth-model.

👤 Bootstrapped state and the operator's next actions

  • setup is done; this is no longer a deployment waiting for a first pass:
    • Owner account loca (admin@loca.zone) exists, is active and holds the Owner role, so GET /api/v2/users/first answers 200
    • the default organization is coder
    • the docker template is pushed and its version is active, and one workspace (ws1) is running against it; see operations/workspaces
  • how that account was created, for the record: POST /api/v2/users/first over loopback, with a randomly generated 32-character password written straight into /home/loca/dev/coder/.admin-credentials (mode 600, git-ignored) and never displayed, logged or copied anywhere else
  • the operator's actual next actions, in order:
    • sign in at https://code.loca.zone and rotate that generated password in Account then Security, so the only stored copy stops being the live credential
    • create further workspaces from the docker template, respecting the memory gate in reference/limits
  • Coder OSS has no open signup: POST /api/v2/users requires authentication, so every later account is admin-created only (coder users create, or Users then New user in the dashboard)

🧩 Reaching a workspace

  • workspace app, path-based because coder_app keeps subdomain = false: https://code.loca.zone/@<username>/<workspace>.<agent>/apps/<slug>/
    • the trailing slash matters; the server redirects when it is missing
  • web terminal: https://code.loca.zone/@<username>/<workspace>.<agent>/terminal
  • arbitrary ports from your own machine: coder port-forward <workspace> --tcp 8000:8080, or coder ssh <workspace> plus normal SSH forwarding
  • dashboard port forwarding and subdomain = true apps are unavailable here because no wildcard access URL is configured; see reference/limits and operations/workspaces

⬆️ Upgrade in four steps

cd /home/loca/dev/coder
# 1. snapshot first: upstream states Coder does not support rollbacks
sudo -n docker compose exec -T database pg_dump -U coder coder | gzip > /home/loca/dev/coder/backup-$(date +%F).sql.gz
# 2. edit the image tag in docker-compose.yml and config/runtime-version.txt
sudo -n docker compose pull coder && sudo -n docker compose up -d coder
curl -sf http://127.0.0.1:52226/api/v2/buildinfo

Full procedure, including restore: operations/install-upgrade.

✅ Do / don't

  • do: pin the image tag and keep config/runtime-version.txt in step with docker-compose.yml
  • do: keep postgres private; it publishes no host port and is reachable only over the compose network
  • do: record free -m before and after every workspace build; this host runs about ten co-tenant stacks and the gate is documented in reference/limits
  • do: leave TLS to nginx; the container speaks plain HTTP on loopback only
  • don't: add an Authelia rule for code.loca.zone; it would break agents, the CLI and DERP traffic
  • don't: pass /var/run/docker.sock into a workspace container; the socket stays on the control plane
  • don't: create Coder accounts for other people; this is a single-admin deployment with the Owner authoring every template
  • don't: put secrets in this repo; .env is the only home for CODER_PG_PASSWORD and it is git-ignored
  • don't: commit, paste or quote .admin-credentials anywhere; it stays at mode 600 in a git-ignored path, and its only legitimate use is one interactive sign-in before the password is rotated

Start here

Need Page
Architecture section hub architecture/index
Understand the deployed shape architecture/runtime-topology
Operations section hub operations/index
Bring up, upgrade, back up operations/install-upgrade
Understand or change auth operations/auth-model
Build templates and reach workspaces operations/workspaces
Re-run the proof checks operations/verification
Reference section hub reference/index
Look up a path, port or env var reference/config-paths
Know what is deliberately off reference/limits

📚 Sources