EQVPS

Docker Compose for AI agents: a full self-hosted stack on one VPS

Sep 6, 2026 · 3 min read · EQVPS Team

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

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

VPS for AI agents (the overview) → · VPS for Docker → · Host a vector DB for agent memory →

FAQ

Why run an AI agent with Docker Compose instead of bare processes?

An agent is rarely just one process — it's the agent loop plus a vector store, a cache and usually a database. Compose describes the whole stack in one file, brings it all up with one command, restarts each piece on crash or reboot, and keeps internal services (Postgres, Redis, Qdrant) on a private network so only what you choose is exposed. It's the tidiest way to self-host an agent that has moving parts.

What plan does an agent stack need?

For an API-backed agent (the model runs at your provider) the stack is light — the agent loop, Qdrant, Redis and Postgres fit comfortably on our Small ($8/mo) or the AI-Agent plan ($10/mo, 4 GB). You only need more RAM if you hold a large vector index in memory or run a local model, which is a different, heavier setup.

Where do I put the API keys — in the compose file?

No. Keep secrets in a .env file (git-ignored) and reference them as environment variables in compose, or use Docker secrets. Never commit keys into docker-compose.yml. Bind internal services to the compose network only; publish just the agent's port (or nothing, if it only makes outbound calls).

Do the containers come back after a reboot?

Only if you tell them to. Set restart: unless-stopped (or always) on each service and enable Docker on boot; then docker compose up -d survives reboots and crashes. Without a restart policy a container stays down after the server restarts.

Do you ask for KYC or a card?

No. Email to sign up, pay in USDC or USDT — no documents, no card. Root in about a minute.

← Back to blogSee plans & pricing →

Comments

No comments yet. Be the first.

Leave a comment

Comments are moderated before they appear.