Running One Docker Container Per User on a $35/Month Server
Source: Dev.to
Overview
I run a Telegram AI bot where each user gets their own Docker container. This setup works on a single cheap GCP instance without Kubernetes.
The AI companion bot gives each user a persistent agent with its own memory, personality file, and schedule. Users never see each other’s data, and each agent needs an isolated filesystem.
Options Considered
- Shared process, per‑user directories – cheapest, but one crash kills everyone.
- Kubernetes – overkill for 10–50 users on one machine.
- Docker containers, managed by a gateway – just right.
Architecture
gateway container (always running)
|
+-- User A container (started on demand)
+-- User B container (started on demand)
+-- User C container (idle, stopped after 60 min)
The gateway manages the container lifecycle:
- Start on demand – When a message arrives for user X, check if the container exists. If not,
docker create+docker start. - Idle cleanup – Every 5 minutes, stop containers that haven’t received a message recently.
- Zero resource usage when stopped – Docker keeps the filesystem, so state persists.
Gateway Logic (TypeScript)
async function ensureContainer(userId: string): Promise {
const name = `adola-user-${userId.slice(0, 8)}`;
try {
const info = await docker.inspect(name);
if (!info.State.Running) {
await docker.start(name);
}
return name;
} catch {
await docker.create({
name,
Image: "adola-agent:latest",
HostConfig: {
Binds: [`/data/users/${userId}/workspace:/workspace`],
NetworkMode: "adola-net"
}
});
await docker.start(name);
return name;
}
}
Resource Usage (e2‑medium, 4 GB RAM)
- Baseline (gateway + Postgres + Caddy): ~400 MB
- Each active user container: ~150–200 MB
- Stopped containers: 0 MB (filesystem only)
With 8 users, peak usage during the heartbeat cycle (all containers briefly active) is ~2 GB, leaving comfortable headroom.
Docker Configuration
The gateway mounts the Docker socket so it can manage sibling containers (the “Docker‑out‑of‑Docker” pattern).
gateway:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /data:/data
All containers join the same Docker bridge network (adola-net). The gateway calls user containers by name:
http://adola-user-abc12345:18789/v1/chat/completions
Docker DNS handles resolution, so no port mapping is needed.
Scaling Considerations
For 100+ users you might add:
- Container pooling – pre‑warm a few idle containers.
- Horizontal scaling – multiple gateway instances with consistent hashing.
- Prometheus metrics – monitor container lifecycle.
For the 8–50 user range, the simple approach works perfectly.
Live Demo
The system is live at t.me/adola2048_bot. Each user gets their own isolated AI agent container on Telegram.