Jesse A. Green / notebook

Live demo: the DocCompiler guide library as a static, read-only snapshot (October 2026). No backend, no accounts, nothing to submit.

code-server Administrator & Developer Guide

Generated May 2026 from coder/code-server at 5f7c23b

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

code-server wraps Visual Studio Code in a Node.js server process, exposing it as a browser-accessible web application with its own authentication, proxying, and CLI layer. It is built by Coder (coder.com), licensed MIT, and targets administrators who need to provide remote development environments accessible from any device with a modern browser.

1.1 High-Level Architecture

Browser (any device)
  │
  │  HTTPS / WSS
  ▼
┌─────────────────────────────────────────────────┐
│  code-server (Node.js 22 / Express 5)           │
│                                                  │
│  ┌──────────┐  ┌──────────┐  ┌───────────────┐ │
│  │ CLI/Entry │→│ Wrapper   │→│ Child Process  │ │
│  │ (entry.ts)│  │(parent)  │  │ (actual server)│ │
│  └──────────┘  └──────────┘  └───────┬───────┘ │
│                                       │         │
│  ┌────────────────────────────────────┤         │
│  │         Express Router             │         │
│  │  ┌─────┐ ┌─────┐ ┌──────┐ ┌────┐ │         │
│  │  │Login│ │Proxy│ │Health│ │VS  │ │         │
│  │  │Route│ │Route│ │Route │ │Code│ │         │
│  │  └─────┘ └─────┘ └──────┘ └────┘ │         │
│  └────────────────────────────────────┘         │
│                                                  │
│  VS Code Server (lib/vscode submodule + patches)│
└─────────────────────────────────────────────────┘
       │
       ▼
  Filesystem (extensions, settings, heartbeat)

1.2 Process Model — The Wrapper Pattern

code-server uses a parent/child process architecture implemented in src/node/wrapper.ts:

  1. Parent process (ParentProcess): Spawns a child with the --child flag and an IPC channel. Forwards CLI arguments via a handshake message. Monitors the child for crashes and handles OS signals (SIGTERM, SIGINT, SIGHUP).
  2. Child process (ChildProcess): Receives arguments from the parent over IPC, then starts the actual HTTP server. Calls preventExit() to override process.exit() — this is critical because VS Code's internals call process.exit() in several places, which would crash the entire server without this guard.
  3. ProcessError: Wraps exit codes so the wrapper can distinguish intentional shutdowns from crashes.

This isolation layer exists specifically because VS Code was designed as a desktop application and calls process.exit() in code paths that a long-running server must survive.

1.3 Request Flow

