Best Practices for Configuring code-server Behind a Reverse Proxy
Running code-server behind a reverse proxy is the recommended method for secure internet exposure, requiring proper TLS termination, Host header forwarding, and WebSocket support while leveraging code-server's built-in proxy module for port routing.
Deploying code-server from the coder/code-server repository behind a reverse proxy such as NGINX, Caddy, or Traefik provides enterprise-grade security and flexible routing. This architecture places the proxy at the network edge to handle encryption and authentication, while the internal code-server process serves the VS Code web interface on a local port. Understanding the interaction between these components ensures reliable WebSocket connections and correct URL generation for proxied services.
Architectural Overview
When running code-server behind a reverse proxy, three primary components handle the request flow:
- code-server (listening on
127.0.0.1:8080by default): Serves the VS Code web UI and provides built-in proxying for other local services via/proxy/<port>/or/absproxy/<port>/endpoints. It validates theOriginheader on WebSocket upgrades. - Reverse proxy (NGINX, Caddy, Traefik): Terminates TLS, sets correct
HostandX-Forwarded-Protoheaders, rewrites request paths when serving from sub-paths, forwards WebSocket upgrades, and optionally enforces additional authentication. - Client browser: Connects to
https://<your-domain>, receives a valid certificate from the proxy, and communicates with the local code-server instance through the proxy tunnel.
Core Proxy Settings in code-server
The proxy implementation resides in src/node/proxy.ts, which creates an HTTP proxy server, rewrites absolute redirects when a base path is set, and provides custom error handling. The test suite in test/unit/node/proxy.test.ts validates critical behaviors including disabled proxy responses, base-path handling, and WebSocket origin checks.
Configure code-server using these flags and environment variables:
--proxy-domain <domain>: Enables sub-domain proxying. When a request arrives for8080.<domain>, code-server rewrites internal redirects to include the host header. This logic processes responses viaproxy.on("proxyRes")in the source file.VSCODE_PROXY_URI: Overrides the default/proxy/<port>/behavior. Setting this tohttps://{{port}}.example.devcauses the Ports panel to generate external URLs instead of local paths.--disable-proxy: Disables the built-in/proxyendpoint entirely, returning 403 Forbidden for all proxy requests (validated in the unit test "should return 403 Forbidden if proxy is disabled").--auth=none: Disables code-server's built-in authentication. Use this only when your reverse proxy already handles identity verification.
Essential Reverse Proxy Configuration
Follow these steps to ensure reliable operation:
- Terminate TLS at the proxy: Use certificates from Let's Encrypt or a corporate CA. Avoid self-signed certificates in production environments as they break certain mobile browsers.
- Forward the original Host header: Set
proxy_set_header Host $http_host;in NGINX or equivalent so code-server can generate correct absolute URLs and validate WebSocket origins. - Enable WebSocket support: Forward
UpgradeandConnectionheaders unchanged. code-server rejects connections that fail origin validation against the Host header (seetest/unit/node/proxy.test.tslines 72-88). - Handle sub-path routing: When serving from a sub-path like
/code/, configure the proxy to strip the prefix before forwarding (e.g.,uri strip_prefix /codein Caddy). - Configure proxy-domain for sub-domains: Use
code-server --proxy-domain example.comwhen routing8080.example.comto local ports so redirects preserve the host header. - Set VSCODE_PROXY_URI for external proxies: Export this variable before launching code-server if you want the Ports panel to reference an external proxy infrastructure.
Implementation Examples
Caddy Configuration (Sub-path)
For serving code-server under a sub-path, strip the prefix before proxying (as documented in docs/guide.md lines 41-56):
mydomain.com {
reverse_proxy 127.0.0.1:8080
}
# Serve under /code/ (strip prefix)
mydomain.com/code/* {
uri strip_prefix /code
reverse_proxy 127.0.0.1:8080
}
NGINX Configuration (HTTPS)
Standard HTTPS configuration with WebSocket support (see docs/guide.md lines 90-101):
server {
listen 80;
server_name mydomain.com;
location / {
proxy_pass http://localhost:8080/;
proxy_set_header Host $http_host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Accept-Encoding gzip;
}
}
Sub-domain Proxying with code-server
Launch code-server with the proxy domain flag to handle sub-domain routing:
code-server --proxy-domain example.com
With this configuration, requests to 8080.example.com proxy to the local service on port 8080, and redirects sent by the target are rewritten to preserve the host header (handled in src/node/proxy.ts lines 21-27).
Custom External Proxy URI
To override the default port proxying behavior:
export VSCODE_PROXY_URI="https://{{port}}.mycompany.dev"
code-server
The Ports panel will now generate URLs like https://3000.mycompany.dev instead of the default /proxy/3000/ path.
Security Considerations
- Origin validation: code-server validates that WebSocket
Originheaders match the requestHostheader. Ensure your proxy forwards the original Host header to prevent connection failures. - Disable unused features: If you do not require the built-in port proxying, start code-server with
--disable-proxyto prevent accidental exposure of internal services. - Certificate trust: While self-signed certificates work for local testing (documented in the self-signed certificate section of the guide), production deployments require certificates trusted by all client browsers.
Summary
- Reverse proxy placement: Always position NGINX, Caddy, or Traefik in front of code-server for TLS termination and security hardening.
- Header forwarding: Preserve the original
Hostheader and WebSocket upgrade headers to ensure code-server functions correctly behind the proxy. - Path handling: Strip sub-path prefixes at the proxy layer when serving code-server from non-root paths.
- Sub-domain support: Use
--proxy-domainandVSCODE_PROXY_URIto customize how code-server generates URLs for proxied ports. - Security hardening: Disable the built-in proxy with
--disable-proxywhen not needed, and rely on the reverse proxy for authentication via--auth=noneonly in trusted environments.
Frequently Asked Questions
Do I need to configure WebSocket support separately when running code-server behind a reverse proxy?
Yes. You must explicitly forward the Upgrade and Connection headers through your proxy configuration. According to test/unit/node/proxy.test.ts, code-server validates WebSocket upgrade requests against the Origin header, which requires the original Host header to be preserved for the check to pass.
How do I serve code-server from a sub-path like /code/?
Configure your reverse proxy to strip the path prefix before forwarding requests. In Caddy, use uri strip_prefix /code inside the site block. In NGINX, use a location block with proxy_pass and ensure the X-Forwarded-Prefix header is set if your application logic depends on it.
What is the difference between --proxy-domain and VSCODE_PROXY_URI?
The --proxy-domain flag enables code-server to rewrite redirects for sub-domain proxying (e.g., 8080.example.com) by processing the host header in src/node/proxy.ts. VSCODE_PROXY_URI is an environment variable that changes the URL format displayed in the Ports panel, allowing you to route traffic through an entirely separate external proxy infrastructure.
Can I disable code-server's built-in authentication when using a reverse proxy?
Yes. Set --auth=none when your reverse proxy handles authentication via OAuth, mutual TLS, or other identity providers. This configuration is common in enterprise deployments where the edge proxy manages all authentication concerns.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →