Skip to content

Deployment

Guides for deploying Prometheal in production.


One-command production deployment with auto-TLS, Redis, and secure defaults.

Prerequisites

  • Docker and Docker Compose
  • A server with 2+ GB RAM
  • A domain name (for TLS) — or use localhost for testing

Deploy

bash
git clone https://github.com/ia03/prometheal.git
cd prometheal
./deploy.sh

The script will:

  1. Ask for your domain (or press Enter for localhost)
  2. Generate secure random secrets (JWT, encryption key, Postgres password)
  3. Build the sandbox image
  4. Start the full stack: App + PostgreSQL + Redis + Caddy
  5. Wait for the server to be healthy

Once ready, open the URL to complete the setup wizard.

What's included

ServicePurpose
AppPrometheal (Next.js, standalone build)
PostgreSQL 16Database (secure random password)
Redis 7Distributed state (rate limits, session cache, locks)
Caddy 2Reverse proxy with automatic TLS certificate provisioning

Localhost mode

If you skip the domain prompt (just press Enter), the stack runs at http://localhost on port 80. Caddy serves as a plain HTTP reverse proxy — no TLS. This is useful for local testing.

Domain mode

When you provide a domain (e.g., prometheal.example.com), Caddy automatically provisions a TLS certificate via Let's Encrypt. Make sure:

  • DNS for the domain points to your server
  • Ports 80 and 443 are open (Caddy needs both for ACME challenges)

gVisor adds kernel-level sandboxing on top of Docker:

bash
sudo apt-get install -y runsc
sudo runsc install
sudo systemctl restart docker

Managing the stack

bash
docker compose -f docker-compose.prod.yml logs -f      # View logs
docker compose -f docker-compose.prod.yml down          # Stop
docker compose -f docker-compose.prod.yml up -d         # Restart
docker compose -f docker-compose.prod.yml ps            # Status

Re-running deploy.sh

The script is idempotent. If .env.production already exists, it keeps the existing config. If the sandbox image already exists, it skips the build. Delete .env.production to regenerate secrets.


Manual single instance (Docker Compose)

If you prefer to configure things yourself instead of using deploy.sh.

Prerequisites

  • Docker and Docker Compose
  • A server with 2+ GB RAM
  • A domain name (recommended) with TLS termination (nginx, Caddy, or cloud load balancer)

1. Clone and configure

bash
git clone https://github.com/ia03/prometheal.git
cd prometheal
cp .env.example .env

Generate secrets:

bash
# JWT secret
echo "JWT_SECRET=$(openssl rand -base64 32)" >> .env

# Encryption key (64 hex chars)
echo "ENCRYPTION_KEY=$(node -e "console.log(require('crypto').randomBytes(32).toString('hex'))")" >> .env

Edit .env:

bash
DATABASE_URL=postgresql://prometheal:your-strong-password@postgres:5432/prometheal
NEXT_PUBLIC_APP_URL=https://prometheal.yourdomain.com
SANDBOX_PROVIDER=docker

2. Build the sandbox image

bash
docker build -t prometheal-sandbox:latest -f sandbox/Dockerfile sandbox/
bash
sudo apt-get install -y runsc
sudo runsc install
sudo systemctl restart docker

4. Start

bash
docker compose up -d

5. Set up a reverse proxy

Example with Caddy (auto-TLS):

prometheal.yourdomain.com {
    reverse_proxy localhost:3000
}

Example with nginx:

nginx
server {
    listen 443 ssl;
    server_name prometheal.yourdomain.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Required for SSE streaming (chat responses)
        proxy_buffering off;
        proxy_cache off;
    }
}

Important: Disable proxy buffering for the chat endpoints — Prometheal streams responses via server-sent events.


Multi-instance deployment

For high availability or handling more concurrent agents. Requires Redis for distributed state.

Architecture

                    ┌─────────┐
                    │  Nginx  │
                    │  (LB)   │
                    └────┬────┘
                    ┌────┴────┐
              ┌─────┤         ├─────┐
              ▼     ▼                ▼
        ┌──────┐ ┌──────┐    ┌──────┐
        │ App 1│ │ App 2│    │ App N│
        └──┬───┘ └──┬───┘    └──┬───┘
           │        │            │
           ▼        ▼            ▼
      ┌─────────┐  ┌─────────┐
      │PostgreSQL│  │  Redis  │
      └─────────┘  └─────────┘

Configuration

Use docker-compose.multi.yml:

bash
docker compose -f docker-compose.multi.yml up -d