Incoming request
  │
  ├─ Cookie parser middleware
  ├─ Common middleware (injects args, heart, settings, updater)
  ├─ TLS redirect (if --cert configured)
  │
  ├─ /_static/*           → Static file serving (no auth)
  ├─ Domain proxy check   → Domain-based proxy (if --proxy-domain matches hostname)
  ├─ /proxy/:port/*       → Path-based proxy with URL rewriting
  ├─ /absproxy/:port/*    → Absolute path proxy (passthrough, no rewriting)
  ├─ /healthz             → Health check (HTTP GET or WebSocket)
  ├─ /login               → Login page (GET) / password submission (POST)
  ├─ /logout              → Session clearing
  ├─ /update/check        → Version update check
  ├─ /vscode/*            → VS Code web client (legacy prefix)
  ├─ /*                   → VS Code web client (primary)
  └─ 404                  → Catch-all error handler

1.4 Component Inventory

Component Path Role
Entry point src/node/entry.ts CLI parsing, dispatch to wrapper or VS Code CLI
CLI parser src/node/cli.ts Argument parsing, config file loading, defaults
App factory src/node/app.ts Express + HTTP(S) server creation
Route registry src/node/routes/index.ts Middleware chain and route mounting
VS Code route src/node/routes/vscode.ts Loads VS Code server module, delegates
Login route src/node/routes/login.ts Login page rendering, password validation, rate limiting
Logout route src/node/routes/logout.ts Cookie clearing
Health route src/node/routes/health.ts Health check (HTTP + WebSocket)
Update route src/node/routes/update.ts Version check endpoint
Domain proxy src/node/routes/domainProxy.ts Hostname-based port proxying
Path proxy src/node/routes/pathProxy.ts URL path-based port proxying
Error handlers src/node/routes/errors.ts HTTP + WebSocket error handling
HTTP utilities src/node/http.ts Auth, origin check, redirect, cookies, templates
Proxy server src/node/proxy.ts http-proxy instance with redirect rewriting
Heart src/node/heart.ts Heartbeat file writing, activity tracking
Settings src/node/settings.ts JSON file-based settings read/write
Socket proxy src/node/socket.ts TLS socket proxying for child processes
Update provider src/node/update.ts GitHub release checking, version comparison
Utilities src/node/util.ts Paths, password hashing (argon2/SHA256), cert generation
Constants src/node/constants.ts Version strings, XDG paths, proxy env
Wrapper src/node/wrapper.ts Parent/child process management
VS Code socket src/node/vscodeSocket.ts Editor session manager IPC
WS router src/node/wsRouter.ts WebSocket routing on top of Express
i18n src/node/i18n/index.ts i18next initialization, custom string loading
Emitter src/common/emitter.ts Event emitter with async support
HTTP types src/common/http.ts HttpCode enum, HttpError class, cookie session name
Common utilities src/common/util.ts plural, generateUuid, normalize, logError
Service worker src/browser/serviceWorker.ts Minimal PWA service worker

1.5 Technology Stack

Layer Technology Version
Runtime Node.js 22
Language TypeScript 5.6
HTTP framework Express 5.0.1
WebSocket ws 8.14
Password hashing argon2 0.44
Proxy http-proxy 1.18
TLS httpolyglot 0.1.2
Config parsing js-yaml 4.1
i18n i18next 25.8
Rate limiting limiter 2.1
Proxy agent proxy-agent 6.3
Version comparison semver 7.5
Log rotation rotating-file-stream 3.1
Path resolution env-paths 2.2, xdg-basedir 4.0 —
Process init (Docker) dumb-init —
VS Code Submodule at lib/vscode Patched via quilt

1.6 VS Code Integration

VS Code source lives as a git submodule at lib/vscode. code-server applies 23+ quilt patches on top (see Section 8.5) to adapt the desktop editor for web serving. The VS Code server module is loaded dynamically by the VS Code route handler (src/node/routes/vscode.ts), which delegates all editor-related requests to VS Code's own HTTP handling.


2. System Requirements

2.1 Hardware

Resource Minimum Recommended
CPU 1 core 2+ cores
RAM 1 GB 2+ GB (scales with extensions and open files)
Disk 1 GB (base install) 5+ GB (extensions, workspaces, user data)

Note

Memory consumption scales linearly with the number of open files, active extensions, and language server instances. A TypeScript project with several extensions can consume 2-4 GB.

2.2 Software

  • Node.js 22 (required, not optional)
  • Linux is the primary target (Debian, Ubuntu, Fedora, openSUSE have Dockerfiles)
  • macOS and Windows are supported but Linux is recommended for production
  • A modern browser (Chrome, Firefox, Edge, Safari) on the client side

2.3 Network

  • A single TCP port (default 8080) for HTTP/HTTPS and WebSocket traffic
  • Optionally a Unix socket instead of TCP
  • Outbound access to api.github.com for update checks (can be disabled)

3. Configuration Reference

3.1 Configuration Precedence

Configuration values are resolved in this order (highest wins):

  1. CLI flags (e.g., --auth none)
  2. Environment variables (e.g., PASSWORD=secret)
  3. Config file (config.yaml)
  4. Built-in defaults

3.2 Config File

The default config file location is {config_dir}/config.yaml. On first launch, code-server generates a default config with a random password:

bind-addr: 127.0.0.1:8080
auth: password
password: <randomly-generated>
cert: false

Override the config file path with --config <path> or $CODE_SERVER_CONFIG.

3.3 Complete CLI Reference

Flag Short Type Default Description
--auth password or none password Authentication type
--password string (auto-generated) Password for login. Set in config or $PASSWORD only, not command line.
--hashed-password string Argon2 hash of password. Takes precedence over --password. Set in config or $HASHED_PASSWORD only.
--cert optional string false Path to TLS certificate. If flag is present without a value, generates a self-signed cert.
--cert-host string localhost Hostname for self-signed certificate generation
--cert-key string Path to TLS private key. Required when --cert has a path value.
--disable-telemetry boolean false Disable telemetry
--disable-update-check boolean false Disable periodic update checks against GitHub releases
--session-socket string {data}/code-server-ipc.sock Path for the editor session IPC socket
--cookie-suffix string Suffix appended to cookie names. Also $CODE_SERVER_COOKIE_SUFFIX.
--disable-file-downloads boolean false Block file downloads. Also $CS_DISABLE_FILE_DOWNLOADS.
--disable-file-uploads boolean false Block file uploads
--disable-workspace-trust boolean false Disable the workspace trust prompt (session only)
--disable-getting-started-override boolean false Disable the Getting Started page override. Also $CS_DISABLE_GETTING_STARTED_OVERRIDE.
--disable-proxy boolean false Disable the built-in proxy routes. Also $CS_DISABLE_PROXY.
--help -h boolean Print help and exit
--link-protection-trusted-domains string[] Domains that skip link protection warnings
--locale string IETF language tag for UI localization
--open boolean false Open browser automatically (only works when bound to localhost)
--bind-addr string 127.0.0.1:8080 Address and port to bind. $PORT and $CODE_SERVER_HOST override the port and host components respectively.
--config string {config}/config.yaml Path to YAML config file. $CODE_SERVER_CONFIG.
--host string Deprecated — use --bind-addr
--port number Deprecated — use --bind-addr
--socket string Listen on a Unix socket instead of TCP. Overrides --bind-addr.
--socket-mode string File permissions for the Unix socket
--trusted-origins string[] Origins to allow. Supports * (all) and *.domain.com (wildcard subdomain).
--version -v boolean Print version and exit
--user-data-dir string {data} VS Code user data directory
--extensions-dir string {data}/extensions Extensions installation directory
--builtin-extensions-dir string Additional built-in extensions directory
--list-extensions boolean List installed extensions and exit
--force boolean Skip prompts during extension install
--locate-extension string[] Print the path of specified extensions
--category string Filter extensions by category
--install-extension string[] Install extensions. Format: publisher.name[@version] or path to .vsix
--enable-proposed-api string[] Enable proposed API for specified extensions
--uninstall-extension string[] Uninstall specified extensions
--show-versions boolean Show extension versions when listing
--github-auth string GitHub token for extension marketplace auth. Set in config or $GITHUB_TOKEN only.
--proxy-domain string[] Domain pattern for domain-based proxying. Format: prefix-{{port}}.domain.tld or {{port}}.domain.tld.
--skip-auth-preflight boolean false Allow OPTIONS requests without authentication (for CORS preflight)
--ignore-last-opened -e boolean false Do not reopen the last opened workspace
--new-window -n boolean false Open a new window
--reuse-window -r boolean false Reuse the existing window
--log enum Log level: trace, debug, info, warn, error. Also $LOG_LEVEL.
--verbose -vvv boolean false Sets log level to trace
--app-name -an string code-server Application name. Replaces the {{app}} placeholder in templates.
--welcome-text -w string Deprecated — Login page welcome text
--abs-proxy-base-path string Prefix prepended to absproxy requests
--i18n string Path to custom i18n JSON strings
--idle-timeout-seconds number Auto-shutdown after idle period. Must be >60. Also $CODE_SERVER_IDLE_TIMEOUT_SECONDS.
--reconnection-grace-time string 10800 (3 hours) Seconds to keep sessions alive for reconnection. Also $CODE_SERVER_RECONNECTION_GRACE_TIME.

Important

The --password, --hashed-password, and --github-auth flags cannot be passed on the command line for security reasons. They must be set via config file or environment variables. The corresponding environment variables (PASSWORD, HASHED_PASSWORD, GITHUB_TOKEN) are cleared from the process environment immediately after being read.

3.4 Complete Environment Variable Reference

Variable Purpose
PASSWORD Login password (cleared after read)
HASHED_PASSWORD Argon2 hashed password (cleared after read; takes precedence over PASSWORD)
GITHUB_TOKEN GitHub token for extension marketplace auth (cleared after read)
PORT Override the port component of --bind-addr
CODE_SERVER_HOST Override the host component of --bind-addr
CODE_SERVER_CONFIG Path to config file (overrides default)
CODE_SERVER_SESSION_SOCKET Path to session IPC socket
CODE_SERVER_COOKIE_SUFFIX Suffix for cookie names
CODE_SERVER_RECONNECTION_GRACE_TIME Reconnection grace period in seconds
CODE_SERVER_IDLE_TIMEOUT_SECONDS Idle shutdown timeout in seconds
LOG_LEVEL Log level (trace, debug, info, warn, error)
CS_DISABLE_FILE_DOWNLOADS Set to true or 1 to disable file downloads
CS_DISABLE_GETTING_STARTED_OVERRIDE Set to true or 1 to disable Getting Started override
CS_DISABLE_PROXY Set to true or 1 to disable proxy routes
EXTENSIONS_GALLERY JSON string for custom extensions marketplace configuration
VSCODE_PROXY_URI URI pattern for VS Code's Ports tab
HTTP_PROXY / http_proxy HTTP proxy for outbound connections
HTTPS_PROXY / https_proxy HTTPS proxy for outbound connections
NODE_ENV Set to development to enable i18n debug mode
DOCKER_USER Docker: rename the default coder user
ENTRYPOINTD Docker: directory of startup scripts to execute
CODE_SERVER_PARENT_PID Internal: parent process PID for VS Code CLI
VSCODE_IPC_HOOK_CLI Internal: VS Code CLI IPC socket path

3.5 Data Directory Layout

Platform Data Directory Config Directory Runtime Directory
Linux ~/.local/share/code-server ~/.config/code-server $XDG_RUNTIME_DIR/code-server or /tmp
macOS ~/.local/share/code-server ~/.config/code-server $XDG_RUNTIME_DIR/code-server or /tmp
Windows %APPDATA%/code-server %APPDATA%/code-server System temp directory

Note

macOS uses XDG-style paths, not native macOS ~/Library paths. This is intentional.

Key files within the data directory:

File/Directory Purpose
config.yaml Main configuration (in config dir, auto-generated on first run)
coder.json Settings file (last query, update check cache)
heartbeat Heartbeat timestamp file (written every 60 seconds)
code-server-ipc.sock Session manager IPC socket
extensions/ Installed VS Code extensions
serve-web-key-half Half of the encryption key for VS Code web

4. Deployment & Scaling

4.1 Standalone Installation

Download the latest release from GitHub Releases and run:

# Install script (Linux/macOS)
curl -fsSL https://code-server.dev/install.sh | sh

# Or manually extract and run
tar -xzf code-server-4.116.0-linux-amd64.tar.gz
./code-server-4.116.0-linux-amd64/bin/code-server

On first run, a config file is generated at ~/.config/code-server/config.yaml with a random password. The server listens on 127.0.0.1:8080 by default.

4.2 Docker Deployment

The official Docker image is codercom/code-server:4.116.0. Base images are available for Debian (default), Fedora, and openSUSE.

docker run -d \
  --name code-server \
  -p 8080:8080 \
  -v "$HOME/.local:/home/coder/.local" \
  -v "$HOME/.config:/home/coder/.config" \
  -v "$PWD:/home/coder/project" \
  -u "$(id -u):$(id -g)" \
  -e "DOCKER_USER=$USER" \
  codercom/code-server:4.116.0

Docker-specific behavior:

  • Default user: coder with UID 1000
  • DOCKER_USER: Renames the coder user to match your host user (for cleaner ps output and shell prompts)
  • ENTRYPOINTD: Directory of shell scripts executed during container startup (useful for installing system packages, pre-installing extensions, etc.)
  • Process supervisor: Uses dumb-init as PID 1 to handle signal forwarding and zombie reaping. An alternative catatonit is also available.
  • fixuid: Handles UID/GID remapping when the container user doesn't match the mounted volume ownership

Tip

For persistent data across container recreations, mount ~/.local/share/code-server (extensions, settings) and ~/.config/code-server (config file). Mount your project directory separately.

Docker Compose example:

services:
  code-server:
    image: codercom/code-server:4.116.0
    ports:
      - "8080:8080"
    volumes:
      - code-server-data:/home/coder/.local
      - code-server-config:/home/coder/.config
      - ./project:/home/coder/project
    environment:
      - DOCKER_USER=developer
      - PASSWORD=changeme
    restart: unless-stopped

volumes:
  code-server-data:
  code-server-config:

4.3 Kubernetes via Helm

The official Helm chart is at version 3.35.0 (appVersion 4.116.0).

helm repo add code-server https://helm.coder.com/code-server
helm install code-server code-server/code-server

Helm chart defaults:

Setting Default
Replicas 1
Service type ClusterIP
Service port 8080
PVC size 10Gi (ReadWriteOnce)
Security context UID 1000 / GID 1000
Liveness probe Enabled
Readiness probe Enabled
Volume permissions init container Enabled

Key values.yaml options:

# Extra CLI arguments
extraArgs:
  - --auth=none
  - --disable-telemetry

# Extra environment variables
extraVars:
  - name: EXTENSIONS_GALLERY
    value: '{"serviceUrl": "https://marketplace.example.com/_apis/public/gallery"}'

# Password from existing Kubernetes secret
existingSecret:
  name: code-server-secret
  key: password

# Pre-install extensions via init container
extraInitContainers:
  - name: install-extensions
    image: codercom/code-server:4.116.0
    command: ["sh", "-c", "code-server --install-extension ms-python.python"]
    volumeMounts:
      - name: data
        mountPath: /home/coder

# Sidecar container (e.g., Docker-in-Docker)
extraContainers:
  - name: docker-dind
    image: docker:dind
    securityContext:
      privileged: true

# Ingress
ingress:
  enabled: true
  hosts:
    - host: code.example.com
      paths:
        - /

# Additional volume mounts
extraVolumeMounts: []
extraSecretMounts: []

# Lifecycle hooks
lifecycle: {}

Warning

code-server is a single-user application. Each instance serves one user. Do not set replicas > 1 for a single user. For multi-user deployments, create one code-server instance per user (separate Helm releases or a platform like Coder).

4.4 Reverse Proxy Configuration

code-server requires WebSocket support from any reverse proxy. The following are minimal configurations for common proxies.

Nginx:

server {
    listen 443 ssl;
    server_name code.example.com;

    ssl_certificate     /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection upgrade;
        proxy_set_header Accept-Encoding gzip;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Traefik (Docker labels):

labels:
  - "traefik.enable=true"
  - "traefik.http.routers.code-server.rule=Host(`code.example.com`)"
  - "traefik.http.routers.code-server.tls.certresolver=letsencrypt"
  - "traefik.http.services.code-server.loadbalancer.server.port=8080"

Caddy:

code.example.com {
    reverse_proxy 127.0.0.1:8080
}

Important

When running behind a reverse proxy, set --bind-addr 0.0.0.0:8080 (or the appropriate internal interface) and configure --trusted-origins to include your domain. If you terminate TLS at the proxy, do not use --cert on code-server itself.

4.5 systemd Service

[Unit]
Description=code-server
After=network.target

[Service]
Type=simple
User=coder
Group=coder
Environment=PASSWORD=changeme
ExecStart=/usr/bin/code-server --bind-addr 0.0.0.0:8080
Restart=on-failure
RestartSec=10

[Install]
WantedBy=multi-user.target

4.6 Unix Socket Deployment

For reverse proxy setups where TCP isn't needed:

code-server --socket /run/code-server/code-server.sock --socket-mode 660

The reverse proxy connects to the Unix socket instead of a TCP port. This avoids port conflicts and can provide marginally better performance.


5. Operations

5.1 Health Monitoring

HTTP health check:

curl http://localhost:8080/healthz
# Response: {"status": "alive", "lastHeartbeat": <unix_timestamp>}

WebSocket health check: Connect a WebSocket to /healthz and send any message. The server responds with the same health JSON.

The heartbeat system writes a timestamp to {data}/heartbeat every 60 seconds. The /healthz endpoint returns the last heartbeat time, allowing external monitors to detect stalled processes (a running server that has stopped processing requests).

5.2 Update Management

By default, code-server checks GitHub releases for new versions periodically. The /update/check endpoint returns:

{
  "checked": 1735689600,
  "latest": "4.116.0",
  "current": "4.115.0",
  "isLatest": false
}

Disable this with --disable-update-check or CS_DISABLE_UPDATE_CHECK=true.

5.3 Extension Management

Extensions are managed via the CLI:

# Install an extension
code-server --install-extension ms-python.python

# Install a specific version
code-server --install-extension ms-python.python@2024.1.0

# Install from a .vsix file
code-server --install-extension ./my-extension.vsix

# List installed extensions
code-server --list-extensions --show-versions

# Uninstall
code-server --uninstall-extension ms-python.python

# Skip confirmation prompts
code-server --force --install-extension ms-python.python

Custom extension marketplace: By default, code-server uses the Open VSX Registry. To use a custom marketplace:

export EXTENSIONS_GALLERY='{"serviceUrl": "https://marketplace.example.com/_apis/public/gallery", "itemUrl": "https://marketplace.example.com/items"}'

Caution

The Microsoft Visual Studio Marketplace license prohibits use by non-Microsoft products. code-server uses Open VSX by default for this reason. Some extensions (GitHub Copilot, Microsoft-published extensions) may not be available on Open VSX. See known issue #7494 (Copilot Chat) and #7758 (Homebrew missing vscode.git extension).

5.4 Idle Timeout

Configure automatic shutdown after a period of inactivity:

code-server --idle-timeout-seconds 3600  # Shut down after 1 hour idle

The minimum value is 60 seconds. The idle timer resets on any browser activity that triggers the heartbeat. This is useful for cloud deployments where compute cost should be minimized.

5.5 Multi-Instance / Session Management

When code-server is already running and you invoke it with a file or folder argument, it uses the EditorSessionManager (via the IPC socket at {data}/code-server-ipc.sock) to open the file in the existing instance rather than starting a new server.

# Opens in the already-running instance
code-server /path/to/file.txt

Relevant flags:

  • --new-window / -n: Force a new window
  • --reuse-window / -r: Reuse existing window
  • --ignore-last-opened / -e: Don't reopen the last workspace

5.6 Logging

Control log verbosity:

code-server --log debug          # debug level
code-server --verbose            # trace level (most verbose)
LOG_LEVEL=warn code-server       # via environment

Levels: trace, debug, info, warn, error.

Log output goes to stdout/stderr. Use rotating-file-stream (a dependency) if log rotation is configured. In Docker, rely on Docker's logging drivers to manage log retention.

5.7 Localization

Specify a locale for UI strings:

code-server --locale ja

Custom strings can be provided via --i18n /path/to/strings.json. The i18n system uses i18next internally. Setting NODE_ENV=development enables i18n debug mode.


6. Performance

6.1 Resource Consumption

code-server's resource consumption is dominated by VS Code and its extensions, not by the code-server wrapper layer. Key factors:

  • Memory: Base ~200-400 MB. Each open workspace with language servers adds 100-500 MB. TypeScript projects with IntelliSense are the heaviest.
  • CPU: Mostly idle. Spikes during extension host operations (IntelliSense, linting, search).
  • Disk I/O: Extension installations, file watching, and search operations.
  • Network: WebSocket traffic between browser and server. Proportional to typing speed, terminal output, and extension activity.

6.2 Reconnection Grace Time

The --reconnection-grace-time flag (default: 10800 seconds = 3 hours) controls how long the server keeps a session alive after the browser disconnects. During this period, unsaved work and terminal sessions are preserved. Reduce this value in resource-constrained environments:

code-server --reconnection-grace-time 1800  # 30 minutes

6.3 Proxy Performance

The built-in proxy (/proxy/:port/* and /absproxy/:port/*) uses Node.js http-proxy. It rewrites redirect headers for path-based proxying. For high-throughput proxied services, consider exposing them directly rather than routing through code-server's proxy.

6.4 Tuning Tips

  • Disable unused features: --disable-telemetry, --disable-update-check to reduce background network calls
  • Limit extensions: Each extension consumes memory and potentially CPU; install only what's needed
  • File watching: Large projects with many files can exhaust inotify watchers on Linux. Increase fs.inotify.max_user_watches:
echo "fs.inotify.max_user_watches=524288" | sudo tee /etc/sysctl.d/40-code-server.conf
sudo sysctl --system

7. Security

7.1 Authentication

code-server supports two authentication modes:

Mode Flag Behavior
password (default) --auth password Login page with password prompt
none --auth none No authentication — anyone with network access can use the editor

Caution

Setting --auth none gives full shell and file access to anyone who can reach the server. Never use this on a network-accessible instance without additional access control (VPN, SSH tunnel, reverse proxy with its own auth).

7.2 Password Storage

Passwords are stored and verified using one of three methods, determined by getPasswordMethod() based on the hash format:

Method Format Security
Argon2 (recommended) Hash starts with $argon Memory-hard, resistant to GPU/ASIC attacks
SHA256 (legacy) 64-character hex string Fast hash, not recommended for passwords
Plain text Anything else No hashing, comparison only

Generate an argon2 hash:

# Using npx
npx argon2-cli -e "your-password"

# Set in config
hashed-password: "$argon2i$v=19$m=4096,t=3,p=1$..."

Warning

Known issue #7696: If an attacker obtains the hashed password value, they can potentially use it directly to authenticate without knowing the plaintext. Store your config file with restrictive permissions (chmod 600 ~/.config/code-server/config.yaml).

7.3 Login Rate Limiting

The login endpoint is protected by a RateLimiter class (using the limiter library) with two limits:

  • 2 attempts per minute (burst protection)
  • 12 attempts per hour (sustained brute-force protection)

These limits are hard-coded and not configurable.

7.4 Origin Validation and CSRF Protection

  • HTTP requests: The server validates the Origin header against the Host header. Mismatches are rejected unless the origin is in --trusted-origins.
  • WebSocket connections: Origin checking prevents cross-site WebSocket hijacking.
  • --trusted-origins: Accepts exact domains, * (allow all), or *.domain.com (wildcard subdomain matching).
  • --skip-auth-preflight: Allows OPTIONS requests without authentication, required for CORS preflight in some proxy setups.

7.5 Session Management

  • Sessions use HTTP cookies with sameSite=lax
  • Cookie domain is derived from the highest-level proxy domain (if configured)
  • Cookie path is scoped to the base path
  • --cookie-suffix allows disambiguating cookies when running multiple instances on the same domain

7.6 Sensitive Environment Variable Handling

The following environment variables contain secrets and are cleared from process.env immediately after being read by the CLI parser:

  • PASSWORD
  • HASHED_PASSWORD
  • GITHUB_TOKEN

This prevents accidental leakage via child processes, /proc/*/environ, or crash dumps.

