Coder is for teams that want developer workspaces to be infrastructure, not a pile of snowflake laptops.
It gives you a self-hosted control plane for cloud development environments, Terraform-backed templates, browser and SSH access, and AI coding agent workflows.
The interesting part is not only that it can start a workspace.
The interesting part is that workspaces become reproducible, governed, and close to the infrastructure they need.
Coder is a self-hosted platform for cloud development environments and AI agent workspaces.
What is Coder?
Coder lets platform teams define developer environments as templates, then lets developers create workspaces from those templates.
A workspace might be a Docker container, Kubernetes pod, cloud VM, GPU machine, or another Terraform-managed environment. The developer gets access through the Coder dashboard, CLI, SSH, forwarded ports, web apps, and editor integrations.
Coder also has a growing AI side: Coder Agents, AI Gateway, AI Governance, and Agent Firewall. That makes it relevant for teams trying to give AI coding agents controlled environments instead of handing them broad access to developer laptops or production credentials.
Why Self-Host Coder?
Self-hosting Coder is most useful when local-only development is no longer enough.
Good reasons:
- Reproducible workspaces: define environments once with templates.
- Central control: manage users, templates, workspace lifecycle, and policies in one place.
- Fast access to private infrastructure: run workspaces near databases, clusters, source mirrors, GPUs, or internal networks.
- Lower laptop dependency: heavy builds and tools run remotely.
- Governed AI agent execution: give coding agents controlled workspaces instead of long-lived personal machines.
- Cost control: idle workspaces can shut down automatically.
For one developer with one VPS, plain SSH may be enough. Coder starts making more sense when you have a team, a shared platform, regulated access, or workloads that do not belong on laptops.
Tech Overview of Coder
I inspected the default branch at commit 9008b7881a. The latest stable GitHub release observed during this pass was v2.36.4, published on 2026-09-01.
The repository is a large Go monorepo with a React dashboard:
- Backend: Go module
github.com/coder/coder/v2. - Main server:
coderd, started throughcoder server. - Database: PostgreSQL for production deployments.
- Provisioning: Terraform-backed workspace templates.
- Provisioners: embedded by default, external when you want scale or stronger isolation.
- Agent runtime: runs inside workspaces and provides SSH, port forwarding, apps, scripts, files, processes, metrics, and connectivity.
- Frontend: React 19, Vite, TypeScript, TanStack Query, Monaco, xterm, Radix UI, Tailwind 4, and Lucide icons.
- Official image:
ghcr.io/coder/coder.
The control plane stores state in Postgres. Workspace infrastructure is created from templates. Agents inside the workspaces connect back to Coder so users can reach their environment without manually exposing every workspace service.
Architecture Notes
The system is easiest to understand as three cooperating pieces.
First, coderd is the API and dashboard service.
It serves the browser UI, HTTP API, build info, health checks, deployment config, user setup, templates, workspaces, provisioner jobs, chats, and agent-related APIs.
It is also the service that talks to Postgres.
Second, provisionerd runs infrastructure jobs.
In simple deployments this can be embedded, but external provisioners are a better model when Terraform credentials and provisioning capacity need to be separated from the main server.
Third, the workspace agent runs inside each workspace.
The agent is what makes SSH, terminal sessions, forwarded ports, web apps, liveness checks, startup scripts, file/process APIs, and agent-facing integrations usable from the Coder control plane.
This is why the product feels more like a developer platform than a remote desktop wrapper.
Self-Hosting Coder with Docker
Coder publishes an official Docker image, and the repository includes a Compose file with Coder plus Postgres.
The Home-Lab version below pins the image to the tested stable release, keeps the public port bound to loopback by default, uses Postgres 17, mounts the Docker socket for Docker-backed workspace templates, and disables telemetry in the sample environment.
Pre-Requisites - Docker
Install Docker on your system before proceeding:
- Linux: Official Docker Engine install guide
- Windows / Mac: Docker Desktop
Verify installation: docker --version && docker compose version
Docker Compose Configuration
The reusable Home-Lab compose file is here:
The site can include the same snippet from the Home-Lab submodule:
assets/snippets/coder/docker-compose.yml
services:
coder-db:
image: postgres:17
environment:
POSTGRES_USER: coder
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}
POSTGRES_DB: coder
PGDATA: /var/lib/postgresql/data/pgdata
healthcheck:
test: ["CMD-SHELL", "pg_isready -U coder -d coder"]
interval: 10s
timeout: 5s
retries: 10
start_period: 30s
volumes:
- coder-db-data:/var/lib/postgresql/data
coder:
image: ghcr.io/coder/coder:v2.36.4
depends_on:
coder-db:
condition: service_healthy
ports:
- "127.0.0.1:${CODER_PORT:-7080}:7080"
group_add:
- "${DOCKER_GROUP_ID:-998}"
environment:
CODER_HTTP_ADDRESS: 0.0.0.0:7080
CODER_ACCESS_URL: ${CODER_ACCESS_URL:?Set CODER_ACCESS_URL in .env}
CODER_WILDCARD_ACCESS_URL: ${CODER_WILDCARD_ACCESS_URL:-}
CODER_PG_CONNECTION_URL: postgresql://coder:${POSTGRES_PASSWORD}@coder-db:5432/coder?sslmode=disable
CODER_TELEMETRY_ENABLE: ${CODER_TELEMETRY_ENABLE:-false}
CODER_DISABLE_PASSWORD_AUTH: ${CODER_DISABLE_PASSWORD_AUTH:-false}
volumes:
- coder-home:/home/coder
- /var/run/docker.sock:/var/run/docker.sock
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://127.0.0.1:7080/healthz >/dev/null || exit 1"]
interval: 10s
timeout: 5s
retries: 10
start_period: 45s
volumes:
coder-db-data:
coder-home:
Create .env from the sample:
cp assets/snippets/coder/.env.sample assets/snippets/coder/.env
Then edit:
POSTGRES_PASSWORD
CODER_ACCESS_URL
CODER_WILDCARD_ACCESS_URL
DOCKER_GROUP_ID
You can get the Docker group ID on a Linux host with:
getent group docker | cut -d: -f3
Start the stack:
cd assets/snippets/coder
docker compose up -d
Open the dashboard:
http://localhost:7080
Check health:
curl http://localhost:7080/healthz
The first browser visit walks through initial user creation. The API endpoint /api/v2/users/first returns a first-user state before setup has been completed.
Field Note: Docker Trial on This Host
I validated the current image locally with Postgres.
Because this Docker host has already exhausted its bridge-network address pools, I used a host-network trial for the application container and a direct host port for Postgres.
The tested image:
ghcr.io/coder/coder:v2.36.4
The field test did the following:
- started
postgres:17on host port55433; - started Coder on
127.0.0.1:13000; - mounted
/var/run/docker.sock; - configured
CODER_PG_CONNECTION_URLagainst the test Postgres database; - checked
/healthz; - checked
/; - checked
/api/v2/buildinfo; - checked
/api/v2/users/first; - stopped both test containers after validation.
Results:
/healthzreturned200 OKwith bodyOK./returned200 OKand Coder security headers.X-Coder-Build-Versionreportedv2.36.4+10fd510./api/v2/buildinforeturned versionv2.36.4+10fd510./api/v2/users/firstreturned404withThe initial user has not been created!, which is expected before first-run setup.
Two warnings were worth noting:
CODER_ACCESS_URL=http://127.0.0.1:13000is only acceptable for a local smoke test.- The server warned that the installed Terraform version was newer than the maximum expected version.
That is enough to confirm the container, database connection, HTTP server, and first-run state. It does not validate a full workspace template or a remote agent connection.
Reverse Proxy and Exposure
Set CODER_ACCESS_URL to the URL that browsers and workspaces can actually reach.
For example:
CODER_ACCESS_URL=https://coder.example.com
CODER_WILDCARD_ACCESS_URL=*.coder.example.com
Then expose it through Caddy, Traefik, Nginx, Cloudflare Tunnel, Tailscale, or another controlled ingress path.
Do not use localhost as the access URL for real team workspaces. It will work for a single local test, but remote workspaces will not be able to call back to your Coder deployment.
Security Notes
Coder is powerful because templates can create infrastructure and agents can bridge into development environments. Treat it accordingly.
For a serious deployment:
- use TLS;
- use external PostgreSQL with backups;
- restrict dashboard access;
- configure SSO before disabling password auth;
- review every workspace template like infrastructure code;
- isolate external provisioners when Terraform credentials are sensitive;
- be careful with the Docker socket mount because it gives broad host control;
- set wildcard app domains intentionally;
- decide whether deployment telemetry is acceptable for your environment;
- keep Coder upgraded, especially if exposed beyond a private network.
When to Pick Coder
Pick Coder when you want developer environments to be centrally managed and reproducible.
It fits teams that already think in templates, infrastructure-as-code, and internal platforms. It also fits AI agent workflows where each agent should get a controlled workspace rather than direct access to a developer laptop.
Skip it for tiny setups where a single SSH server and a Git checkout are already enough. Coder adds a real control plane, and that is only worth it when you benefit from shared templates, remote compute, lifecycle controls, and governance.
Final Thoughts
Coder is one of the more serious self-hosted developer-platform projects I have looked at.
The source tree is big because the product surface is big: API server, UI, provisioners, agents, database migrations, templates, security controls, and AI governance all live in the same ecosystem.
For homelab use, I would start with Docker plus Postgres, bind it to localhost, put it behind a private tunnel or reverse proxy, then create one Docker-based template before adding cloud or Kubernetes templates.
Once the first workspace boots and connects reliably, the rest of the value becomes much easier to evaluate.
Comments