Coder: Cloud Development Environments for Teams
Provision development environments on your infrastructure. Templates, workspaces, and collaboration.
Overview
Your development team is growing. Sarah codes on a MacBook, Mike uses Windows with WSL2, and Alex prefers Linux. Everyone has different versions of Node, Python, and Docker. “Works on my machine” is no longer funny—it’s a daily problem costing hours of debugging.
Enter Coder: enterprise-grade cloud development environments that solve the “works on my machine” problem permanently. Give every developer an identical, pre-configured workspace that spins up in seconds. Onboard new team members in minutes instead of days. Scale development infrastructure dynamically. All while maintaining complete control over your code and infrastructure.
Coder (v2) is a complete rewrite of the platform, designed for Kubernetes-native deployments while supporting Docker, VMs, and bare metal. It provides Infrastructure as Code for development environments using Terraform, giving you reproducible workspaces with the flexibility to customize every aspect.
In 2025, Coder has evolved into the go-to solution for teams serious about developer experience and infrastructure efficiency. Whether you’re running a 3-person startup or managing development for hundreds of engineers, Coder scales from a homelab to enterprise deployments.
What you’ll learn:
- Installing Coder on Docker and Kubernetes
- Creating workspace templates with Terraform
- Provisioning development environments
- Managing resources and scaling
- Integrating IDEs (VS Code, JetBrains)
- Multi-user workflows and authentication
- Security and access control
Why Coder for your homelab or team?
Standardize development environments. Onboard developers instantly. Scale resources dynamically based on team needs. Provide powerful development machines without buying expensive laptops. Enable remote work with enterprise-grade infrastructure. Self-hosted means your code never leaves your infrastructure.
Prerequisites
Before starting, ensure you have:
- Linux server with Docker OR Kubernetes cluster
- Docker: 4GB+ RAM (8GB+ for multiple users)
- Kubernetes: 3-node cluster (K3s works great)
- Storage: 50GB+ for workspaces
- Network: Port 3000 for Coder web UI
- PostgreSQL database (required for production)
- Domain name (recommended for HTTPS)
Knowledge requirements:
- Docker fundamentals (containers, volumes, networks)
- Basic Terraform (HCL syntax, providers, resources)
- Kubernetes basics (if using K8s deployment)
- Git and version control concepts
Optional but recommended:
- Reverse proxy experience
- OAuth provider (GitHub, GitLab, Google)
- Terraform Cloud or Terraform Enterprise
- Understanding of Infrastructure as Code
Understanding Coder Architecture
What is Coder?
Coder is an open-source platform for provisioning remote development environments (workspaces) on your infrastructure. Unlike simple IDE-in-browser solutions, Coder manages the entire development environment lifecycle: provisioning, access control, resource management, and teardown.
Core concepts:
Workspaces: Individual development environments for each developer. Can be containers, VMs, or pods in Kubernetes.
Templates: Infrastructure as Code (Terraform) defining how workspaces are provisioned. Version-controlled, reusable configurations.
Provisioners: Coder supports Docker, Kubernetes, AWS, GCP, Azure, VMware, and any Terraform provider.
Agents: Lightweight service running in each workspace that connects it to Coder for metrics, terminal access, and IDE integration.
Users: Developers who create and access workspaces. Supports local auth, OAuth, and OIDC.
Coder vs. Alternatives
| Feature | Coder | Gitpod | GitHub Codespaces | code-server |
|---|---|---|---|---|
| Self-Hosted | Yes | Yes (complex) | No | Yes |
| Team Management | Excellent | Good | Excellent | Manual |
| Infrastructure | Terraform (any) | Kubernetes | Cloud only | Single server |
| IDE Choice | Any (VS Code, JetBrains) | Browser VS Code | Browser VS Code | Browser VS Code |
| Resource Scaling | Dynamic | Dynamic | Limited control | Manual |
| Cost | Free (self-host) | Free tier + paid | Paid tiers | Free |
| Best For | Teams, enterprises | Solo/small teams | GitHub users | Individuals |
When to choose Coder:
- You need team-wide development environments
- You want Infrastructure as Code for dev environments
- You require enterprise features (RBAC, quotas, audit logs)
- You’re already using Terraform
- You need flexibility in compute resources (Docker, K8s, cloud)
Architecture Overview
[Developer Browser/IDE Client]
↓ HTTPS
[Coder Server (Port 3000)]
↓
[PostgreSQL Database]
↓
[Terraform Provisioner]
↓
[Infrastructure Layer]
↓ ↓ ↓
[Docker] [Kubernetes] [Cloud VMs]
↓ ↓ ↓
[Workspace] [Workspace] [Workspace]
(Agent) (Agent) (Agent) How it works:
- Admin creates template (Terraform code)
- User creates workspace from template
- Coder provisions infrastructure via Terraform
- Agent starts in workspace, connects to Coder
- User accesses workspace via browser/IDE
- Coder tracks usage, enforces quotas, manages lifecycle
Installing Coder
Method 1: Docker with PostgreSQL (Recommended for Homelabs)
Create directory structure:
mkdir -p ~/coder && cd ~/coder Create docker-compose.yml:
version: '3.8'
services:
postgres:
image: postgres:15-alpine
container_name: coder-db
restart: unless-stopped
environment:
POSTGRES_USER: coder
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: coder
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- coder
healthcheck:
test: ["CMD-SHELL", "pg_isready -U coder"]
interval: 10s
timeout: 5s
retries: 5
coder:
image: ghcr.io/coder/coder:latest
container_name: coder
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
CODER_PG_CONNECTION_URL: "postgresql://coder:${POSTGRES_PASSWORD}@postgres:5432/coder?sslmode=disable"
CODER_HTTP_ADDRESS: "0.0.0.0:3000"
CODER_ACCESS_URL: "https://${CODER_DOMAIN}"
# Enable Docker provisioner
CODER_DOCKER_HOST: "unix:///var/run/docker.sock"
# Optional: OAuth with GitHub
# CODER_OAUTH2_GITHUB_CLIENT_ID: "${GITHUB_CLIENT_ID}"
# CODER_OAUTH2_GITHUB_CLIENT_SECRET: "${GITHUB_CLIENT_SECRET}"
ports:
- "3000:3000"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- coder_data:/home/coder
networks:
- coder
volumes:
postgres_data:
coder_data:
networks:
coder:
driver: bridge Create .env file:
nano .env # PostgreSQL password
POSTGRES_PASSWORD=your_secure_db_password
# Coder domain (for HTTPS access)
CODER_DOMAIN=coder.homelab.local
# Optional: GitHub OAuth
# GITHUB_CLIENT_ID=your_github_oauth_client_id
# GITHUB_CLIENT_SECRET=your_github_oauth_secret Deploy Coder:
# Start services
docker compose up -d
# Check logs
docker compose logs -f coder
# Wait for "Started HTTP listener" Create first admin user:
# Access the Coder container
docker exec -it coder /bin/bash
# Create admin user
coder users create --email [email protected] --username admin --password your_admin_password
# Make user admin
coder users update admin --role owner
# Exit container
exit Access Coder:
Navigate to http://YOUR-SERVER-IP:3000
- Log in with admin credentials
- Complete setup wizard
Method 2: Kubernetes with Helm (Production)
Prerequisites: K3s, K8s, or managed Kubernetes cluster
Add Coder Helm repository:
helm repo add coder https://helm.coder.com
helm repo update Create values.yaml:
coder:
env:
- name: CODER_ACCESS_URL
value: "https://coder.yourdomain.com"
- name: CODER_PG_CONNECTION_URL
valueFrom:
secretKeyRef:
name: coder-db-url
key: url
service:
type: LoadBalancer
externalTrafficPolicy: Local
ingress:
enable: true
host: coder.yourdomain.com
tls:
enable: true
secretName: coder-tls
postgresql:
enabled: true
auth:
username: coder
password: change-this-password
database: coder
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi Deploy with Helm:
# Create namespace
kubectl create namespace coder
# Install Coder
helm install coder coder/coder --namespace coder --values values.yaml
# Watch deployment
kubectl get pods -n coder -w
# Get access URL
kubectl get svc -n coder Create first admin:
# Get pod name
POD=$(kubectl get pod -n coder -l app.kubernetes.io/name=coder -o jsonpath='{.items[0].metadata.name}')
# Create admin user
kubectl exec -n coder -it $POD -- coder users create --email [email protected] --username admin --password your_password
# Make admin
kubectl exec -n coder -it $POD -- coder users update admin --role owner Method 3: Binary Installation
For standalone server deployments:
# Download Coder binary
curl -fsSL https://coder.com/install.sh | sh
# Or specific version
curl -L https://github.com/coder/coder/releases/download/v2.x.x/coder_2.x.x_linux_amd64.tar.gz | tar -xz -C /usr/local/bin
# Verify installation
coder version Configure environment:
# Create .env file
cat > ~/.config/coder/coder.env << EOF
CODER_PG_CONNECTION_URL=postgresql://coder:password@localhost:5432/coder
CODER_HTTP_ADDRESS=0.0.0.0:3000
CODER_ACCESS_URL=https://coder.homelab.local
EOF Start Coder:
# Run in foreground
coder server
# Or create systemd service (recommended) Creating Workspace Templates
Templates define how workspaces are provisioned. They’re written in Terraform (HCL).
Understanding Templates
Template structure:
my-template/
├── main.tf # Main Terraform configuration
├── README.md # Template documentation
└── coder.yaml # Coder metadata (optional) Key components:
- Terraform provider: Docker, Kubernetes, AWS, etc.
- coder provider: Coder-specific resources (agent, metadata)
- Resources: Containers, VMs, volumes
- Parameters: User inputs (RAM, CPU, image choice)
- Outputs: Connection info, URLs
Docker Template Example
Create main.tf:
terraform {
required_providers {
coder = {
source = "coder/coder"
version = "~> 0.12"
}
docker = {
source = "kreuzwerker/docker"
version = "~> 3.0"
}
}
}
# Get user data
data "coder_workspace" "me" {}
# User parameters
data "coder_parameter" "image" {
name = "Docker Image"
description = "Choose your development environment"
default = "codercom/enterprise-base:ubuntu"
mutable = true
option {
name = "Ubuntu (Latest)"
value = "codercom/enterprise-base:ubuntu"
}
option {
name = "Node.js 20"
value = "node:20"
}
option {
name = "Python 3.11"
value = "python:3.11"
}
}
data "coder_parameter" "cpu" {
name = "CPU Cores"
description = "Number of CPU cores"
default = "2"
type = "number"
mutable = true
validation {
min = 1
max = 8
}
}
data "coder_parameter" "memory" {
name = "Memory (GB)"
description = "Amount of RAM"
default = "4"
type = "number"
mutable = true
validation {
min = 1
max = 16
}
}
# Docker provider configuration
provider "docker" {}
# Create workspace container
resource "docker_container" "workspace" {
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"
image = data.coder_parameter.image.value
# Startup command
command = [
"sh", "-c",
<<-EOT
# Install Coder agent
curl -fsSL https://coder.com/install.sh | sh
# Start agent
coder agent
EOT
]
# Environment variables for agent
env = [
"CODER_AGENT_TOKEN=${coder_agent.main.token}",
]
# Resource limits
cpu_shares = data.coder_parameter.cpu.value * 1024
memory = data.coder_parameter.memory.value * 1024
# Persistent home directory
volumes {
volume_name = docker_volume.home.name
container_path = "/home/coder"
}
# Docker socket access (optional)
volumes {
host_path = "/var/run/docker.sock"
container_path = "/var/run/docker.sock"
}
}
# Persistent home volume
resource "docker_volume" "home" {
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}-home"
}
# Coder agent
resource "coder_agent" "main" {
arch = "amd64"
os = "linux"
# Startup script
startup_script = <<-EOT
#!/bin/bash
set -e
# Install common tools
apt-get update
apt-get install -y git curl wget vim
# Install code-server (VS Code in browser)
curl -fsSL https://code-server.dev/install.sh | sh
# Install Docker CLI
curl -fsSL https://get.docker.com | sh
echo "Workspace ready!"
EOT
}
# VS Code Web IDE
resource "coder_app" "code-server" {
agent_id = coder_agent.main.id
slug = "code-server"
display_name = "VS Code"
icon = "/icon/code.svg"
url = "http://localhost:8080"
share = "owner"
subdomain = false
healthcheck {
url = "http://localhost:8080/healthz"
interval = 5
threshold = 6
}
}
# Terminal access
resource "coder_app" "terminal" {
agent_id = coder_agent.main.id
slug = "terminal"
display_name = "Terminal"
icon = "/icon/terminal.svg"
command = "bash"
share = "owner"
}
# Metadata for users
resource "coder_metadata" "workspace_info" {
count = data.coder_workspace.me.start_count
resource_id = docker_container.workspace.id
item {
key = "CPU"
value = "${data.coder_parameter.cpu.value} cores"
}
item {
key = "Memory"
value = "${data.coder_parameter.memory.value} GB"
}
item {
key = "Image"
value = data.coder_parameter.image.value
}
} Create template in Coder:
# From template directory
coder templates create docker-workspace --directory . --variable project_name=my-project
# Or via UI: Templates → Create Template → Upload directory Kubernetes Template Example
main.tf for Kubernetes:
terraform {
required_providers {
coder = {
source = "coder/coder"
}
kubernetes = {
source = "hashicorp/kubernetes"
}
}
}
data "coder_workspace" "me" {}
provider "kubernetes" {
config_path = "~/.kube/config"
}
# Namespace for workspaces
resource "kubernetes_namespace" "workspace" {
metadata {
name = "coder-${data.coder_workspace.me.owner}"
}
}
# Workspace pod
resource "kubernetes_pod" "workspace" {
metadata {
name = "coder-${data.coder_workspace.me.owner}-${data.coder_workspace.me.name}"
namespace = kubernetes_namespace.workspace.metadata[0].name
}
spec {
container {
name = "dev"
image = "codercom/enterprise-base:ubuntu"
command = ["sh", "-c", coder_agent.main.init_script]
env {
name = "CODER_AGENT_TOKEN"
value = coder_agent.main.token
}
resources {
requests = {
cpu = "500m"
memory = "1Gi"
}
limits = {
cpu = "4"
memory = "8Gi"
}
}
volume_mount {
name = "home"
mount_path = "/home/coder"
}
}
volume {
name = "home"
persistent_volume_claim {
claim_name = kubernetes_persistent_volume_claim.home.metadata[0].name
}
}
}
}
# Persistent storage
resource "kubernetes_persistent_volume_claim" "home" {
metadata {
name = "home"
namespace = kubernetes_namespace.workspace.metadata[0].name
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = "10Gi"
}
}
}
}
resource "coder_agent" "main" {
arch = "amd64"
os = "linux"
startup_script = <<-EOT
#!/bin/bash
# Install development tools
apt-get update
apt-get install -y git vim
EOT
} Workspace Management
Creating Workspaces
Via Web UI:
- Log into Coder
- Click Create Workspace
- Select template
- Configure parameters (name, resources, options)
- Click Create Workspace
Via CLI:
# Login
coder login https://coder.homelab.local
# Create workspace
coder create my-workspace --template docker-workspace
# Start workspace
coder start my-workspace
# SSH into workspace
coder ssh my-workspace Accessing Workspaces
Browser-based access:
Click workspace → Open in Browser → Choose IDE (VS Code, Terminal)
SSH access:
# Direct SSH
coder ssh my-workspace
# Configure SSH
coder config-ssh
# Now use normal SSH
ssh coder.my-workspace IDE integration:
VS Code Desktop:
- Install “Coder” extension
- Connect to Coder server
- Select workspace
- Code with full VS Code desktop features
JetBrains IDEs:
Use JetBrains Gateway:
- Download Gateway
- Add Coder provider
- Connect to workspace
- Open project in IntelliJ/PyCharm/etc.
Workspace Lifecycle
Start/Stop workspaces:
# Start
coder start my-workspace
# Stop
coder stop my-workspace
# Restart
coder restart my-workspace Auto-stop policies:
Set inactivity timeouts to save resources:
# In template
resource "coder_agent" "main" {
# ... other config ...
# Stop after 4 hours of inactivity
connection_timeout = 14400
} Delete workspace:
coder delete my-workspace Data in persistent volumes is preserved for recreation.
Team Management
User Management
Create users (admin):
# Via CLI
coder users create --email [email protected] --username johndoe --password temp_password
# User should change password on first login Via UI:
- Admin panel → Users
- Create User
- Fill in details
- Send invite link
Roles:
- Owner: Full admin access
- Template Admin: Manage templates
- User: Create workspaces from templates
- Auditor: Read-only access to audit logs
Quotas and Resource Limits
Set user quotas:
# Limit workspace count
coder users update johndoe --workspace-quota 5
# Limit CPU per workspace
coder users update johndoe --cpu-quota 8 Template-level limits:
# In template parameters
data "coder_parameter" "cpu" {
validation {
min = 1
max = 4 # Max 4 CPUs per workspace
}
} Organization Structure
Groups (Enterprise feature):
- Assign users to groups
- Group-based template access
- Shared quotas
RBAC:
# Template access control
template:
acl:
- group: developers
permission: use
- group: admins
permission: admin Security and Authentication
OAuth2 Configuration
GitHub OAuth:
- Create GitHub OAuth App
- Set environment variables:
# docker-compose.yml
environment:
CODER_OAUTH2_GITHUB_CLIENT_ID: "your_client_id"
CODER_OAUTH2_GITHUB_CLIENT_SECRET: "your_client_secret"
CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS: "true"
CODER_OAUTH2_GITHUB_ALLOWED_ORGS: "your-org-name" - Restart Coder
- Users can now “Sign in with GitHub”
OIDC (Generic):
CODER_OIDC_ISSUER_URL: "https://accounts.google.com"
CODER_OIDC_CLIENT_ID: "your_client_id"
CODER_OIDC_CLIENT_SECRET: "your_secret" Audit Logging
Enable audit logs:
CODER_AUDIT_LOGGING: "true" View logs:
# Via CLI
coder audit-logs list
# Via API
curl -H "Coder-Session-Token: $TOKEN" https://coder.homelab.local/api/v2/audit What’s logged:
- User authentication
- Workspace creation/deletion
- Template changes
- Permission changes
- Resource access
Network Security
Workspace isolation:
# Kubernetes: Use network policies
resource "kubernetes_network_policy" "workspace" {
metadata {
name = "workspace-isolation"
namespace = kubernetes_namespace.workspace.metadata[0].name
}
spec {
pod_selector {}
policy_types = ["Ingress", "Egress"]
# Only allow traffic from Coder
ingress {
from {
namespace_selector {
match_labels = {
name = "coder"
}
}
}
}
}
} Advanced Features
Air-Gapped Deployments
Run Coder completely offline:
Package offline installer:
# Download Coder binary
curl -L https://github.com/coder/coder/releases/download/v2.x.x/coder_2.x.x_linux_amd64.tar.gz
# Download required images
docker pull ghcr.io/coder/coder:latest
docker pull codercom/enterprise-base:ubuntu
# Save images
docker save -o coder-images.tar ghcr.io/coder/coder:latest codercom/enterprise-base:ubuntu
# Transfer to air-gapped environment
# Load images
docker load -i coder-images.tar Custom Provisioners
Support any infrastructure:
# VMware vSphere example
provider "vsphere" {
# ... config ...
}
resource "vsphere_virtual_machine" "workspace" {
# ... VM definition ...
}
resource "coder_agent" "main" {
# Agent connects from VM
} Metrics and Monitoring
Prometheus metrics:
CODER_PROMETHEUS_ENABLE: "true"
CODER_PROMETHEUS_ADDRESS: "0.0.0.0:2112" Scrape config:
# prometheus.yml
scrape_configs:
- job_name: 'coder'
static_configs:
- targets: ['coder:2112'] Grafana dashboard:
Import official Coder dashboard from Grafana.com
Troubleshooting
Workspace Won’t Start
Check provisioner logs:
# Via UI: Workspace → Build Logs
# Via CLI
coder logs my-workspace Common issues:
- Terraform errors: Check template syntax
- Resource limits: Increase quotas
- Image pull failures: Check registry access
Agent Connection Failed
Debug agent:
# Check agent status in workspace
curl http://localhost:6060/healthz
# View agent logs
docker logs coder-username-workspace | grep agent Firewall issues:
Ensure workspace can reach Coder server (usually port 3000)
Performance Issues
Optimize resources:
# Reduce startup script complexity
startup_script = <<-EOT
# Only essential installs
apt-get update
apt-get install -y git
# Defer other installs to runtime
EOT Database tuning:
# PostgreSQL optimizations
POSTGRES_MAX_CONNECTIONS: "200"
POSTGRES_SHARED_BUFFERS: "256MB" Conclusion
Coder brings enterprise-grade development infrastructure to teams of any size. You’ve learned:
- Installing Coder on Docker and Kubernetes
- Creating workspace templates with Terraform
- Provisioning and managing workspaces
- Team management and authentication
- Security and access control
- Advanced features and integrations
Key Takeaways
- Infrastructure as Code: Templates define reproducible environments
- Any infrastructure: Docker, Kubernetes, clouds, VMs
- Team-ready: RBAC, quotas, audit logs, SSO
- IDE flexibility: Browser, desktop, SSH access
- Self-hosted: Complete control, no vendor lock-in
Next Steps
- Create production templates for your tech stack
- Onboard your team with standardized environments
- Integrate with CI/CD for automated deployments
- Set up monitoring with Prometheus and Grafana
- Implement quotas to manage resource usage
- Configure SSO for seamless authentication
Related Guides
- code-server - Simpler browser-based VS Code
- Gitea - Self-hosted Git for workspace repos
- K3s - Lightweight Kubernetes for Coder
- Docker Basics - Container fundamentals
- Terraform - IaC for advanced templates
Resources
- Official Docs: coder.com/docs
- GitHub: github.com/coder/coder
- Template Examples: github.com/coder/coder/tree/main/examples
- Community: Discord
Document Version: 1.0 Last Updated: December 16, 2025 Based on: Coder v2.8+ Estimated Completion Time: 60 minutes
Happy cloud development!