Skip to content

Code Anywhere: Setting Up Claude Code on a VPS with Mobile Access

Ever seen someone coding at a cafe from their phone and wondered how? Here's the exact setup to run Claude Code (and OpenAI Codex) on a remote server and access it from your phone, tablet, or any device with an internet connection.

Inspired by levelsio's tweet about coding on his phone via Termius + Claude Code while out and about.

Claude Code running on phone via Termius


What You'll Need

  • A DigitalOcean account (or any VPS provider — Hetzner, Vultr, etc.)
  • A phone with Termius installed (iOS/Android)
  • 10 minutes

Step 1: Generate an SSH Key

On your local machine (Mac/Linux):

ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_claude_vps

It'll ask for a passphrase — set one for security or leave empty for convenience.

This creates two files: - ~/.ssh/id_ed25519_claude_vps — your private key (never share this) - ~/.ssh/id_ed25519_claude_vps.pub — your public key (this goes on the server)

Copy the public key to your clipboard:

# macOS
cat ~/.ssh/id_ed25519_claude_vps.pub | pbcopy

# Linux
cat ~/.ssh/id_ed25519_claude_vps.pub | xclip -selection clipboard

Gotcha: The public key starts with ssh-ed25519 AAAA.... The private key starts with -----BEGIN OPENSSH PRIVATE KEY-----. Know the difference — you'll need both at different steps.

Step 2: Create a DigitalOcean Droplet

  1. Go to cloud.digitalocean.comCreateDroplets
  2. Region: Pick the closest to you (lower latency = snappier terminal)
  3. Image: Ubuntu 24.04 LTS
  4. Size: Basic → Regular → $6/mo (1 vCPU, 1GB RAM)
  5. Authentication: Select SSH Key → paste your public key (the one you copied with pbcopy)
  6. Hostname: claude-dev (or whatever you like)
  7. Hit Create Droplet

Note down the IP address once it's ready (e.g., 134.209.42.100).

Why not AWS? A simple VPS has predictable billing ($6/mo flat), no surprise charges, and zero config overhead. AWS EC2 makes sense if you're already in that ecosystem, but for "SSH in and code" it's overkill.

Step 3: Set Up SSH Config (Saves Time Later)

Add this to ~/.ssh/config on your local machine:

Host claude-dev
    HostName <your-droplet-ip>
    User root
    IdentityFile ~/.ssh/id_ed25519_claude_vps

Note: We're using root for now to set up the server. You'll change this to a non-root user in Step 5.

Now you can connect with just:

ssh claude-dev

Gotcha: If you get UNPROTECTED PRIVATE KEY FILE error, fix permissions:

chmod 600 ~/.ssh/id_ed25519_claude_vps
SSH refuses to use a private key that other users can read.

Gotcha: Use the private key (without .pub) in your SSH command and config. The .pub file is only for pasting into servers/services. If you use the .pub file with ssh -i, you'll get a Permission denied error.

Step 4: Install Everything on the Server

SSH into your droplet and run this setup script:

ssh claude-dev

Then paste:

#!/bin/bash
set -e

# Install Node.js 22
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo bash -
sudo apt install -y nodejs

# Install Claude Code
sudo npm install -g @anthropic-ai/claude-code

# Install OpenAI Codex (optional)
sudo npm install -g @openai/codex

# Install tmux for persistent sessions
sudo apt install -y tmux

echo "Done! Run: tmux new -s claude && claude"

Or save it as a script and SCP it over:

scp -i ~/.ssh/id_ed25519_claude_vps setup.sh root@<your-ip>:~
ssh claude-dev "bash ~/setup.sh"

Step 5: Create a Non-Root User

Claude Code refuses to run as root for security reasons. You need to create a regular user:

ssh claude-dev

# Create a new user called "claude" with no password prompt
adduser claude --disabled-password --gecos ""

# Give the user sudo privileges (for installing packages later)
usermod -aG sudo claude

# Allow passwordless sudo (needed since we didn't set a password)
echo "claude ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/claude
chmod 440 /etc/sudoers.d/claude

# Copy root's SSH keys so you can SSH in as this new user
cp -r ~/.ssh /home/claude/.ssh

# Fix ownership — copied files are owned by root, change to claude
chown -R claude:claude /home/claude/.ssh

Now update your local ~/.ssh/config to use the new user:

Host claude-dev
    HostName <your-droplet-ip>
    User claude
    IdentityFile ~/.ssh/id_ed25519_claude_vps

Test it:

ssh claude-dev

You should now be logged in as claude instead of root.

Gotcha: If you skip this step and try to run Claude Code as root, you'll get: --dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons. Don't try to force it — just create a regular user.

