Running One Docker Container Per User on a $35/Month Server

Published: (February 11, 2026 at 06:37 PM EST)
3 min read
Source: Dev.to

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:

  1. Start on demand – When a message arrives for user X, check if the container exists. If not, docker create + docker start.
  2. Idle cleanup – Every 5 minutes, stop containers that haven’t received a message recently.
  3. 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.

0 views
Back to Blog

Related posts

Read more »