How to Self-Host AI Agents on a VPS for Business Automation
Purpose
In this post, I will demonstrate how to self-host AI agents on a VPS for 24/7 business automation using Docker.
Problem
I wanted AI agents running autonomously 24/7, but I ran into several problems with cloud-based solutions:
- Dependency on third-party services creates single points of failure
- Data privacy concerns when sensitive workflows run on external platforms
- Need for custom integrations with internal tools and APIs
- Cost unpredictability with cloud-based agent platforms
- Limited control over the automation stack
I needed a solution that gives me full control, reduces dependency on external platforms, and allows agents to operate continuously with complete data privacy.
Environment
- Ubuntu 22.04 VPS
- Docker and Docker Compose
- OpenClaw agent framework
- Ollama for local model support
- PostgreSQL for persistence
- Caddy for reverse proxy with SSL
Solution
I deployed a complete AI agent stack on a VPS using Docker. Here’s how I did it.
Step 1: Choose Your VPS Provider
I selected a VPS with minimum specifications:
- 4GB RAM
- 2 vCPUs
- 50GB SSD
Recommended providers include DigitalOcean, Linode, Hetzner, or AWS Lightsail. Ensure the provider allows Docker installation and outbound API calls.
Step 2: Install Docker and Docker Compose
# Update systemsudo apt update && sudo apt upgrade -y
# Install Dockercurl -fsSL https://get.docker.com -o get-docker.shsudo sh get-docker.sh
# Add user to docker groupsudo usermod -aG docker $USER
# Log out and back in for group changes to take effectStep 3: Create Project Structure
# Create project directorymkdir ~/ai-agents && cd ~/ai-agents
# Create necessary directoriesmkdir -p data config logs backupsStep 4: Create Docker Compose Configuration
I created a complete docker-compose.yml with OpenClaw, PostgreSQL, Ollama, and Prometheus for monitoring:
version: '3.8'
services: openclaw: image: openclaw/openclaw:latest container_name: openclaw restart: unless-stopped ports: - "3000:3000" volumes: - ./data:/app/data - ./config:/app/config - ./logs:/app/logs environment: - OPENAI_API_KEY=${OPENAI_API_KEY} - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY} - OLLAMA_BASE_URL=http://ollama:11434 - DATABASE_URL=postgresql://openclaw:${DB_PASSWORD}@postgres:5432/openclaw depends_on: - postgres - ollama networks: - agent-network
postgres: image: postgres:15-alpine container_name: openclaw-postgres restart: unless-stopped environment: - POSTGRES_USER=openclaw - POSTGRES_PASSWORD=${DB_PASSWORD} - POSTGRES_DB=openclaw volumes: - postgres_data:/var/lib/postgresql/data networks: - agent-network
ollama: image: ollama/ollama:latest container_name: ollama restart: unless-stopped ports: - "11434:11434" volumes: - ollama_data:/root/.ollama networks: - agent-network
prometheus: image: prom/prometheus:latest container_name: prometheus ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml networks: - agent-network
networks: agent-network: driver: bridge
volumes: postgres_data: ollama_data:Step 5: Configure Environment Variables
# Create .env file with your API keyscat > .env << 'EOF'OPENAI_API_KEY=your_openai_key_hereANTHROPIC_API_KEY=your_anthropic_key_hereDB_PASSWORD=your_secure_db_password_hereALERT_WEBHOOK=https://your-webhook-url.com/alertEOF
# Secure the filechmod 600 .envStep 6: Set Up Reverse Proxy with SSL
I used Caddy for automatic HTTPS:
# Install Caddysudo apt install -y caddy
# Configure Caddyfilecat > /etc/caddy/Caddyfile << 'EOF'your-domain.com { reverse_proxy localhost:3000}EOF
# Restart Caddysudo systemctl restart caddyStep 7: Start the Stack
# Start all servicesdocker-compose up -d
# Check statusdocker-compose ps
# View logsdocker-compose logs -f openclawStep 8: Create Health Check Script
I created a health check script to monitor agent health and restart if needed:
#!/bin/bash# health-check.sh - Monitor agent health and restart if needed
# Check if OpenClaw is respondingif ! curl -f http://localhost:3000/health > /dev/null 2>&1; then echo "$(date): OpenClaw not responding, restarting..." docker-compose restart openclaw # Send alert curl -X POST "${ALERT_WEBHOOK}" -d '{"text": "OpenClaw restarted due to health check failure"}'fi
# Check disk spaceDISK_USAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')if [ $DISK_USAGE -gt 80 ]; then echo "$(date): Disk usage at ${DISK_USAGE}%" # Clean up old logs find ./logs -type f -mtime +7 -deletefiStep 9: Set Up Automated Tasks
# Add to crontab with: crontab -e# Run health check every 5 minutes*/5 * * * * /home/user/ai-agents/health-check.sh >> /home/user/ai-agents/cron.log 2>&1
# Backup database daily at 2 AM0 2 * * * docker exec openclaw-postgres pg_dump -U openclaw openclaw > /home/user/backups/openclaw_$(date +\%Y\%m\%d).sqlStep 10: Verify Everything Works
# Check all containers are runningdocker-compose ps
# Test OpenClaw health endpointcurl http://localhost:3000/health
# Test Ollamacurl http://localhost:11434/api/version
# Test PostgreSQL connectiondocker exec -it openclaw-postgres psql -U openclaw -d openclaw -c "SELECT 1;"When I ran these commands, I saw:
$ docker-compose psNAME COMMAND STATUS PORTSopenclaw "/app/entrypoint.sh" Up 2 hours 0.0.0.0:3000->3000/tcpopenclaw-postgres "docker-entrypoint.s…" Up 2 hours 5432/tcpollama "/bin/ollama serve" Up 2 hours 0.0.0.0:11434->11434/tcpprometheus "/bin/prometheus --c…" Up 2 hours 0.0.0.0:9090->9090/tcp
$ curl http://localhost:3000/health{"status": "healthy", "version": "1.0.0"}The Reason
Self-hosting AI agents on a VPS provides several key benefits:
Data Sovereignty: All sensitive business data stays on your infrastructure. No third-party access to your workflows or agent memory.
Cost Control: Predictable monthly VPS costs (around $20-40/month) versus variable cloud platform fees that can spike unexpectedly.
Customization Freedom: Modify agent behavior without platform restrictions. Add custom tools, integrate with internal APIs, and tune responses to your needs.
Reliability: No dependency on third-party uptime SLAs. Your agents run on your schedule.
Compliance: Meet regulatory requirements for data handling. Perfect for industries with strict data residency rules.
Common Mistakes to Avoid
I made these mistakes so you don’t have to:
Insufficient Resources: I initially deployed on a 1GB RAM VPS. The agent kept timing out. Upgrade to at least 4GB RAM for reliable operation.
No Backup Strategy: I lost agent memory and conversation history once. Now I back up the PostgreSQL database daily.
Ignoring Security: I initially exposed agent endpoints without authentication. Always use a reverse proxy with proper authentication.
Hardcoded Credentials: I accidentally committed API keys to git once. Use environment variables and add .env to .gitignore.
No Monitoring: Agents can fail silently. Set up Prometheus alerts for failures or anomalies.
Over-Reliance on Cloud Models: When OpenAI had an outage, my agents stopped. I added Ollama as a fallback for critical workflows.
Missing Rate Limits: I exhausted my API quota mid-task, leaving agents in inconsistent states. Now I implement rate limiting and checkpointing.
Summary
In this post, I demonstrated how to self-host AI agents on a VPS using Docker. The key components are: Docker Compose for orchestration, PostgreSQL for persistence, Ollama for local model fallback, and Caddy for secure access. Start with a basic deployment and add monitoring, backups, and health checks from day one.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Docker Documentation
- 👨💻 Ollama
- 👨💻 Caddy Server
- 👨💻 PostgreSQL Docker Image
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments