devAlice
← Multi-OS

Remote development — work on another machine via SSH · Tailscale · VS Code Remote

Drive your home desktop / home server / cloud workstation from a laptop seamlessly — Tailscale · SSH · VS Code Remote · tmux unified setup.

"Keep the powerful desktop at home and travel light" or "use a GPU workstation remotely" — same scenario. Core tools: Tailscale (zero-config VPN) + SSH + VS Code Remote-SSH + tmux. Set up once and a cafe feels like your desktop.

I think what Tailscale changes about remote development is the barrier to entry. Not because SSH was hard before — it wasn't — but rather because NAT traversal and VPN configuration used to require either a static IP, a VPN server to maintain, or exposing SSH to the public internet. Because Tailscale handles the networking layer automatically, the setup reduces to "install on both machines and sign in," which is what makes the remote-desktop pattern accessible to anyone.

TL;DR

  1. Tailscale — mesh VPN that punches NAT/firewalls. Connect machines without a corporate VPN
  2. SSH — all traffic after auth
  3. VS Code Remote-SSH — edit remote files locally as if they were local
  4. tmux — session persistence. Work survives disconnects
  5. Mosh (optional) — SSH alternative stable on mobile networks

Prerequisites

  • SSH + accounts + internet on both ends
  • (Optional) No need for a domain or static IP — Tailscale handles it

1. Tailscale Setup

Tailscale is a WireGuard-based mesh VPN. Install on each machine + log into the same account → private IPs (100.x.x.x) are assigned. NAT punched, direct connect.

1.1 Install

Mac:

brew install --cask tailscale

Windows:

winget install --id tailscale.tailscale

Linux (Ubuntu):

curl -fsSL https://tailscale.com/install.sh | sh

1.2 Sign In

On each machine:

sudo tailscale up      # Mac/Linux
# Or use the GUI tray → Login

Opens a browser → sign up with Google/GitHub/Microsoft (Tailscale free: 100 devices).

1.3 Find the Machine IP

tailscale ip -4
# 100.x.x.x

Or see all machines at admin.tailscale.com.

1.4 Machine Names (MagicDNS)

Admin console → DNS → enable MagicDNS. Now SSH by name like desktop.tail-scale.ts.net:

ssh me@desktop
# (.tail-scale.ts.net auto-appended)

Once enabled, never think about private IPs again. The rest of this guide assumes the name desktop.

2. SSH Prep

2.1 Enable SSH on the Remote

Mac (remote):

  • System Settings → General → Sharing → Remote Login ON

Windows (remote):

  • Settings → System → Optional features → install OpenSSH Server
  • PowerShell (admin):
    Set-Service -Name sshd -StartupType Automatic
    Start-Service sshd

Linux (remote):

sudo apt install openssh-server
sudo systemctl enable --now ssh

2.2 Register the SSH Key

Add the local public key to the remote's ~/.ssh/authorized_keys:

# Local
ssh-copy-id me@desktop
# Or manually on the remote:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAA..." >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

2.3 Connect

ssh me@desktop
# Or directly to 100.x.x.x

3. VS Code Remote-SSH

Edit remote files at local speed from VS Code.

3.1 Install the Extension

VS Code marketplace:

  • Remote - SSH (ms-vscode-remote.remote-ssh)

Or:

code --install-extension ms-vscode-remote.remote-ssh

3.2 Connect

VS Code Command Palette (⌘⇧P / Ctrl+Shift+P) → Remote-SSH: Connect to Host → enter me@desktop.

First connect installs VS Code Server on the remote (~50MB, once). Subsequent connects are instant.

3.3 Use

Bottom-left shows SSH: desktop. File → Open Folder → open ~/work/repo on the remote. Extensions install on the remote (e.g., the Python extension uses the remote's Python env).

  • ESLint / Prettier
  • Python / Pylance
  • Docker
  • (Keep theme/keymap on local for neatness)

4. tmux — Session Persistence

If SSH drops, work stays:

4.1 Install (remote)

# Mac / Linux remote
brew install tmux   # Mac
sudo apt install tmux   # Ubuntu

4.2 Use

ssh me@desktop
tmux new -s work       # start session
# ...work...
# Ctrl+B, D  → detach (session keeps running)
 
# Later
ssh me@desktop
tmux attach -t work    # reattach

4.3 Key Shortcuts

Shortcut (prefix = Ctrl+B)Action
prefix + DDetach
prefix + CNew window
prefix + N / PNext / previous window
prefix + %Vertical split
prefix + "Horizontal split
prefix + arrowsMove pane
prefix + ZZoom pane

4.4 Auto-attach

.zshrc (remote):

if [[ -z "$TMUX" && -n "$SSH_CONNECTION" ]]; then
  tmux attach -t main || tmux new -s main
fi

SSH in → auto-attach to main (or create).

5. Mosh — On Mobile Networks

If SSH drops a lot during transitions (5G ↔ Wi-Fi), use Mosh (Mobile shell). UDP-based, local echo, auto-recover.

brew install mosh
# Remote
sudo apt install mosh
mosh me@desktop

Uses SSH for auth + UDP ports 60000-61000. No extra firewall configuration if going through Tailscale.

6. Scenario: GPU Workstation Remote

Goal: train ML on desktop GPU from a laptop.

# On the laptop
ssh me@gpu-workstation
tmux new -s train
 
# Inside tmux
cd ~/projects/ml
python train.py --epochs 100
 
# Ctrl+B, D to detach
 
# Close the laptop, move to a cafe
# Reconnect
ssh me@gpu-workstation
tmux attach -t train
# Training continues

Edit with VS Code Remote + run training in tmux. Both run together.

7. Security

Tailscale ACL (optional)

By default, all machines on the same account see each other. For corp/family mix:

  • Admin console → ACLs → JSON policy
  • Tag-based permissions (tag:dev, tag:home)

Harden SSH

On the remote /etc/ssh/sshd_config:

PasswordAuthentication no       # keys only
PermitRootLogin no
AllowUsers me
sudo systemctl restart sshd

1Password SSH Agent

See password manager. With Tailscale + 1Password agent, SSH needs only biometric — no passphrase.

Verification

  1. tailscale status on both → "online"
  2. ssh me@desktop → instant login (one passphrase or biometric)
  3. VS Code Command Palette → Remote-SSH Connect → edit + save → changes reflect on the remote
  4. tmux new -s test → detach → tmux attach -t test → state preserved
  5. mosh me@desktop → drop Wi-Fi, switch networks → session auto-recovers

Troubleshooting

Tailscale doesn't connect

  • Both machines run tailscale up and signed in
  • Admin console shows both as "Connected"
  • Firewall — Tailscale uses 41641/UDP. Corp networks may block (falls back to DERP relay)

ssh: connect to host 100.x.x.x: Connection refused

  • SSH service isn't running on the remote (re-check §2.1)
  • Windows: Get-Service sshd is Running?

VS Code Remote is slow

  • First connect installs Server — slow once
  • If going via internet (Tailscale Direct failed) — tailscale ping desktop to see direct vs DERP

Colors broken in tmux

.tmux.conf:

set -g default-terminal "screen-256color"
set -ga terminal-overrides ",xterm-256color:Tc"

Mosh won't connect

UDP 60000-61000 blocked — common on corporate networks. Fall back to SSH. Mosh needs UDP.

SSH agent forwarding (be careful)

For SSH-from-remote-to-another-remote, ssh -A. Only when the intermediate remote is trusted — a malicious root would see keys.

References

Changelog

  • 2026-05-12: First draft. Tailscale · SSH · VS Code Remote · tmux · Mosh + scenario · security + six troubleshooting cases.

Keep reading