Remote Development — SSH, Codespaces, Dev Containers Guide
Remote development lets you use a powerful remote machine, cloud environment, or container for computation while keeping your local editor's interface, extensions, and keybindings. This guide covers the three most popular remote development approaches and when to use each.
What You'll Learn
You'll configure VS Code Remote-SSH for seamless remote editing, set up GitHub Codespaces for cloud-based development environments, build Dev Containers with reproducible configurations, manage port forwarding and secrets, and choose the right remote approach for your team's workflow.
Why Remote Development Matters
Local development breaks when your project needs specific OS dependencies, GPU access, or compute resources your laptop can't provide. Remote development solves this by running the toolchain on a server, container, or cloud environment while you edit with your preferred local setup.
DodaZIP's compression benchmarks run on remote servers with 64-core CPUs and 256GB RAM. Developers edit the benchmarking code locally with Remote-SSH, run tests on the remote machine, and see results in their local terminal.
Learning Path
flowchart LR A[Editor Basics] --> B[Remote Development
You are here] B --> C[Dev Containers] C --> D[Codespaces] C --> E[SSH Workflows] style B fill:#f90,color:#fff
VS Code Remote-SSH
The Remote-SSH extension lets you open any folder on a remote machine as if it were local:
# Install Remote-SSH extension
code --install-extension ms-vscode-remote.remote-ssh
# Connect to a remote host
# Ctrl+Shift+P → "Remote-SSH: Connect to Host..."
# Or connect directly from the command line:
code --remote ssh-remote+dev-server /path/to/project
SSH Configuration
# ~/.ssh/config — SSH host configuration
Host dev-server
HostName 192.168.1.100
User developer
Port 2222
IdentityFile ~/.ssh/id_ed25519_dev
ForwardAgent yes
ServerAliveInterval 60
ServerAliveCountMax 5
Host build-server
HostName build.internal.company.com
User ci
IdentityFile ~/.ssh/id_ed25519_ci
RemoteForward 9229 localhost:9229
LocalForward 3000 localhost:3000
Remote-SSH Settings
// VS Code settings for Remote-SSH:
{
"remote.SSH.showLoginTerminal": true,
"remote.SSH.allowLocalForwarding": true,
"remote.SSH.path": "/usr/bin/ssh",
"remote.SSH.useLocalServer": true,
"remote.SSH.connectTimeout": 30,
"remote.SSH.extensions": [
"ms-python.python",
"dbaeumer.vscode-eslint",
"eamodio.gitlens]
]
}
Installing Extensions Remotely
# Extensions can be installed locally (for UI) or remotely (for language support)
# Ctrl+Shift+P → "Extensions: Show Local Extensions"
# Ctrl+Shift+P → "Extensions: Show Remote Extensions"
# Remote extensions run on the server and provide language features:
# - Python, Pylance, Jupyter
# - ESLint, Prettier
# - GitLens, GitHub PRs
# - Docker
GitHub Codespaces
Codespaces provide cloud-hosted development environments with a consistent configuration:
// .devcontainer/devcontainer.json — Codespaces configuration
{
"name": "DodaTech API Development",
"image": "mcr.microsoft.com/devcontainers/universal:2",
"features": {
"ghcr.io/devcontainers/features/python:1": {
"version": "3.12"
},
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/node:1": {
"version": "20"
}
},
"customizations": {
"vscode": {
"extensions": [
"ms-python.python",
"ms-python.black-formatter",
"dbaeumer.vscode-eslint",
"eamodio.gitlens",
"github.copilot",
"ms-azuretools.vscode-docker]
],
"settings": {
"editor.formatOnSave": true,
"python.defaultInterpreterPath": "/usr/local/bin/python"
}
}
},
"forwardPorts": [3000, 8000, 5432],
"portsAttributes": {
"3000": { "label": "Frontend", "onAutoForward": "openBrowser" },
"8000": { "label": "API", "onAutoForward": "notify" },
"5432": { "label": "PostgreSQL", "onAutoForward": "silent" }
},
"postCreateCommand": "pip install -r requirements.txt && npm install",
"remoteUser": "codespace"
}
Starting a Codespace
# From GitHub repository:
# Code → Codespaces → Create codespace on main
# From CLI (requires gh CLI):
gh codespace create --repo dodatech/api --branch main
# List codespaces:
gh codespace list
# SSH into a codespace:
gh codespace ssh
# Delete a codespace:
gh codespace delete --codespace <name>
Codespace Lifecycle
# Events that trigger lifecycle hooks:
# 1. prebuild (optional) — runs on repo push
# 2. create — first time codespace starts
# 3. postCreate — after container is ready
# 4. postAttach — every time you connect
# 5. postStart — after stop/start cycle
# Lifecycle scripts in devcontainer.json:
"postCreateCommand": "bash scripts/setup-dev.sh"
"postAttachCommand": "bash scripts/start-dev.sh"
"postStartCommand": "bash scripts/migrate-db.sh"
Dev Containers
Dev Containers allow you to define a Docker-based development environment:
# Dockerfile — Development container
FROM ubuntu:22.04
# Install system dependencies
RUN apt-get update && apt-get install -y \
python3.12 \
python3-pip \
nodejs \
npm \
git \
curl \
build-essential \
postgresql-client \
&& rm -rf /var/lib/apt/lists/*
# Install Python packages
COPY requirements.txt /tmp/
RUN pip3 install --no-cache-dir -r /tmp/requirements.txt
# Install Node packages
COPY package.json /tmp/
RUN cd /tmp && npm install
# Set working directory
WORKDIR /workspace
# Create non-root user
RUN useradd -m developer
USER developer
// .devcontainer/devcontainer.json — Dev Container configuration
{
"name": "DodaTech Full Stack Dev",
"build": {
"dockerfile": "Dockerfile",
"context": ".."
},
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspace",
"mounts": [
"source=${env:HOME}${env:USERPROFILE}/.ssh,target=/home/developer/.ssh,type=bind]
],
"containerEnv": {
"DATABASE_URL": "postgresql://dev:dev@db:5432/dodatech",
"REDIS_URL": "redis://redis:6379",
"NODE_ENV": "development"
},
"remoteUser": "developer",
"postCreateCommand": "bash .devcontainer/setup.sh",
"forwardPorts": [3000, 8000, 5432, 6379]
}
# docker-compose.yml — Multi-service development environment
version: "3.8"
services:
app:
build:
context: .
dockerfile: Dockerfile
volumes:
- ..:/workspace:cached
- ~/.ssh:/home/developer/.ssh:ro
command: sleep infinity
ports:
- "3000:3000"
- "8000:8000"
depends_on:
- db
- redis
db:
image: postgres:16
environment:
POSTGRES_USER: dev
POSTGRES_PASSWORD: dev
POSTGRES_DB: dodatech
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
redis:
image: redis:7
ports:
- "6379:6379"
volumes:
postgres-data:
Port Forwarding and Service Access
# VS Code Remote-SSH — automatic port forwarding
# When a server starts on port 3000, VS Code prompts to forward it
# Ctrl+Shift+P → "Remote-SSH: Forward Port"
# Manual port forwarding:
# View → Command Palette → "Forward a Port"
# Enter the port number (e.g., 3000)
# Codespaces — ports are forwarded automatically:
# Ports are listed in VS Code's "PORTS" tab
# You can set visibility: private, org, or public
# SSH local port forwarding:
ssh -L 3000:localhost:3000 dev-server
# SSH remote port forwarding:
ssh -R 9229:localhost:9229 dev-server
Security Best Practices
# 1. Use SSH keys, not passwords
ssh-keygen -t ed25519 -C "dev@dodatech.com"
ssh-copy-id dev-server
# 2. Use SSH config for host aliases
# (see SSH configuration section above)
# 3. Never commit .env or secrets files to repos
# Use Codespaces secrets: https://github.com/settings/codespaces
# 4. Use GitHub secrets for Codespaces:
gh secret set DATABASE_URL --repos dodatech/api
# 5. Restrict Codespace access:
# "codespaces: write" permission in GitHub settings
# IP allow lists for Codespaces in GitHub organization settings
Choosing the Right Approach
| Criteria | Remote-SSH | Codespaces | Dev Containers |
|---|---|---|---|
| Best for | Dedicated dev server | Cloud-native teams | Reproducible environments |
| Setup time | Minutes | Seconds | Hours (first time) |
| Cost | Server cost + bandwidth | Per-minute billing | Free (local Docker) |
| Internet required | Yes | Yes | No (local) |
| Team consistency | Manual | Automatic | Automatic |
| GPU support | Yes | Limited | Yes |
| Local resources | Minimal | None needed | Docker host required |
Common Remote Development Mistakes
1. Ignoring Latency
Remote-SSH over transatlantic connections (200ms+ latency) is painful for real-time editing. Use Codespaces in the closest region. For Remote-SSH, use a server in the same geographic region.
2. Not Using SSH Config
Putting host addresses, ports, and keys in VS Code settings instead of ~/.ssh/config. SSH config is the standard and works with all SSH tools, not just VS Code.
3. Forgetting to Install Extensions Remotely
Language support extensions (Python, ESLint) must be installed on the remote machine. VS Code prompts for this, but confirm with "Extensions: Show Remote Extensions".
4. Hardcoding Secrets in devcontainer.json
Never put database URLs, API keys, or tokens in devcontainer.json. Use environment variables, Codespaces secrets, or a .env file excluded from version control.
5. Not Managing Codespace Costs
Codespaces bill by minute. Stop unused codespaces. Set auto-stop timers (30 minutes default; lower to 15 for personal use). Use prebuilds to reduce startup time.
6. Overlooking Docker Resource Limits
Dev Containers share your host's Docker resources. A container with unlimited memory can starve other containers. Set limits in docker-compose.yml: deploy: resources: limits: memory: 4G.
7. Mixing Multiple Remote Approaches
Using Remote-SSH to connect to Codespaces or running Dev Containers within Remote-SSH is possible but adds complexity. Choose one approach per project and stick with it.
Practice Questions
1. What is the difference between Remote-SSH, Codespaces, and Dev Containers? Remote-SSH connects to a remote server via SSH. Codespaces provides cloud-hosted environments managed by GitHub. Dev Containers run on your local Docker but define the environment in a configuration file.
2. How do you forward a port in a Remote-SSH session? When VS Code detects a server starting on a port, it prompts to forward it. Manually: Ctrl+Shift+P → "Forward a Port" → enter the port number.
3. What file defines a Dev Container or Codespaces configuration?
.devcontainer/devcontainer.json. This file specifies the image or Dockerfile, extensions, settings, forwarded ports, and lifecycle commands.
4. How do you securely pass secrets to a Codespace?
Use GitHub Codespaces secrets (gh secret set or GitHub.com → Settings → Codespaces). Secrets are injected as environment variables but never visible in configuration files.
5. Challenge: Your team is migrating from local development with manual environment setup to a reproducible remote workflow. Design a Dev Container configuration that includes Python 3.12, Node.js 20, PostgreSQL 16, Redis 7, and automatically installs project dependencies on creation.
Answer: Create a docker-compose.yml with app, db, and redis services. Create a Dockerfile with Python 3.12 and Node.js 20 installed. In devcontainer.json, reference the Dockerfile and docker-compose, set postCreateCommand to install pip and npm dependencies, forward ports 3000/8000/5432/6379, and include required VS Code extensions.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-23.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro