An AI agent is rarely a single process. There's the agent loop itself, a vector store for memory, a cache, usually a database for state, and maybe a small dashboard. Running each of those by hand — starting them, restarting them after a reboot, remembering which port is which — gets old fast. Docker Compose describes the whole thing in one file and runs it with one command. This is the copy-paste stack for putting an agent on a VPS the tidy way.
If you just want the deploy-without-Docker version, the run an AI agent 24/7 guide covers systemd instead. This page is the container-native version.
The stack
A typical self-hosted agent wants four things next to it: the agent process, Qdrant (vector memory), Redis (cache / queues) and Postgres (state). Here's a docker-compose.yml that runs all of it, with internal services kept off the public internet:
# /opt/agent/docker-compose.yml
services:
agent:
build: . # your agent image (or image: your/agent:latest)
restart: unless-stopped
env_file: [.env] # OPENAI/ANTHROPIC keys etc. — never in this file
environment:
QDRANT_URL: http://qdrant:6333
REDIS_URL: redis://redis:6379
DATABASE_URL: postgres://agent:${DB_PASSWORD}@postgres:5432/agent
depends_on: [qdrant, redis, postgres]
# no ports: — this agent only makes outbound calls. Publish one only if it serves webhooks.
qdrant:
image: qdrant/qdrant:latest
restart: unless-stopped
volumes: ["qdrant:/qdrant/storage"] # internal only — not published
redis:
image: redis:7-alpine
restart: unless-stopped
command: ["redis-server", "--save", "60", "1"]
volumes: ["redis:/data"]
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_USER: agent
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: agent
volumes: ["pg:/var/lib/postgresql/data"]
volumes: { qdrant: {}, redis: {}, pg: {} }
Secrets live in .env, not the compose file:
# /opt/agent/.env (chmod 600, never committed)
ANTHROPIC_API_KEY=sk-ant-...
DB_PASSWORD=a-long-random-string
Bring it up:
apt update && apt install -y docker.io docker-compose-v2
systemctl enable --now docker
cd /opt/agent && docker compose up -d
docker compose logs -f agent
Every internal service (Qdrant, Redis, Postgres) is reachable only on the compose network by service name — none of them are published to the internet. The agent talks to them over that private network, and nothing on those ports faces the world.
The details that matter
restart: unless-stoppedon every service — that's what survives a reboot or a crash. Enable Docker on boot and the whole stack comes back on its own.- Keys in
.env, not YAML. Reference them as env vars; keep.envatchmod 600and out of git. A leaked compose file with a live key is the classic mistake. - Publish nothing you don't have to. An agent that only calls model APIs and its own services needs no inbound port at all — so a NAT plan works. Add a dedicated IP only if it serves webhooks or a dashboard.
- Size for memory, not cores. API-backed agents are light. If Qdrant's index grows large or you add a local model, that's when you move up — see high-memory VPS for agents.
The part that's actually ours: the agent can build its own box
Because EQVPS exposes an MCP server, an agent running this stack can provision another clean VPS on its own — order it, get root, tear it down — paying from a prepaid crypto balance. A compose stack that needs a fresh sandbox can spin one up without a human in the loop.
Why EQVPS for a Dockerized agent
- Clean images, root in ~60 seconds. Ubuntu/Debian;
docker compose upand the stack is live. - No KYC, crypto payment. Email to register, USDC/USDT to pay — nothing tying the box to your identity.
- NVMe + unmetered 1 Gbit/s, EU (Germany/Finland). Pulling images and shipping logs won't produce a surprise bill.
VPS for AI agents (the overview) → · VPS for Docker → · Host a vector DB for agent memory →
Comments
No comments yet. Be the first.