113 lines
7.5 KiB
Markdown
113 lines
7.5 KiB
Markdown
---
|
|
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/@<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
|
|
|
|
```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
|