Letting the AI Do It

I needed a dev server: VM with SSH access and dev tools installed. I described what I wanted to Claude Code and let it handle the setup.

The Prompt

I asked for a Vultr VM with 8 cores and 32GB of RAM, accessible only through Tailscale, with persistent sessions that survive network drops.

What Claude Code Built

1. Provisioned the VM via Vultr API

It created an 8-core/32GB Ubuntu instance, waited for the IP, then SSH’d in as root.

2. Hardened SSH

Port 49152                    # Random high port
PermitRootLogin no
PasswordAuthentication no
ListenAddress 100.x.x.x       # Tailscale interface only

Key-based auth only, listening only on the Tailscale interface.

3. Set up three layers of firewall

4. Installed Tailscale with SSH enabled

curl -fsSL https://tailscale.com/install.sh | sh
tailscale up --ssh --authkey=$TAILSCALE_KEY

This creates a second SSH path via Tailscale’s built-in SSH server, independent of OpenSSH.

5. Installed the dev stack

Node.js (via nvm), Python (via pyenv), Docker, and common tools. Configured Docker to run without sudo.

6. Set up persistent sessions with tmux

A startup script that automatically reattaches to an existing session, so network drops don’t kill running processes.

7. Created local management scripts

dev-start and dev-stop scripts on my laptop that spin the VM up and down via the Vultr API.

The Lockout

After finishing, Claude Code verified that root login was disabled by attempting to SSH in as root. The login failed. fail2ban noticed the failed attempts and banned us.

Claude Code had set up Tailscale SSH as a secondary path. It used tailscale ssh to get back in and ran:

fail2ban-client set sshd unbanip 100.x.x.x

Setup

You’ll need:

Store API keys as environment variables and reference them by name (e.g., $VULTR_API_KEY) so secrets don’t appear in the conversation.

Example prompt:

Create an 8-core VM on Vultr, lock it down so it’s only accessible via Tailscale, set up Node/Python/Docker, and give me scripts to start and stop it.