Key differences from single-instance:

  • REDIS_URL must be set — enables distributed rate limiting, session cache, MCP tool cache, and sandbox locks
  • Nginx load balances across app instances
  • All instances share the same PostgreSQL and Redis

Scaling

bash
docker compose -f docker-compose.multi.yml up -d --scale app=3

Sticky sessions

The nginx config uses IP hash for session affinity. This isn't strictly required (sessions are stateless JWTs), but it helps with:

  • Tool confirmation flows (the pending confirmation is stored in-memory on the instance that started it)
  • MCP client connections (stdio processes are per-instance)

E2B Cloud deployment

If you don't want to manage sandbox infrastructure:

bash
SANDBOX_PROVIDER=e2b
E2B_API_KEY=your-key

Sandboxes run as Firecracker microVMs on E2B's infrastructure. You still need to host the Prometheal server, but sandbox containers are managed by E2B.


Database management

Migrations

Migrations run automatically on startup via docker-entrypoint.sh:

bash
node_modules/prisma/build/index.js migrate deploy

For manual migration:

bash
npx prisma migrate deploy    # production (applies pending migrations)
npx prisma migrate dev       # development (creates + applies migrations)

Backups

Use the included backup script for one-command backups:

bash
./backup.sh                           # Back up to ./backups/
./backup.sh /mnt/backups              # Custom backup directory
COMPOSE_FILE=docker-compose.prod.yml ./backup.sh  # Production stack

This backs up:

  1. PostgreSQL database — full pg_dump in custom format
  2. Uploads — agent documents and library files
  3. Encryption key — extracted from .env / .env.production (store this in a secure vault)
  4. Workspace volume list — for manual volume backup if needed

Restore:

bash
# Database
docker compose exec -T postgres pg_restore -U prometheal -d prometheal --clean < backups/<timestamp>/database.dump

# Uploads
tar -xzf backups/<timestamp>/uploads.tar.gz

Scheduled backups (cron):

bash
# Daily at 2 AM, keep 30 days
0 2 * * * cd /path/to/prometheal && COMPOSE_FILE=docker-compose.prod.yml ./backup.sh /mnt/backups && find /mnt/backups -maxdepth 1 -mtime +30 -exec rm -rf {} +

Critical

Always back up your ENCRYPTION_KEY separately in a secure vault (AWS Secrets Manager, HashiCorp Vault, 1Password). Without it, encrypted credentials in the database cannot be recovered.

Sandbox volumes

Agent workspaces are stored in Docker named volumes (prometheal-workspace-{agentId}). These persist across sandbox restarts. To back up a specific workspace:

bash
# List volumes
docker volume ls | grep prometheal-workspace

# Back up a volume
docker run --rm -v prometheal-workspace-<agentId>:/data -v $(pwd):/backup alpine tar czf /backup/workspace.tar.gz /data

Health checks

EndpointWhat it checks
GET /api/healthDatabase connection (public, used by Docker healthcheck)
GET /api/settings/systemDatabase connection, sandbox config, agent counts, uptime (admin only)
GET /api/llm-proxy/healthLLM proxy availability
GET /api/sandbox/healthSandbox provider health

Use these for monitoring and load balancer health checks.


Environment variable reference

See configuration.md for the complete list of environment variables.


Updating

bash
git pull
docker compose build
docker compose up -d

Migrations run automatically on startup. Always back up your database before updating.


Troubleshooting

Container won't start

bash
docker compose logs app

Common issues:

  • DATABASE_URL is wrong or PostgreSQL isn't running
  • ENCRYPTION_KEY is empty or not 64 hex chars
  • Port 3000 is already in use

Sandbox won't create

bash
docker compose logs app | grep sandbox

Common issues:

  • Docker socket not accessible (if Prometheal runs in Docker, mount /var/run/docker.sock)
  • Sandbox image not built (docker build -t prometheal-sandbox:latest -f sandbox/Dockerfile sandbox/)
  • E2B API key invalid or expired

Chat responses are slow or cut off

  • Check if proxy buffering is disabled in your reverse proxy
  • Ensure the LLM API key is valid (Settings > General)
  • Check spending limits (Settings > Usage)

MCP integration not connecting

bash
# Test the MCP server manually
npx -y @modelcontextprotocol/server-github
  • Check credentials are correct in Settings > Integrations
  • Check the integration status (ACTIVE/INACTIVE/ERROR)
  • Look for errors in the server logs

Released under the MIT License.