Installing code-server on Ubuntu: Run VS Code in Your Browser with HTTPS and Nginx

Ubuntu tutorial - IT technology blog
Ubuntu tutorial - IT technology blog

When Do You Need code-server?

I started using code-server when I had to debug a staging server from an iPad at a coffee shop — VS Code couldn’t be installed directly, and the codebase lived on a VPS. After trying a few remote IDE solutions, code-server became my go-to because it’s straightforward: it is VS Code, loading directly in the browser, with full extensions, an integrated terminal, and nothing extra to install on the client side.

code-server is a good fit when you:

  • Code from multiple devices (laptop, iPad, work computer)
  • Want to leverage a more powerful VPS for building and compiling instead of your local machine
  • Need a dev environment that mirrors production as closely as possible — same OS, same dependencies
  • Have teammates who need to review code directly on the server without passing files back and forth

Installing code-server

System Requirements

Ubuntu 20.04 or 22.04 (LTS). Minimum 1GB RAM — though in practice, the TypeScript language server alone can consume 300–500MB, so if you’re running multiple extensions simultaneously, 2GB is where things get comfortable. You’ll need at least 2GB of free disk space; with extensions and workspaces added, 5GB is a safer target. Bandwidth requirements are low — 1 Mbps is plenty for normal use.

Quick Install via Script

curl -fsSL https://code-server.dev/install.sh | sh

The script auto-detects your distro, adds the appropriate package repo, and installs the binary. On Ubuntu it uses apt; on Fedora it uses dnf — no manual intervention needed. Once done, verify the version:

code-server --version

Manual Install via .deb (When You Need Version Control)

VERSION="4.95.3"
wget https://github.com/coder/code-server/releases/download/v${VERSION}/code-server_${VERSION}_amd64.deb
sudo dpkg -i code-server_${VERSION}_amd64.deb

Detailed Configuration

Default Config File

Run it once to generate the config file:

code-server --config ~/.config/code-server/config.yaml

The default content will look like this:

bind-addr: 127.0.0.1:8080
auth: password
password: your-password-here
cert: false

Important: Keep bind-addr: 127.0.0.1 — this restricts connections to localhost only. Nginx will handle exposing it externally with HTTPS. Don’t bind directly to 0.0.0.0 without SSL in place.

Generate a stronger random password:

PASSWORD=$(openssl rand -base64 16)
echo "Your password: $PASSWORD"
sed -i "s/password: .*/password: $PASSWORD/" ~/.config/code-server/config.yaml

Running code-server as a systemd Service

sudo systemctl enable --now code-server@$USER
sudo systemctl status code-server@$USER

Configuring Nginx as a Reverse Proxy

This is where most people run into issues. code-server uses WebSockets to sync the editor in real time, so Nginx needs the Upgrade header — without it, the editor will load but the terminal and live sync won’t work.

Create the Nginx config file:

sudo nano /etc/nginx/sites-available/code-server
server {
    listen 80;
    server_name code.yourdomain.com;
    return 301 https://$host$request_uri;
}

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

    ssl_certificate /etc/letsencrypt/live/code.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/code.yourdomain.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

    location / {
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection upgrade;
        proxy_set_header Accept-Encoding gzip;
        proxy_http_version 1.1;
    }
}

Enable the site, test the config, then reload:

sudo ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Hardening Security

code-server has password authentication by default, but this editor gives you a terminal directly on the server — if it gets compromised, you lose the whole machine. I usually add a few extra layers to be safe:

Restrict access by IP (if you’re connecting from a fixed IP):

location / {
    allow 203.0.113.10;   # Your IP
    deny all;
    proxy_pass http://localhost:8080/;
    proxy_set_header Host $host;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection upgrade;
    proxy_http_version 1.1;
}

Add HTTP Basic Auth (defense in depth — two layers of authentication):

sudo apt install apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd your_username

Add to the location block in Nginx:

auth_basic "Code Server";
auth_basic_user_file /etc/nginx/.htpasswd;

My final setup on staging: IP whitelist + basic auth + code-server password. Three layers might seem like overkill, but when it’s a terminal with root access on a server, I’m not willing to take chances.

Testing and Monitoring

Testing the Connection and WebSockets

Visit https://code.yourdomain.com — enter your password and VS Code loads right in the browser. If the editor loads but the terminal doesn’t respond, WebSockets are likely being blocked. Check the Nginx logs:

# HTTP 101 = WebSocket handshake successful
sudo tail -f /var/log/nginx/access.log | grep " 101 "

Viewing code-server Logs

# Follow service logs in real time
sudo journalctl -u code-server@$USER -f

# Enable verbose logging for debugging
code-server --log-level debug

Monitoring Resource Usage

TypeScript, ESLint, and Pylance can be surprisingly memory-hungry — the TypeScript language server alone can take up 300–500MB on large projects. Monitor usage with:

ps aux | grep code-server | awk '{print $2, $4, $6, $11}'

Only have 1GB of RAM? Limit the Node.js process memory:

sudo systemctl edit code-server@$USER

Paste in:

[Service]
Environment="NODE_OPTIONS=--max-old-space-size=512"
Restart=on-failure
RestartSec=5s

Apply the changes:

sudo systemctl daemon-reload
sudo systemctl restart code-server@$USER

Daily Usage Tips

  • Sync settings via GitHub: Enable Settings Sync in VS Code and sign in with GitHub — extensions and settings automatically sync between your local machine and code-server, no need to reinstall from scratch
  • Built-in port forwarding: When developing a web app on the server and need to preview it locally, use the Ports tab in the bottom panel of the editor — forward ports without needing a manual SSH tunnel
  • Use a dedicated subdomain: Host code-server at code.domain.com rather than a path like domain.com/code — this avoids issues with extensions that rely on Service Workers
  • Regular backups: The ~/.local/share/code-server/ directory contains your installed extensions and workspace state — backing this up is enough for a quick restore when needed

Share: