VPS Setup and Hardening
Choose a VPS provider, create a non-root user, configure SSH key authentication, set up a firewall, install Node.js and Claude Code, and complete first-time OAuth authentication.
- Choose the right VPS provider and plan for remote Claude Code workloads based on memory, disk, and pricing
- Create a non-root Linux user with correct sudoers restrictions for running Claude Code safely
- Harden SSH access with key-only authentication and disable password login
- Configure a firewall (ufw or iptables) to allow only required ports from required sources
- Install Node.js 22, Claude Code CLI, and complete first-time OAuth authentication on the VPS
01VPS Provider Comparison and Sizing
Claude Code itself is lightweight at runtime. What you actually need is a VPS with enough memory to run Node.js comfortably plus any co-located services you intend to add later.
Minimum specs for solo Claude Code:
- 2 GB RAM (1 GB works, but is tight once you add any other service)
- 1 vCPU
- 40 GB disk (most of this is for logs and workspace files, not Claude Code itself)
- Linux (Ubuntu 22.04 or 24.04 LTS recommended)
Realistic specs if you plan to add other services (n8n, Traefik, Postgres, monitoring):
- 4-8 GB RAM
- 2-4 vCPU
- 100-400 GB disk
Provider comparison (2026 pricing):
| Provider | Entry plan | Price intro | Renewal | Notes |
|---|---|---|---|---|
| Hostinger KVM 1 | 1 vCPU, 4 GB, 50 GB | $4.99/mo | ~$11/mo | 24-month term, aggressive intro |
| Hostinger KVM 2 | 2 vCPU, 8 GB, 100 GB | $6.99/mo | ~$15/mo | Sweet spot for multi-service |
| Hetzner CX22 | 2 vCPU, 4 GB, 40 GB | $4.59/mo | $4.59/mo | Monthly, no contract, German data center |
| DigitalOcean Basic | 1 vCPU, 2 GB, 50 GB | $12/mo | $12/mo | Easiest UI, most docs |
| Vultr Cloud Compute | 1 vCPU, 2 GB, 55 GB | $10/mo | $10/mo | Many regions |
| Contabo VPS S | 4 vCPU, 8 GB, 200 GB | $6.99/mo | $6.99/mo | Best specs-per-dollar, slower support |
Our pick for this Pro Track: Hostinger KVM 2 at $7/mo intro. 8 GB RAM gives room to add n8n, a web service, and a knowledge graph later without a resize. The intro pricing lowers the barrier to experimentation.
Deal-breakers to avoid: providers with CPU-stealing neighbors (shared-hypervisor OpenVZ providers, ultra-low-end VPS marketplaces), providers with unclear data residency policies, and anything without KVM virtualization.
02Initial Ubuntu Setup and Non-Root User
Never run Claude Code as root. Anthropic explicitly recommends against it, and the VS Code extension refuses to start as root for security reasons. Create a dedicated user on first login.
Step 1: SSH in as root the first time (via the password your VPS provider emailed):
ssh root@your.vps.ip.addressStep 2: Update the system and install basic tooling:
apt update && apt upgrade -y
apt install -y curl wget git tmux ufw fail2ban htopStep 3: Create a non-root user for Claude Code:
We will call this user claude-user throughout this Pro Track, but you can pick any name.
adduser claude-user
# Set a strong password when prompted. You will mostly use SSH keys,
# but having a password is still useful for sudo.
# Grant sudo access (you can lock this down further in Module 6):
usermod -aG sudo claude-user
# Switch to the new user to verify:
su - claude-user
whoami # should print: claude-user
exit # return to rootStep 4: Copy SSH keys to the new user so you can log in directly:
mkdir -p /home/claude-user/.ssh
cp /root/.ssh/authorized_keys /home/claude-user/.ssh/
chown -R claude-user:claude-user /home/claude-user/.ssh
chmod 700 /home/claude-user/.ssh
chmod 600 /home/claude-user/.ssh/authorized_keysFrom a separate terminal on your laptop, test the new user login:
ssh claude-user@your.vps.ip.addressIf that works, you are ready to disable root SSH access in the next section.
03Harden SSH: Keys Only, No Root Login
Password authentication and root SSH access are the two biggest attack vectors for a public-facing VPS. Both should be disabled within the first hour of setting up the server.
Edit the SSH daemon config:
sudo nano /etc/ssh/sshd_configFind and set (or add) these three lines:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yesSave (Ctrl+O, Enter, Ctrl+X) and reload sshd:
sudo systemctl reload sshTest from a separate terminal before closing the current session:
# Should succeed:
ssh claude-user@your.vps.ip.address
# Should FAIL (password auth disabled):
ssh some-password-only-user@your.vps.ip.address
# Should FAIL (root login disabled):
ssh root@your.vps.ip.addressIf your test session in a new window still works with keys, you are hardened. Close your original root SSH session.
Bonus: install fail2ban for brute-force protection:
sudo systemctl enable --now fail2banFail2ban watches auth logs and auto-bans IPs that fail SSH auth too many times. This matters even with password auth disabled, because aggressive scanning still consumes CPU and fills logs.
04Firewall: Only Open What You Need
A fresh VPS has all ports open by default. Lock it down with ufw (Uncomplicated Firewall), a friendlier wrapper around iptables.
Baseline firewall rules for a Claude Code VPS:
# Set default policies
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (otherwise you lock yourself out)
sudo ufw allow 22/tcp
# Allow HTTP and HTTPS (if you plan to add web services like n8n)
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable the firewall
sudo ufw enable
# Verify:
sudo ufw status verboseWhat this gives you:
- Only SSH, HTTP, and HTTPS are reachable from the internet
- All outbound traffic allowed (Claude needs to reach the Anthropic API, Telegram servers, GitHub, npm registry, etc.)
- Anything else is blocked by default
Gotchas to know:
- If you plan to add Docker later (for n8n, Traefik, etc.), Docker bypasses ufw by default via its own iptables rules. This is a well-documented Docker quirk. Use the DOCKER-USER chain to block Docker-exposed ports from the public internet.
- If you change your SSH port away from 22 (a common hardening step), update the ufw rule BEFORE reloading sshd, or you lock yourself out.
- Cloud provider firewalls (Hostinger, DigitalOcean, Hetzner) exist independently of ufw. A port blocked at the provider level but open in ufw is still blocked. Check both layers when troubleshooting.
05Install Node.js 22 and Claude Code
Claude Code requires Node.js 18+, but we recommend Node.js 22 LTS for long-term stability. Use NodeSource, not the default Ubuntu apt repos, because Ubuntu LTS ships an older Node.js.
Install Node.js 22 from NodeSource:
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
sudo apt install -y nodejs
node --version # should print v22.x.x
npm --versionInstall Claude Code globally:
sudo npm install -g @anthropic-ai/claude-code@latest
claude --versionFirst-time authentication:
su - claude-user # switch to your non-root user if not already
cd ~
claudeClaude Code will prompt you to authenticate. Two paths:
Path A: Claude Pro subscription (Anthropic account login)
- Opens a browser-based auth flow.
- The CLI prints a URL. Open it on any device (your laptop, your phone). Log in with your Anthropic account. Claude stores the OAuth token in
~/.claude/auth.json. - OAuth tokens currently expire after roughly 18 months. Plan to rotate them annually.
Path B: API key (pay-as-you-go)
- Generate an API key at console.anthropic.com.
- Paste it when prompted.
- API keys do not expire unless you rotate them manually.
Verify Claude Code works:
> Hello, tell me what directory I am inClaude should respond and, if you approve the tool call, run pwd and report back. If you see the conversation working, you have a functional Claude Code installation on your VPS.
Next: Module 3 wraps this installation in a systemd service so it persists across reboots and disconnects.
- 01Hostinger KVM 2 at $7/mo intro hits the sweet spot for a Claude Code VPS with room for co-located services
- 02Never run Claude Code as root; create a dedicated non-root user with sudo for administrative tasks only
- 03Harden SSH with keys-only auth and no root login within the first hour of setup; test before disabling
- 04Use ufw for a simple firewall baseline (SSH + HTTP + HTTPS only) and be aware Docker bypasses ufw via DOCKER-USER chain
- 05Install Node.js 22 LTS from NodeSource rather than Ubuntu default repos; OAuth tokens expire annually and need rotation