Skip to content

Bootstrap Checklist: From Current State to Remote Server

Prerequisites (already done)

  • Windows 11 installed on remote PC
  • Tailscale installed as Windows app, authenticated
  • WSL2 Ubuntu installed, user admin created
  • wsl.exe shell works interactively on the PC

Phase 1: Configure on the PC (interactive, one-time)

These steps must be done while physically at the PC (or via remote desktop).

Step 1.1: Configure WSL2 settings

Inside WSL2 -- edit /etc/wsl.conf:

sudo tee /etc/wsl.conf <<'EOF'
[boot]
systemd = true
command = service ssh start

[network]
generateResolvConf = false
EOF

Create static DNS:

sudo rm -f /etc/resolv.conf
sudo tee /etc/resolv.conf <<'EOF'
nameserver 1.1.1.1
nameserver 8.8.8.8
EOF

Step 1.2: Configure .wslconfig

On Windows -- create/edit %UserProfile%\.wslconfig:

[general]
instanceIdleTimeout = -1

[wsl2]
vmIdleTimeout = -1
networkingMode = mirrored

[experimental]
autoMemoryReclaim = disabled

Apply: wsl --shutdown from PowerShell, then restart WSL.

Step 1.3: Install and configure SSH

sudo apt update && sudo apt install -y openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh

Edit /etc/ssh/sshd_config:

Port 22
ListenAddress 0.0.0.0
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication yes   # temporarily, for key deployment

Restart: sudo systemctl restart ssh

Step 1.4: Deploy SSH public key

Generate on your home machine:

ssh-keygen -t ed25519 -f ~/.ssh/wsl_ubuntu -C "wsl-remote-dev"

Copy ~/.ssh/wsl_ubuntu.pub content to the PC (USB, email, whatever), then on the WSL2 instance:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "<paste pubkey here>" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Step 1.5: Configure firewalls

From PowerShell (admin):

# Windows Firewall
New-NetFirewallRule -DisplayName "WSL2 SSH via Tailscale" `
    -Direction Inbound -Protocol TCP -LocalPort 22 `
    -Action Allow -RemoteAddress 100.64.0.0/10

# Hyper-V Firewall (mirrored mode)
New-NetFirewallHyperVRule -Name "WSL-SSH" -Direction Inbound `
    -VMCreatorId '{40E0AC32-46A5-438A-A0B2-2B479E8F2E90}' `
    -Protocol TCP -LocalPorts 22 -Action Allow

Disable Windows OpenSSH server if present:

Stop-Service sshd -ErrorAction SilentlyContinue
Set-Service -Name sshd -StartupType Disabled -ErrorAction SilentlyContinue

Step 1.6: Set up auto-start

Task Scheduler at logon (PowerShell admin):

$action = New-ScheduledTaskAction -Execute "C:\Windows\System32\wsl.exe" `
    -Argument "-d Ubuntu"
$trigger = New-ScheduledTaskTrigger -AtLogOn
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries `
    -DontStopIfGoingOnBatteries -ExecutionTimeLimit ([TimeSpan]::Zero)
Register-ScheduledTask -TaskName "WSL2-AutoStart" -Action $action `
    -Trigger $trigger -Settings $settings -RunLevel Highest

Optionally configure Windows auto-login (so WSL starts after unattended reboots).

Step 1.7: Test from home (before leaving)

From your home machine:

ssh -i ~/.ssh/wsl_ubuntu admin@<tailscale-ip>

If it works, harden SSH:

# On WSL2:
sudo sed -i 's/^PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart ssh

Test again with key auth to confirm lockdown.

Phase 2: Remote provisioning (over SSH from home)

Once SSH works, everything below can be done remotely.

Step 2.1: Passwordless sudo

echo "admin ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/admin
sudo chmod 440 /etc/sudoers.d/admin

Step 2.2: System updates

sudo apt update && sudo apt upgrade -y
sudo apt install -y build-essential git curl wget htop tmux

Step 2.3: CUDA toolkit (if needed)

See cuda-setup.md.

Step 2.4: Python / ML environment (if needed)

See ml-workloads.md.

Step 2.5: Docker (if needed)

curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker admin
# Re-login for group membership

For GPU containers, see ml-workloads.md Docker section.

Phase 3: Verify everything survives reboot

Ask someone at the PC to reboot Windows (or use Tailscale + RDP if available). After reboot:

  1. Confirm Tailscale reconnects (check admin console).
  2. Confirm WSL2 starts (Task Scheduler + auto-login).
  3. Confirm SSH works: ssh wsl-dev.
  4. Confirm GPU: nvidia-smi.

Fallback: If Mirrored Mode Fails

If SSH is unreachable after Step 1.2, switch to NAT mode + portproxy:

  1. Remove networkingMode = mirrored from .wslconfig.
  2. wsl --shutdown and restart.
  3. Set up portproxy -- see port-forwarding.md.