Running coding agents on a remote server: a practical guide

· 11 min read

Running Claude Code, Codex, or Cursor CLI on a remote machine instead of your laptop changes what you can ask them to do. Runs survive disconnects, you can check on work from a phone, and a long task doesn't hold your laptop hostage.

The setup is not hard, but there are four places where people reliably get stuck. This guide walks the whole path and flags each one.

What you need before starting

  • A VPS with at least 2 vCPU and 4 GB of RAM. Agents themselves are light, but the builds and test suites they trigger are not. 8 GB is more comfortable.
  • Root or sudo access.
  • A domain, if you want preview URLs with HTTPS later.

Ubuntu 24.04 is the path of least resistance and what the commands below assume.

Step 1: Harden SSH before anything else

A fresh VPS with password auth is found by bots within minutes. Copy your key up, then disable password login:

ssh-copy-id root@your-server-ip
ssh root@your-server-ip

Then in /etc/ssh/sshd_config, set:

PasswordAuthentication no
PermitRootLogin prohibit-password

Reload with systemctl reload ssh. Keep your existing session open while you test a second one — locking yourself out here is a rite of passage worth skipping.

Step 2: Install a runtime

Agent CLIs are distributed as npm packages and expect a current Node. The version in Ubuntu's default repositories is too old. Use a version manager rather than fighting the system package:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
source ~/.bashrc
nvm install --lts

Install whatever else your project needs at this point — Python, a JDK, build tooling. This is also where you'll discover that a 2 GB box can't compile anything interesting.

Step 3: Authenticate the agents

This is the step that stops people. Agent CLIs authenticate through a browser OAuth flow. Your server has no browser.

The flow prints a URL and then waits for a redirect to localhost on the server — which your laptop's browser can't reach. The fix is an SSH tunnel that forwards the callback port from the server to your machine:

ssh -L 54545:localhost:54545 user@your-server-ip

With that tunnel open, run the login command inside the SSH session. When it prints a URL, paste it into your local browser. The redirect to localhost:54545 now lands on the tunnel and reaches the server process.

The port differs per tool, and some tools pick a random one at runtime. If the callback hangs, run ss -tlnp on the server to see what port the CLI is actually listening on, then open a second tunnel for that port.

An alternative for some tools is a long-lived API key set as an environment variable, which sidesteps OAuth entirely. Check whether your agent supports it before wrestling with tunnels.

Step 4: Make sessions persistent

Run agents inside tmux so that an SSH disconnect — a train tunnel, a closed laptop — doesn't kill the run:

tmux new -s agent

Detach with Ctrl-b then d. Reattach later, from any device, with tmux attach -t agent. This is the piece that makes remote agents actually valuable: the work continues while you're gone.

Give each long-running task its own named session. Debugging a wedged agent is much easier when you haven't stacked four of them in one window.

Step 5: Get a database running

Most real work needs one. A local PostgreSQL on the same box is faster than a managed database over the network and costs nothing extra:

sudo apt install postgresql
sudo -u postgres createuser --interactive
sudo -u postgres createdb myapp

Leave it bound to localhost. Exposing PostgreSQL to the internet on the default port is the second-fastest way to get compromised, after password SSH.

Set up pg_dump on a cron schedule now rather than after you need it.

Step 6: Reach your dev server

A dev server bound to localhost:3000 on the VPS isn't reachable from your laptop. Three options, in increasing order of effort:

SSH tunnel — zero setup, works immediately, only for you:

ssh -L 3000:localhost:3000 user@your-server-ip

Firewall rule — bind the dev server to 0.0.0.0, open the port with ufw, and hit the IP directly. Simple, but you're serving an unauthenticated dev build to the open internet.

Reverse proxy with TLS — Caddy is the least painful path, and gets you a real HTTPS URL you can send to someone:

preview.yourdomain.com {
  reverse_proxy localhost:3000
}

Caddy provisions the certificate automatically. Point a DNS A record at your server first.

What this costs you

Done carefully, expect two to four hours the first time, and a recurring tax afterward: OS patches, certificate edge cases, disk filling with build artifacts, and redoing agent auth when a token expires. You also own the security posture of a box with your source code and database on it.

That tradeoff is worth it for the workflow it unlocks. Whether it's worth doing by hand is a separate question — it's the same configuration every time, which is why ForgeVPS ships it preconfigured: agents installed and authenticated, an editor and root terminal in the browser, PostgreSQL already local, and dev servers that get an HTTPS preview URL without a proxy config.

Either way, the important part is that the machine doing the work isn't the one in your bag.