--- title: "🏗️ Coder SSOT" description: "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." source: "verified deployment on the loca operator host, 2026-08-19; first user, template and first workspace verified 2026-08-20" reviewed: 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/@/./apps//` - the trailing slash matters; the server redirects when it is missing - web terminal: `https://code.loca.zone/@/./terminal` - arbitrary ports from your own machine: `coder port-forward --tcp 8000:8080`, or `coder ssh ` 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 ```bash 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 - https://coder.com/docs/install/docker - https://coder.com/docs/admin/setup - https://coder.com/docs/admin/networking/port-forwarding - https://coder.com/docs/install/upgrade - https://coder.com/docs/admin/users - https://coder.com/docs/reference/api/users - https://coder.com/docs/reference/api/authentication - https://github.com/coder/coder - https://github.com/coder/coder/blob/main/coderd/workspaceapps/appurl/appurl.go - https://github.com/coder/coder/blob/main/site/src/modules/apps/apps.ts