A remote VPS is one of the best development environments you can set up. Your code runs on a powerful Linux machine with fast internet, consistent dependencies, and no drain on your laptop's battery or CPU. VS Code's Remote - SSH extension makes this seamless — you edit files locally in a native VS Code window while all execution, linting, and debugging happens on the server.
This guide covers the complete remote development workflow: configuring SSH for fast, secure connections, setting up the VS Code Remote - SSH extension, installing development tools on your VPS, using port forwarding for local preview, running Dev Containers remotely, and setting up code-server as a browser-based alternative. By the end, you'll have a portable development environment that works from any machine with just an SSH key.
Prerequisites
Before starting, you need:
- An Ubuntu 24.04 VPS. For development workloads, deploy a Cloud VPS with 2 vCPU / 4 GB RAM — this handles multiple language runtimes, Docker containers, and background services comfortably. If you compile large projects regularly, consider 4 vCPU / 8 GB RAM.
- Root or sudo access. Follow our Ubuntu VPS setup guide and security hardening guide to configure a non-root user with SSH key authentication.
- VS Code installed locally. Download from code.visualstudio.com (Windows, macOS, or Linux).
- An SSH key pair. If you don't have one, our setup guide covers key generation.
MassiveGRID Ubuntu VPS — Ubuntu 24.04 LTS pre-installed, Proxmox HA cluster with automatic failover, Ceph 3x replicated NVMe storage, independent CPU/RAM/storage scaling, 12 Tbps DDoS protection, 4 global datacenter locations, 100% uptime SLA, and 24/7 human support rated 9.5/10. Deploy a self-managed VPS from $1.99/mo.
Why Develop on a Remote VPS
Before diving into setup, here's why remote development on a VPS is increasingly popular:
- Consistent environment. Every team member works on the same OS, same package versions, same architecture. No "works on my machine" issues.
- More resources. A VPS can have more RAM, faster storage (NVMe), and more CPU cores than a typical laptop — especially relevant for compilation, Docker, and database workloads.
- Always-on. Long-running processes (builds, tests, database migrations) continue even when you close your laptop. Reconnect later and pick up where you left off.
- Fast internet. Your VPS has a datacenter-grade connection. Pulling Docker images, downloading dependencies, and cloning large repos happens at server speed, not your home WiFi speed.
- Thin client. All you need locally is VS Code and an SSH key. Switch between a powerful desktop, a Chromebook, or a tablet with a keyboard — the experience is identical.
- Security. Source code never leaves the server. You connect via SSH, and the code stays on the VPS.
SSH Configuration for Fast Connections
A well-configured SSH config file makes connecting to your VPS instant and reliable. Edit (or create) your local SSH config:
# On your local machine
nano ~/.ssh/config
Add an entry for your VPS:
Host dev
HostName 203.0.113.50
User deploy
Port 22
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes
TCPKeepAlive yes
AddKeysToAgent yes
Now you can connect with just:
ssh dev
Explanation of each directive:
| Directive | Purpose |
|---|---|
Host dev |
Alias — use ssh dev instead of the full command |
HostName |
Your VPS IP address or domain |
User |
SSH username (use a non-root user) |
IdentityFile |
Path to your private SSH key |
ForwardAgent |
Forward your SSH agent to the remote — lets you use your local SSH keys for Git on the VPS |
ServerAliveInterval |
Send a keepalive every 60 seconds to prevent disconnections |
ServerAliveCountMax |
Allow 3 missed keepalives before disconnecting (3 min tolerance) |
Compression |
Compress SSH traffic — helpful for high-latency connections |
AddKeysToAgent |
Automatically add the key to your SSH agent |
SSH Connection Multiplexing
SSH multiplexing reuses a single TCP connection for multiple SSH sessions. This makes new connections to the same host nearly instant (no handshake delay) and is especially useful because VS Code opens multiple SSH channels.
Add these directives to your SSH config, either globally or under the specific Host entry:
Host dev
HostName 203.0.113.50
User deploy
IdentityFile ~/.ssh/id_ed25519
ForwardAgent yes
ServerAliveInterval 60
ServerAliveCountMax 3
Compression yes
ControlMaster auto
ControlPath ~/.ssh/sockets/%r@%h-%p
ControlPersist 600
Create the socket directory:
mkdir -p ~/.ssh/sockets
ControlPersist 600 keeps the master connection alive for 10 minutes after the last session closes, so reconnecting is instant.
Setting Up VS Code Remote - SSH
Installing the Extension
In VS Code on your local machine:
- Open the Extensions panel (
Ctrl+Shift+XorCmd+Shift+X) - Search for "Remote - SSH" by Microsoft
- Click Install
This extension is part of the official Remote Development extension pack by Microsoft. You can install the full pack for Remote - SSH, Remote - Containers, and WSL support, or just install Remote - SSH on its own.
Connecting to Your VPS
- Press
Ctrl+Shift+P(orCmd+Shift+P) to open the Command Palette - Type "Remote-SSH: Connect to Host"
- Select dev from the list (it reads your
~/.ssh/config) - VS Code opens a new window and connects to your VPS
The first connection takes 30-60 seconds because VS Code downloads and installs a small server component (vscode-server) on your VPS. Subsequent connections are much faster.
Once connected, the bottom-left corner of VS Code shows SSH: dev in a green badge. You're now editing files on the remote server.
Opening a Workspace
After connecting:
- Click File > Open Folder
- Navigate to your project directory (e.g.,
/home/deploy/myproject) - Click OK
The file explorer, terminal, search, and Git panel all operate on the remote filesystem. The integrated terminal opens a shell on the VPS.
VS Code Settings for Remote Development
Some VS Code settings are applied locally, and some are applied on the remote. You can configure remote-specific settings in your settings.json:
{
"remote.SSH.remotePlatform": {
"dev": "linux"
},
"remote.SSH.connectTimeout": 30,
"remote.SSH.showLoginTerminal": true,
"remote.SSH.defaultExtensions": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-python.python"
],
"remote.SSH.localServerDownload": "auto"
}
The defaultExtensions setting automatically installs the listed extensions on every remote host you connect to.
Installing Development Tools on the VPS
Set up your VPS as a complete development environment. Run these commands in the VS Code integrated terminal (which is a remote shell on your VPS).
Essential System Packages
sudo apt update
sudo apt install -y build-essential curl wget git unzip zip \
software-properties-common apt-transport-https \
ca-certificates gnupg lsb-release \
htop tree jq ripgrep fd-find
Git Configuration
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
git config --global init.defaultBranch main
git config --global pull.rebase true
git config --global core.editor "code --wait"
Setting core.editor to code --wait means Git operations that open an editor (commit messages, interactive rebase) will open in VS Code on the remote.
Since you configured ForwardAgent yes in your SSH config, your local SSH keys are available on the remote. Verify Git can authenticate with GitHub:
ssh -T git@github.com
# Hi username! You've successfully authenticated...
Node.js (via nvm)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts
nvm alias default node
node --version
npm --version
Install commonly used global packages:
npm install -g typescript ts-node nodemon eslint prettier
Python
sudo apt install -y python3 python3-pip python3-venv python3-dev
# Create a virtual environment for your project
cd ~/myproject
python3 -m venv .venv
source .venv/bin/activate
# Install packages
pip install flask django fastapi uvicorn pytest black ruff
Go
wget https://go.dev/dl/go1.23.6.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -C /usr/local -xzf go1.23.6.linux-amd64.tar.gz
rm go1.23.6.linux-amd64.tar.gz
# Add to ~/.bashrc
echo 'export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin' >> ~/.bashrc
source ~/.bashrc
go version
Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/env
rustc --version
cargo --version
Docker
Docker is essential for containerized development. Follow our Docker installation guide on Ubuntu VPS for the complete setup, or use the quick install:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for group membership to take effect
# Or use: newgrp docker
docker --version
docker compose version
Database Clients
# PostgreSQL client
sudo apt install -y postgresql-client
# MySQL client
sudo apt install -y mysql-client
# Redis CLI
sudo apt install -y redis-tools
Port Forwarding for Local Preview
When your application runs on the VPS (e.g., on port 3000), you can't access it directly from your local browser unless the port is open to the internet. VS Code's port forwarding creates a secure tunnel through your SSH connection.
Automatic Port Forwarding
VS Code detects when a process starts listening on a port and offers to forward it automatically. Start your application in the integrated terminal:
cd ~/myproject
npm run dev
# Server running on http://localhost:3000
VS Code shows a notification: "Your application running on port 3000 is available." Click Open in Browser to access it at http://localhost:3000 on your local machine.
Manual Port Forwarding
If automatic detection doesn't trigger, forward ports manually:
- Open the Ports panel (View > Ports, or click the Ports tab in the bottom panel)
- Click Forward a Port
- Enter the port number (e.g.,
3000) - Access the application at
http://localhost:3000locally
You can forward multiple ports simultaneously — useful for applications with separate frontend and backend servers, or when running a database admin tool alongside your app.
Command-Line Port Forwarding
You can also forward ports directly via SSH without VS Code. From your local terminal:
# Forward local port 3000 to remote port 3000
ssh -L 3000:localhost:3000 dev
# Forward multiple ports
ssh -L 3000:localhost:3000 -L 5432:localhost:5432 -L 6379:localhost:6379 dev
# Background forwarding (no interactive shell)
ssh -fN -L 3000:localhost:3000 dev
Configuring Port Forwarding in VS Code Settings
To always forward certain ports when connected to your VPS, add this to your workspace .vscode/settings.json on the remote:
{
"remote.autoForwardPorts": true,
"remote.autoForwardPortsSource": "process",
"remote.portsAttributes": {
"3000": {
"label": "Frontend",
"onAutoForward": "openBrowser"
},
"8080": {
"label": "API Server",
"onAutoForward": "notify"
},
"5432": {
"label": "PostgreSQL",
"onAutoForward": "silent"
}
}
}
Using VS Code Dev Containers on a VPS
Dev Containers define your entire development environment in a devcontainer.json file — OS, language runtime, tools, VS Code extensions, and settings. When you use Dev Containers on a remote VPS, the container runs on the VPS (using its Docker daemon), while VS Code connects through SSH + container.
Prerequisites
Ensure Docker is installed on your VPS (see the Docker section above), and install the Dev Containers extension in VS Code locally.
Creating a Dev Container Configuration
In your project root on the VPS, create a .devcontainer/devcontainer.json:
{
"name": "Node.js Dev Environment",
"image": "mcr.microsoft.com/devcontainers/javascript-node:22",
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/git:1": {}
},
"forwardPorts": [3000, 5432],
"postCreateCommand": "npm install",
"customizations": {
"vscode": {
"extensions": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-azuretools.vscode-docker"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}
},
"mounts": [
"source=node_modules,target=${containerWorkspaceFolder}/node_modules,type=volume"
]
}
Using docker-compose with Dev Containers
For projects with multiple services (app + database + cache), use a Docker Compose file:
Create .devcontainer/docker-compose.yml:
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ..:/workspace:cached
- node_modules:/workspace/node_modules
command: sleep infinity
ports:
- "3000:3000"
db:
image: postgres:16
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: devpass
POSTGRES_DB: myapp
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
node_modules:
pgdata:
Update .devcontainer/devcontainer.json to use the compose file:
{
"name": "Full Stack Dev",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"forwardPorts": [3000, 5432, 6379],
"postCreateCommand": "npm install"
}
When you open the project in VS Code (while connected to the VPS), it prompts you to reopen in a container. All services start on the VPS, and port forwarding tunnels them to your local machine.
Configuring Extensions Remotely
VS Code extensions run in two possible locations:
- UI extensions (themes, keybindings, snippets) run locally
- Workspace extensions (linters, formatters, language servers, debuggers) run on the remote
VS Code automatically installs workspace extensions on the remote when you first connect. You can also manage this explicitly.
Installing Extensions on the Remote
When connected to the remote, the Extensions panel shows two sections: Local - Installed and SSH: dev - Installed. Install extensions in the SSH section — they run on the VPS.
Recommended extensions for remote development:
| Extension | Purpose |
|---|---|
| ESLint | JavaScript/TypeScript linting (runs on remote) |
| Prettier | Code formatting (runs on remote) |
| Python | Python IntelliSense, debugging, linting (runs on remote) |
| Go | Go language support (runs on remote) |
| rust-analyzer | Rust language server (runs on remote) |
| GitLens | Advanced Git features (runs on remote) |
| Docker | Docker file support and container management (runs on remote) |
| Thunder Client | API testing (runs on remote) |
Workspace Extension Recommendations
Define recommended extensions in your project so anyone connecting to the remote workspace gets prompted to install them. Create .vscode/extensions.json:
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-python.python",
"ms-azuretools.vscode-docker",
"eamodio.gitlens"
]
}
Performance Tips for Remote Editing
Remote development over SSH is fast, but there are optimizations that make it even smoother.
Exclude Large Directories from File Watching
VS Code watches the filesystem for changes. On large projects, watching node_modules, .git, or build output directories wastes CPU and memory. Add to your workspace .vscode/settings.json:
{
"files.watcherExclude": {
"**/node_modules/**": true,
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/dist/**": true,
"**/build/**": true,
"**/.next/**": true,
"**/coverage/**": true,
"**/venv/**": true,
"**/__pycache__/**": true
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/build": true,
"**/coverage": true
}
}
Optimize the VS Code Server
The VS Code server process (vscode-server) runs on your VPS and can consume significant memory, especially with many extensions. Monitor its usage:
ps aux | grep vscode-server | grep -v grep
htop -p $(pgrep -d, -f vscode-server)
If memory is tight, disable extensions you don't need for the current project. You can also set a per-workspace extension list rather than enabling everything globally.
Use a Workspace Instead of Opening the Home Directory
Never open your entire home directory (/home/deploy/) as a workspace. VS Code will try to index everything, wasting resources. Always open a specific project directory.
SSH Connection Stability
If you experience frequent disconnections:
# On the VPS, increase the SSH server keepalive
sudo nano /etc/ssh/sshd_config
Add or modify:
ClientAliveInterval 60
ClientAliveCountMax 3
sudo systemctl reload sshd
Combined with the client-side ServerAliveInterval we configured earlier, this creates bidirectional keepalive that prevents most timeout disconnections.
Need consistently low latency for remote editing? Choose a MassiveGRID VPS datacenter location closest to you — New York, London, Frankfurt, or Singapore. For CPU-intensive development workloads like compilation and running test suites, a Dedicated VPS (VDS) ensures your CPU cores are never shared with other tenants.
Alternative: code-server (VS Code in the Browser)
If you want to access your development environment from any device (including tablets) without installing VS Code locally, code-server runs VS Code as a web application on your VPS.
Installing code-server
curl -fsSL https://code-server.dev/install.sh | sh
Configure code-server:
nano ~/.config/code-server/config.yaml
bind-addr: 127.0.0.1:8080
auth: password
password: your-strong-password-here
cert: false
Start code-server:
sudo systemctl enable --now code-server@$USER
Verify it's running:
sudo systemctl status code-server@$USER
Exposing code-server with Nginx and SSL
Never expose code-server directly to the internet without HTTPS. Set up Nginx as a reverse proxy with SSL. If you haven't installed Nginx yet, see our Nginx reverse proxy guide.
Create an Nginx server block:
sudo nano /etc/nginx/sites-available/code-server
server {
listen 80;
server_name code.yourdomain.com;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Accept-Encoding gzip;
}
}
Enable the site and get an SSL certificate:
sudo ln -s /etc/nginx/sites-available/code-server /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
# Get SSL certificate
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d code.yourdomain.com
Now access your development environment at https://code.yourdomain.com from any browser.
Securing code-server
Beyond the password in the config file, add these additional security layers:
# Restrict access to specific IPs in Nginx
location / {
allow 203.0.113.10; # Your home IP
allow 198.51.100.0/24; # Your office subnet
deny all;
proxy_pass http://127.0.0.1:8080;
# ... rest of proxy config
}
Alternatively, access code-server through an SSH tunnel without exposing it to the internet at all:
# From your local machine
ssh -L 8080:localhost:8080 dev
# Then open http://localhost:8080 in your browser
You can also place code-server behind a WireGuard VPN for secure access without public exposure.
code-server vs Remote - SSH: When to Use Each
| Feature | VS Code Remote - SSH | code-server |
|---|---|---|
| Local installation needed | Yes (VS Code desktop) | No (browser only) |
| Performance | Better (native UI) | Good (browser rendering) |
| Extension compatibility | Full marketplace access | Open VSX marketplace |
| Device flexibility | Desktop/laptop only | Any device with a browser |
| Keyboard shortcuts | Full OS-native support | Some browser conflicts |
| Offline local editing | No (needs connection) | No (needs connection) |
| Resource usage (local) | Medium (VS Code process) | Low (browser tab) |
| Resource usage (remote) | Medium | Medium-High |
Recommendation: Use Remote - SSH as your primary workflow. Use code-server when you need access from a device where VS Code can't be installed (tablets, borrowed computers, Chromebooks).
Working with tmux for Persistent Sessions
Even with VS Code's integrated terminal, tmux is valuable for running long processes that should survive SSH disconnections. Install it:
sudo apt install -y tmux
Basic tmux workflow:
# Start a new named session
tmux new -s dev
# Detach from session (keeps running)
# Press Ctrl+B, then D
# List sessions
tmux ls
# Reattach to a session
tmux attach -t dev
# Kill a session
tmux kill-session -t dev
Create a ~/.tmux.conf for a better experience:
# Use Ctrl+A instead of Ctrl+B (more ergonomic)
set -g prefix C-a
unbind C-b
bind C-a send-prefix
# Enable mouse support
set -g mouse on
# Start window numbering at 1
set -g base-index 1
setw -g pane-base-index 1
# Increase scrollback buffer
set -g history-limit 50000
# Better colors
set -g default-terminal "screen-256color"
# Split panes with | and -
bind | split-window -h
bind - split-window -v
Use tmux sessions for tasks like running development servers, watching file changes, or monitoring logs — even when VS Code reconnects after a disconnection, your tmux sessions remain intact.
Project-Specific Development Environments
Keep your VPS organized with isolated environments per project.
Directory Structure
/home/deploy/
├── projects/
│ ├── frontend-app/ # React/Vue/Next.js project
│ ├── backend-api/ # Node.js/Python API
│ ├── mobile-backend/ # Another project
│ └── experiments/ # Scratch projects
├── .config/
│ └── code-server/ # code-server config
├── .ssh/
│ └── config # SSH config for Git remotes
└── .bashrc # Shell customization
Per-Project Node.js Versions
# Project A uses Node 20
cd ~/projects/frontend-app
echo "20" > .nvmrc
nvm use # Reads .nvmrc automatically
# Project B uses Node 22
cd ~/projects/backend-api
echo "22" > .nvmrc
nvm use
Per-Project Python Virtual Environments
cd ~/projects/backend-api
python3 -m venv .venv
source .venv/bin/activate
# VS Code detects the .venv and uses it automatically
# for Python IntelliSense, linting, and debugging
What's Next
- Ubuntu VPS initial setup guide — configure your server with a non-root user, SSH keys, and basic security
- Security hardening guide — firewall, SSH hardening, fail2ban for protecting your dev server
- Install Docker on Ubuntu VPS — required for Dev Containers and containerized development
- Nginx reverse proxy guide — set up HTTPS for code-server and development previews
- WireGuard VPN setup — secure access to your development server without exposing ports
- VPS monitoring guide — track resource usage on your development server