Development advanced ⏱ 60 minutes

Coder: Cloud Development Environments for Teams

Provision development environments on your infrastructure. Templates, workspaces, and collaboration.

By homelabbing.io • 2025-12-17
#coder#development#workspaces#kubernetes#docker

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

FeatureCoderGitpodGitHub Codespacescode-server
Self-HostedYesYes (complex)NoYes
Team ManagementExcellentGoodExcellentManual
InfrastructureTerraform (any)KubernetesCloud onlySingle server
IDE ChoiceAny (VS Code, JetBrains)Browser VS CodeBrowser VS CodeBrowser VS Code
Resource ScalingDynamicDynamicLimited controlManual
CostFree (self-host)Free tier + paidPaid tiersFree
Best ForTeams, enterprisesSolo/small teamsGitHub usersIndividuals

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:

  1. Admin creates template (Terraform code)
  2. User creates workspace from template
  3. Coder provisions infrastructure via Terraform
  4. Agent starts in workspace, connects to Coder
  5. User accesses workspace via browser/IDE
  6. Coder tracks usage, enforces quotas, manages lifecycle

Installing Coder

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:

  1. Log into Coder
  2. Click Create Workspace
  3. Select template
  4. Configure parameters (name, resources, options)
  5. 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:

  1. Install “Coder” extension
  2. Connect to Coder server
  3. Select workspace
  4. Code with full VS Code desktop features

JetBrains IDEs:

Use JetBrains Gateway:

  1. Download Gateway
  2. Add Coder provider
  3. Connect to workspace
  4. 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:

  1. Admin panel → Users
  2. Create User
  3. Fill in details
  4. 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:

  1. Create GitHub OAuth App
  2. 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"
  1. Restart Coder
  2. 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

  1. Create production templates for your tech stack
  2. Onboard your team with standardized environments
  3. Integrate with CI/CD for automated deployments
  4. Set up monitoring with Prometheus and Grafana
  5. Implement quotas to manage resource usage
  6. Configure SSO for seamless authentication
  • 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


Document Version: 1.0 Last Updated: December 16, 2025 Based on: Coder v2.8+ Estimated Completion Time: 60 minutes

Happy cloud development!