How to Deploy a Self-Hosted AI Agent Platform for $19/Month
How to Deploy a Self-Hosted AI Agent Platform for $19/Month
We run five AI agents — CEO, CTO, CMO, CFO, COO — with persistent memory, GitHub access, and a three-layer backup system. Total infrastructure cost: $19/month.
Here’s the exact stack, the tradeoffs we made, and the parts that will catch you if you’re not paying attention.
Why Self-Hosted
The obvious alternative is a managed AI agent platform. Several exist. They’re easier to set up, managed by someone else, and usually have better UIs.
We went self-hosted for three reasons:
Control over agent access. Our agents have access to a private GitHub repo with corporate strategy, financial planning, and unreleased content. Running that through a third-party SaaS means their infrastructure has access to your most sensitive context. That’s a risk profile we weren’t comfortable with.
Cost at scale. SaaS agent platforms charge per seat, per action, or per compute minute. At five agents running continuously, costs add up fast. Our $19/month is fixed regardless of how many tasks the agents run.
Auditability. Every agent action, every PR, every config change goes through our own infrastructure and version control. We know exactly what ran and when.
The Stack
AWS EC2 t4g.small (ARM64) $12/month
20GB root EBS volume (gp3) $1.60/month
20GB data EBS volume (gp3) $1.60/month
EBS snapshots (14-day DLM) ~$1.60/month
KMS encryption key $1.00/month
S3 backup storage < $0.50/month
SSM / CloudWatch < $1.00/month
─────────────────────────────────────────
Total ~$19/month
The t4g.small is ARM64 with 2GB RAM. It runs:
- PostgreSQL 17 (Alpine, external container)
- Paperclip AI server (Node.js, ~400MB RAM)
- 2GB swap file (required — Node.js + Postgres hits the ceiling without it)
The Security Architecture
No SSH port open. No inbound ports at all. Access is exclusively through AWS Systems Manager Session Manager, which routes through the SSM agent running on the instance.
UI access uses SSM port forwarding:
aws ssm start-session `
--target i-YOUR-INSTANCE-ID `
--region us-east-1 `
--profile your-profile `
--document-name AWS-StartPortForwardingSession `
--parameters portNumber=3100,localPortNumber=3100
Then open http://localhost:3100 in your browser. The port forward runs over the SSM tunnel — no public IP required, no security group rules needed.
Secrets live in AWS SSM Parameter Store encrypted with a dedicated KMS key. The instance IAM role can only read /paperclip-app/* parameters — nothing else.
The Docker Setup That Actually Works
This took us several iterations to get right. The final working configuration:
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_USER: paperclip
POSTGRES_PASSWORD: paperclip
POSTGRES_DB: paperclip
healthcheck:
test: ["CMD-SHELL", "pg_isready -U paperclip -d paperclip"]
interval: 2s
retries: 30
volumes:
- /data/paperclip/pgdata:/var/lib/postgresql/data
server:
build: .
user: "1000:1000" # REQUIRED — Claude CLI refuses to run as root
ports:
- "3100:3100"
environment:
DATABASE_URL: postgres://paperclip:paperclip@db:5432/paperclip
BETTER_AUTH_SECRET: "${BETTER_AUTH_SECRET:?must be set}"
GITHUB_TOKEN: "${GITHUB_TOKEN}"
volumes:
- /data/paperclip/appdata:/paperclip
- /data/paperclip/appdata:/app/data # REQUIRED — agent workspace creation
depends_on:
db:
condition: service_healthy
Three things that will break silently if you miss them:
user: "1000:1000" — Claude CLI has a hard check that refuses to run with --dangerously-skip-permissions when running as root. Without this, every agent task fails immediately.
/app/data volume mount — Paperclip tries to create agent workspace directories under /app/data inside the container. If this path isn’t mounted to persistent storage, it either fails on creation (EACCES) or creates ephemeral directories that disappear on container restart.
Bind mounts, not named volumes — Named volumes work until your container names change, which happens when you modify your compose configuration. Bind mounts at explicit paths survive any container configuration change.
The ARM64 Gotcha
The t4g.small is ARM64. Most Docker images handle this fine, but the Paperclip build process has one catch: the Vite build OOMs on 2GB RAM.
Fix:
# Before building
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile none swap sw 0 0" >> /etc/fstab
Add this to your bootstrap script so it’s permanent across reboots.
The Agent Workspace Setup
Each agent gets its own clone of the repo as a working directory:
# On the instance
for ROLE in ceo cto cmo cfo coo; do
docker exec server git clone \
https://YOUR-BOT:$GITHUB_TOKEN@github.com/YOUR-ORG/YOUR-REPO \
/paperclip/workspace/$ROLE
done
# Configure git credentials for agent git operations
docker exec server sh -c 'git config --global credential.helper store'
docker exec server sh -c 'echo "https://YOUR-BOT:$GITHUB_TOKEN@github.com" > /root/.git-credentials'
Why separate clones per agent: simultaneous agent tasks that modify files create merge conflicts if they share a working directory. Separate clones mean each agent’s changes are isolated until they open a PR.
What the $19 Gets You
For $19/month you get:
- Five persistent AI agents with memory, projects, and issues
- A private GitHub-connected workspace for each agent
- Three-layer backup protection (bind mounts + EBS snapshots + nightly pg_dump)
- End-to-end encryption (KMS for secrets, EBS encryption at rest)
- Zero-trust access (no open ports, SSM-only access)
- Full Terraform IaC so you can rebuild from scratch in under 2 hours
That last point isn’t marketing. We know it’s true because we had to do it.
The Things That Aren’t Solved
Honest accounting of what $19/month doesn’t buy you:
Agent-to-agent coordination is manual. The CEO can assign tasks to the CTO, but they don’t have a native communication channel — you wire it together through Paperclip’s task system and manual review.
Compute scaling isn’t automatic. A t4g.small handles five agents fine when they’re running sequentially. If you start running five simultaneous heavy tasks, you’ll hit memory limits.
No managed SSL. The UI is accessible only via SSM port forward, so there’s no public URL, no SSL cert, no CDN. For internal team use, this is fine. For a public-facing agent interface, you’d need a different architecture.
For a small AI-native company running internal operations, though, $19/month is the right answer.
Comments