Step 6: Add Swap (Prevent Crashes on 1GB Droplet)

The $6 droplet only has 1GB RAM. Adding swap prevents out-of-memory crashes:

ssh claude-dev "sudo fallocate -l 2G /swapfile && sudo chmod 600 /swapfile && sudo mkswap /swapfile && sudo swapon /swapfile && echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab"

This gives you 2GB of virtual memory. Not as fast as real RAM but keeps things stable.

Step 7: Set Up Termius on Your Phone (Code From Anywhere)

  1. Download Termius from App Store / Play Store
  2. Go to KeychainKeys → tap +Import
  3. Paste your private key (the one starting with -----BEGIN OPENSSH PRIVATE KEY-----)

To get it on your phone, on your Mac run:

cat ~/.ssh/id_ed25519_claude_vps
Then AirDrop the text, or copy-paste via a secure method.

Gotcha: Do NOT paste the public key here. Termius needs the private key. If you see ssh-ed25519 AAAA... that's the wrong one. You need -----BEGIN OPENSSH PRIVATE KEY-----.

  1. Go to Hosts → tap +:
  2. Label: claude-dev
  3. Hostname: <your-droplet-ip>
  4. Username: claude
  5. Key: Select the key you just imported
  6. Save → tap the host to connect

Step 8: Start Coding with tmux

tmux keeps your session alive even when you disconnect (phone loses signal, close the app, etc.).

ssh claude-dev

# First time: create a session
tmux new -s claude

# Run Claude Code
claude

When you disconnect and come back:

ssh claude-dev
tmux attach -t claude

Your session is exactly where you left it.

tmux essentials: | Action | Keys | |---|---| | Detach (leave session running) | Ctrl+B then D | | Reattach | tmux attach -t claude | | New window | Ctrl+B then C | | Switch windows | Ctrl+B then 0-9 | | Scroll up | Ctrl+B then [ (press q to exit scroll) |


Step 9 (Optional): Lock Down SSH with Tailscale

Right now your server's SSH port (22) is open to the entire internet. Anyone can try to connect to your IP on port 22. You're protected by SSH keys, so it's hard to break in — but the port is still visible and exposed to brute-force attempts.

Tailscale creates a private VPN mesh between your devices. Once set up, your server gets a private IP (like 100.x.x.x) that only your devices can reach. You can then close port 22 on the public firewall entirely — no one on the internet can even see your SSH port.

Think of it like this:

  • Without Tailscale: Your server's front door is on a public street. It's locked (SSH keys), but anyone can walk up and try the handle.
  • With Tailscale: Your server's front door is inside a private building that only your devices have a keycard to enter.

On your server:

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

# Start and authenticate — it'll print a URL, open it in your browser
sudo tailscale up

# Note your server's Tailscale IP
tailscale ip -4
# e.g., 100.92.45.13

On your Mac:

Install the Tailscale app from the Mac App Store (search "Tailscale"). Sign in with the same account.

On your phone:

Install the Tailscale app from App Store / Play Store. Sign in with the same account.

Update your SSH config:

Replace the public IP with your server's Tailscale IP:

Host claude-dev
    HostName <your-tailscale-ip>
    User claude
    IdentityFile ~/.ssh/id_ed25519_claude_vps

Also update the Hostname in your Termius host to the Tailscale IP.

Block public SSH access (optional):

Once everything works through Tailscale, lock down the firewall:

  1. Go to DigitalOcean → NetworkingFirewallsCreate Firewall
  2. Name: claude-dev-firewall
  3. Inbound Rules: Delete the default SSH rule, then add:
  4. Type: Custom, Protocol: TCP, Port range: All Ports, Sources: 100.64.0.0/10 (Tailscale IP range)
  5. Outbound Rules: Leave defaults (allow all)
  6. Apply to Droplets: Select claude-dev
  7. Create Firewall

Now only your Tailscale devices can reach the server. If you ever get locked out, just remove the firewall from the DigitalOcean dashboard.


Security Tips

  • Never share your private key. If you emailed it to yourself to get it on your phone, delete that email.
  • Disable password auth on your server (it's off by default on DigitalOcean if you chose SSH key auth).
  • Consider Mosh instead of SSH for mobile — it handles flaky connections and network switches (Wi-Fi to 5G) much better than SSH.

Cost

Item Cost
DigitalOcean droplet $6-12/mo
Termius Free tier works fine
Claude Code Pay per API usage
Coding at a cafe while your friends wonder what you're doing Priceless

That's it. You now have a cloud dev environment accessible from any device. Start a tmux session, fire up Claude Code, and code from anywhere.