7.7 TLS Configuration

Self-signed certificate (development/testing):

code-server --cert
# Generates a self-signed cert for --cert-host (default: localhost)

Bring your own certificate (production):

code-server --cert /path/to/cert.pem --cert-key /path/to/key.pem

When --cert is configured:

  • The server uses httpolyglot to serve both HTTP and HTTPS on the same port
  • HTTP requests are automatically redirected to HTTPS
  • The TLS redirect middleware is injected into the route chain

For production, terminate TLS at a reverse proxy (nginx, Traefik, Caddy) rather than using code-server's built-in TLS.

7.8 Proxy Security

The built-in proxy routes (/proxy/:port/*, /absproxy/:port/*, and domain-based proxy) require authentication. This means that services running on the same host are only accessible through code-server to authenticated users.

Disable the proxy entirely with --disable-proxy if it's not needed.

7.9 File Transfer Controls

code-server --disable-file-downloads  # Prevent downloading files
code-server --disable-file-uploads    # Prevent uploading files

These flags are useful in environments where data exfiltration or introduction of unauthorized files is a concern.

7.10 Security Hardening Checklist

  1. Use --auth password with an argon2 hashed password
  2. Restrict config file permissions: chmod 600 ~/.config/code-server/config.yaml
  3. Bind to localhost (127.0.0.1) and use a reverse proxy with TLS for external access
  4. Set --trusted-origins to your specific domain(s), never * in production
  5. Use --disable-proxy if the proxy feature is not needed
  6. Use --disable-file-downloads and --disable-file-uploads if file transfer is not required
  7. Run as a non-root user (the Docker image defaults to UID 1000)
  8. Keep code-server updated (or disable update checks and manage updates externally)
  9. Increase fs.inotify.max_user_watches for Linux deployments to prevent DoS via file watching exhaustion

8. Developer Internals

8.1 Build System

The build process involves three main steps:

  1. Compile TypeScript: src/ is compiled to JavaScript
  2. Build VS Code: The lib/vscode submodule is built with patches applied
  3. Package: The result is packaged into distributable tarballs or Docker images

Quilt patches in patches/ are applied to the VS Code submodule before building. These patches adapt the desktop VS Code for web serving (see Section 8.5).

8.2 Entry Point Dispatch Logic

src/node/entry.ts follows this decision tree:

entry.ts
  ├─ Is this a child process (--child flag)?
  │   └─ Yes → Handshake with parent via IPC, run server directly
  │
  ├─ Is --help or --version?
  │   └─ Yes → Print and exit
  │
  ├─ Is an extension flag present (--install-extension, etc.)?
  │   └─ Yes → runCodeCli() — spawns VS Code CLI subprocess
  │
  ├─ Is a file/folder argument with an existing instance?
  │   └─ Yes → openInExistingInstance() via IPC socket
  │
  └─ Otherwise → wrapper.start(args) — spawn child process

8.3 Server Creation (app.ts)

createApp() in src/node/app.ts:

  1. Creates an Express router
  2. If --cert is configured: creates an httpolyglot server (serves HTTP + HTTPS on the same port)
  3. Otherwise: creates a plain http.createServer
  4. Creates a separate wsRouter for WebSocket handling via the handleUpgrade mechanism
  5. Creates an EditorSessionManager server on a separate Unix socket for IPC between instances
  6. Returns { router, wsRouter, server, dispose() }

8.4 Route Registration (routes/index.ts)

The route registration in src/node/routes/index.ts follows this exact order:

  1. Heartbeat system: Starts writing to {data}/heartbeat every 60 seconds
  2. Cookie parser: Parses cookies on all requests
  3. Common middleware: Injects args, heart, settings, updater, cookieSessionName into the request object
  4. TLS redirect: If --cert is configured, redirects HTTP to HTTPS
  5. Static files: /_static serves static assets (no auth required)
  6. Domain proxy: Checked first via hostname matching against --proxy-domain patterns
  7. Path proxy: /proxy/:port/* (rewriting) and /absproxy/:port/* (passthrough)
  8. Health check: /healthz (HTTP GET and WebSocket)
  9. Login/logout: /login and /logout (only mounted when --auth password)
  10. Update check: /update/check
  11. VS Code: Mounted at both /vscode and / (dual prefix for legacy compatibility)
  12. 404 catch-all: Returns error page
  13. Error handlers: Separate handlers for HTTP and WebSocket errors

8.5 VS Code Patches

The patches/ directory contains 23+ quilt patches applied to the VS Code submodule. Each patch adapts a specific VS Code behavior for the browser-served context:

Patch Purpose
base-path Support for serving behind a sub-path
cli-window-open Adapt window opening for browser
clipboard Browser clipboard integration
copilot Copilot compatibility adjustments
disable-builtin-ext-update Prevent built-in extensions from self-updating
display-language Display language / locale support
external-file-actions Handle external file operations in browser
getting-started Custom Getting Started page
insecure-notification Suppress insecure-connection warnings
integration Core integration with code-server's HTTP layer
keepalive WebSocket keepalive for long connections
local-storage Browser localStorage adaptations
logout Add logout functionality
marketplace Extension marketplace (Open VSX) integration
proposed-api Enable proposed API support
proxy-uri Proxy URI handling for ports tab
service-worker PWA service worker
signature-verification Extension signature verification handling
sourcemaps Source map handling for debugging
store-socket Store socket path for IPC
telemetry Telemetry handling
trusted-domains Link protection and trusted domains
unique-db Unique database paths per instance
update-check Update notification integration
webview Webview resource handling for browser

8.6 Key Internal Modules

src/node/http.ts — HTTP utilities:

  • authenticated(): Checks cookie session for valid authentication
  • ensureAuthenticated(): Middleware that redirects to login if not authenticated
  • ensureOrigin(): Validates Origin header against Host and trusted origins
  • redirect(): Constructs redirect responses with proper base path handling
  • replaceTemplates(): Replaces {{CS_*}}, {{BASE}}, {{APP_NAME}} placeholders in HTML

src/node/proxy.ts — Proxy server:

  • Creates an http-proxy instance
  • Rewrites Location headers in redirect responses to maintain path-based routing
  • Handles both HTTP and WebSocket proxying

src/node/heart.ts — Heartbeat:

  • Heart class writes the current timestamp to {data}/heartbeat every 60 seconds
  • beat() is called on activity events
  • alive() returns the last heartbeat timestamp

src/node/settings.ts — Settings:

  • SettingsProvider<T> reads and writes JSON settings files
  • Used for coder.json (update check cache, last query time)

src/node/update.ts — Update provider:

  • UpdateProvider checks GitHub releases for newer versions
  • Caches the result to avoid excessive API calls
  • Compares versions using the semver library

src/common/emitter.ts — Emitter:

  • Emitter<T> provides type-safe event emitting with async support
  • Used throughout for internal event communication

8.7 WebSocket Router

src/node/wsRouter.ts provides WebSocket routing on top of Express. Since Express does not natively handle WebSocket upgrades, this module intercepts upgrade events on the HTTP server and routes them through a parallel set of route handlers that mirror the Express routing pattern.

8.8 Testing

Test Type Location Framework
Unit tests test/unit/ Jest + ts-jest
Script tests test/scripts/ bats (Bash Automated Testing System)
Integration tests test/integration/ Jest
E2E tests test/e2e/ Playwright
  • Coverage threshold: 60% line coverage minimum
  • Test isolation: Tests have their own package.json (test/package.json) to avoid type conflicts with the VS Code submodule's TypeScript types
  • E2E auth state: globalSetup preserves authentication state across Playwright tests
# Run unit tests
npm test

# Run e2e tests
npx playwright test

# Run script tests (requires bats)
bats test/scripts/

8.9 Project Structure

code-server/
├── src/
│   ├── node/              # Server-side TypeScript
│   │   ├── entry.ts       # Main entry point
│   │   ├── cli.ts         # CLI argument parser
│   │   ├── app.ts         # Express + HTTP server factory
│   │   ├── wrapper.ts     # Parent/child process management
│   │   ├── routes/        # Route handlers
│   │   │   ├── index.ts   # Route registration
│   │   │   ├── vscode.ts  # VS Code delegation
│   │   │   ├── login.ts   # Authentication
│   │   │   ├── health.ts  # Health check
│   │   │   ├── pathProxy.ts
│   │   │   ├── domainProxy.ts
│   │   │   └── errors.ts
│   │   ├── http.ts        # HTTP utilities
│   │   ├── proxy.ts       # Proxy server
│   │   ├── heart.ts       # Heartbeat
│   │   ├── settings.ts    # JSON settings
│   │   ├── update.ts      # Update checker
│   │   ├── util.ts        # Utilities
│   │   ├── constants.ts   # Version, paths
│   │   ├── socket.ts      # TLS socket proxy
│   │   ├── vscodeSocket.ts # Session IPC
│   │   ├── wsRouter.ts    # WebSocket router
│   │   └── i18n/          # Localization
│   ├── common/            # Shared code (server + browser)
│   │   ├── emitter.ts
│   │   ├── http.ts
│   │   └── util.ts
│   └── browser/           # Browser-side code
│       └── serviceWorker.ts
├── lib/
│   └── vscode/            # VS Code submodule (git submodule)
├── patches/               # Quilt patches for VS Code
├── test/
│   ├── unit/
│   ├── integration/
│   ├── e2e/
│   ├── scripts/
│   └── package.json       # Separate test dependencies
├── ci/                    # CI/CD configuration
└── docs/                  # Documentation

9. Integration Points

9.1 HTTP API Reference

All endpoints served by code-server:

Method Path Auth Required Response
GET /healthz No {"status": "alive", "lastHeartbeat": <timestamp>}
WS /healthz No Send any message, receive health JSON
GET /login No HTML login page
POST /login No Validates password, sets session cookie, redirects
GET /logout No Clears session cookie, redirects to login
GET /update/check Yes {"checked": <ts>, "latest": "x.y.z", "current": "x.y.z", "isLatest": bool}
GET /manifest.json No PWA manifest
POST /mint-key No VS Code web encryption key
GET /robots.txt No Robots exclusion
GET /security.txt No Security contact information
ALL /proxy/:port/* Yes Path-based proxy with URL rewriting
ALL /absproxy/:port/* Yes Absolute path proxy (no rewriting)
ALL /* (domain proxy) Yes Domain-based proxy via --proxy-domain matching
GET /vscode/* Yes VS Code web client (legacy prefix)
GET /* Yes VS Code web client (primary)
GET /_static/* No Static assets

9.2 Proxy Modes

code-server provides three proxy modes for accessing services running on the same host:

Path-based proxy (/proxy/:port/*):

  • Rewrites URLs in responses to maintain correct routing
  • Example: https://code.example.com/proxy/3000/ proxies to localhost:3000
  • Rewrites Location headers in redirects

Absolute path proxy (/absproxy/:port/*):

  • Passes requests through without URL rewriting
  • Configured base path via --abs-proxy-base-path
  • Useful when the proxied application handles its own path prefix

Domain-based proxy (--proxy-domain):

  • Routes based on hostname matching
  • Format: prefix-{{port}}.domain.tld or {{port}}.domain.tld
  • Example: --proxy-domain "{{port}}.proxy.example.com" routes 3000.proxy.example.com to localhost:3000
  • Requires wildcard DNS and TLS certificate

The VSCODE_PROXY_URI environment variable integrates with VS Code's Ports tab, allowing forwarded ports to appear in the VS Code UI.

9.3 Extension Marketplace

By default, code-server connects to the Open VSX Registry. Override with the EXTENSIONS_GALLERY environment variable:

export EXTENSIONS_GALLERY='{
  "serviceUrl": "https://marketplace.example.com/_apis/public/gallery",
  "itemUrl": "https://marketplace.example.com/items"
}'

9.4 GitHub Integration

The --github-auth / $GITHUB_TOKEN setting provides a token that VS Code extensions can use for GitHub API authentication (e.g., for GitHub Pull Requests extension). The token is cleared from the environment after being read.

9.5 PWA Support

code-server includes a minimal service worker (src/browser/serviceWorker.ts) and PWA manifest (/manifest.json), allowing it to be installed as a Progressive Web App on supported browsers. This provides an app-like experience with its own window and taskbar icon.

9.6 IPC and Session Management

The EditorSessionManager (in src/node/vscodeSocket.ts) listens on a Unix socket ({data}/code-server-ipc.sock) and enables:

  • Opening files in an existing instance from the command line
  • Window management (--new-window, --reuse-window)
  • Session discovery

Appendix A: Troubleshooting

A.1 Cannot find module 'argon2'

Error: Cannot find module 'argon2' on startup.

Cause: The argon2 native module failed to compile or is missing for the current platform/architecture.

Solution: Reinstall dependencies with npm rebuild argon2 or use a SHA256 hashed password as a workaround. The Docker image includes pre-built argon2 binaries.

Prevention: Use the official release binaries or Docker image, which include pre-compiled native modules.

Reference: GitHub issue #7588 (closed/resolved).

A.2 Copilot Chat Not Working

Error: GitHub Copilot Chat extension fails to activate or respond.

Cause: Copilot extensions may require specific VS Code APIs or authentication flows that differ between desktop VS Code and code-server's web environment.

Solution: Ensure you are using the latest code-server version. Check that the Copilot patch is applied correctly. Some Copilot features may have limited support in the web context.

Reference: GitHub issue #7494.

A.3 Extension Not Found or Wrong Version Installed

Error: CLI installs an older extension version than expected.

Cause: The Open VSX Registry may not have the latest version of the extension, or the version resolution differs from the VS Code Marketplace.

Solution: Specify the exact version: code-server --install-extension publisher.name@x.y.z. Alternatively, download the .vsix file directly and install it: code-server --install-extension ./extension.vsix.

Reference: GitHub issue #7631.

A.4 Always Asks to Trust Workspace

Error: The workspace trust dialog appears every time.

Cause: Workspace trust state may not persist correctly in certain configurations.

Solution: Use --disable-workspace-trust to suppress the dialog entirely.

Reference: GitHub issue #7703.

A.5 Dynamic Webview Resources Fail

Error: Webview content (e.g., extension UI panels) fails to load in some browsers.

Cause: Browser security policies or proxy configurations interfere with dynamically loaded webview resources.

Solution: Ensure your reverse proxy passes all required headers and does not strip or modify content. Check browser console for CSP or network errors.

Reference: GitHub issue #3410.

A.6 Random Text Insertion

Error: Random characters appear in the editor.

Cause: Input method or keyboard event handling differences between browser and native VS Code.

Solution: Update to the latest version. Try a different browser. Disable browser extensions that intercept keyboard events.

Reference: GitHub issue #7707.

A.7 --app-name Does Not Set Page Title

Error: Setting --app-name changes the login page branding but not the browser tab title.

Cause: The page title is controlled by VS Code's internal logic, not the --app-name template replacement.

Reference: GitHub issue #7688.

A.8 Security Vulnerabilities (Snyk)

Error: Snyk or other vulnerability scanners report issues.

Cause: Transitive dependencies may have known vulnerabilities.

Solution: Update to the latest code-server release, which periodically updates dependencies. Review the specific CVEs reported and assess whether they are exploitable in your deployment context.

Reference: GitHub issue #7737.


Appendix B: What Does NOT Exist

This section explicitly documents what code-server does not have, to prevent assumptions:

  • No CLI subcommands: code-server uses a flat flag-based CLI parser, not a subcommand structure
  • No built-in API beyond the routes listed in Section 9.1: There is no REST API for managing users, workspaces, or settings programmatically
  • No database: All state is file-based (config YAML, JSON settings, filesystem)
  • No background job queue: Everything is synchronous request/response or WebSocket
  • No plugin system: An earlier version (v1) had a plugin API; it was removed. Extensions are VS Code extensions, not code-server plugins.
  • No multi-user support: Each instance serves exactly one user. Multi-user requires multiple instances (or a platform like Coder).
  • No built-in OAuth/SSO: Authentication is password-only. Use a reverse proxy (oauth2-proxy, Authelia, etc.) for SSO.
  • No native macOS paths: macOS uses XDG-style paths (~/.local/share, ~/.config), not ~/Library.