Skip to main content
The fastest way to self-host Private Connect is using Docker Compose, which handles all dependencies and networking automatically.

Prerequisites

1

Install Docker

Install Docker Engine and Docker Compose:
# Ubuntu/Debian
curl -fsSL https://get.docker.com | sh

# Verify installation
docker --version
docker compose version
2

Clone the repository

git clone https://github.com/treadiehq/private-connect.git
cd private-connect

Docker Compose Configuration

The included docker-compose.yml defines three services:
services:
  postgres:
    image: postgres:16-alpine
    ports:
      - "5433:5432"   # Mapped to 5433 to avoid local Postgres conflicts
    environment:
      POSTGRES_USER: privateconnect
      POSTGRES_PASSWORD: privateconnect
      POSTGRES_DB: privateconnect
    volumes:
      - postgres-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U privateconnect"]
      interval: 5s
      timeout: 5s
      retries: 5

  api:
    build:
      context: ./apps/api
      dockerfile: Dockerfile
    ports:
      - "3001:3001"
      - "23000-23100:23000-23100"  # Tunnel ports range
    environment:
      - DATABASE_URL=postgresql://privateconnect:privateconnect@postgres:5432/privateconnect
      - PORT=3001
    depends_on:
      postgres:
        condition: service_healthy

  web:
    build:
      context: ./apps/web
      dockerfile: Dockerfile
    ports:
      - "3000:3000"
    environment:
      - NUXT_PUBLIC_API_URL=http://localhost:3001
    depends_on:
      - api

volumes:
  postgres-data:

Deployment Steps

1

Configure environment variables

Create a .env file in the project root to customize settings:
# Database credentials
POSTGRES_USER=privateconnect
POSTGRES_PASSWORD=your_secure_password_here
POSTGRES_DB=privateconnect

# API configuration
NODE_ENV=production
PORT=3001

# Email authentication (optional)
RESEND_API_KEY=re_xxxxxxxxxxxx
EMAIL_FROM="Private Connect <[email protected]>"
APP_URL="https://yourdomain.com"

# Web UI API endpoint
NUXT_PUBLIC_API_URL=http://localhost:3001
Change the default PostgreSQL password in production!
2

Start the services

Build and start all containers:
docker compose up --build -d
This will:
  • Pull the PostgreSQL 16 Alpine image
  • Build the API container from apps/api/Dockerfile
  • Build the Web UI container from apps/web/Dockerfile
  • Create a persistent volume for PostgreSQL data
  • Start all services with proper health checks
3

Run database migrations

Initialize the database schema:
docker compose exec api pnpm db:push
This runs Prisma migrations to set up all tables, indexes, and relations.
4

Verify deployment

Check that all services are running:
docker compose ps
You should see:
NAME                STATUS              PORTS
postgres            Up (healthy)        0.0.0.0:5433->5432/tcp
api                 Up (healthy)        0.0.0.0:3001->3001/tcp, 0.0.0.0:23000-23100->23000-23100/tcp
web                 Up                  0.0.0.0:3000->3000/tcp
5

Access the dashboard

Open your browser and navigate to:
http://localhost:3000
The API is available at:
http://localhost:3001

Port Mappings

Host PortContainer PortServicePurpose
54335432PostgreSQLDatabase (mapped to 5433 to avoid conflicts)
30013001API HubAgent connections & REST API
23000-2310023000-23100API HubTunnel port range (101 concurrent tunnels)
30003000Web UIDashboard interface
PostgreSQL is mapped to host port 5433 instead of 5432 to avoid conflicts with a locally-running PostgreSQL instance.

Managing the Deployment

View Logs

Follow logs from all services:
docker compose logs -f
View logs for a specific service:
docker compose logs -f api
docker compose logs -f web
docker compose logs -f postgres

Stop Services

docker compose down
Stop and remove volumes (deletes all data):
docker compose down -v

Restart Services

docker compose restart
Restart a specific service:
docker compose restart api

Rebuild Containers

After code changes, rebuild without cache:
docker compose down
docker compose build --no-cache
docker compose up -d
Or use the npm script:
pnpm docker:rebuild

Database Management

Access Database Shell

docker compose exec postgres psql -U privateconnect -d privateconnect

Backup Database

docker compose exec postgres pg_dump -U privateconnect privateconnect > backup.sql

Restore Database

cat backup.sql | docker compose exec -T postgres psql -U privateconnect -d privateconnect

Open Prisma Studio

Inspect and edit database records with a GUI:
docker compose exec api pnpm db:studio
Access at http://localhost:5555

Health Checks

The Docker Compose configuration includes health checks:

PostgreSQL Health Check

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U privateconnect"]
  interval: 5s
  timeout: 5s
  retries: 5

API Health Check

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3001/v1/agents"]
  interval: 10s
  timeout: 5s
  retries: 3
The API service waits for PostgreSQL to be healthy before starting.

Production Considerations

1

Use a reverse proxy

Set up nginx or Caddy for HTTPS:
server {
  listen 80;
  server_name privateconnect.yourdomain.com;
  return 301 https://$host$request_uri;
}

server {
  listen 443 ssl http2;
  server_name privateconnect.yourdomain.com;
  
  ssl_certificate /etc/ssl/certs/privateconnect.crt;
  ssl_certificate_key /etc/ssl/private/privateconnect.key;
  
  location / {
    proxy_pass http://localhost:3000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
  
  location /api/ {
    proxy_pass http://localhost:3001/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}
2

Secure PostgreSQL

Use strong passwords and avoid exposing port 5433 publicly:
postgres:
  ports:
    - "127.0.0.1:5433:5432"  # Only accessible from localhost
3

Configure persistent storage

Use named volumes or bind mounts for data persistence:
volumes:
  postgres-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /var/lib/private-connect/postgres
4

Set resource limits

Prevent containers from consuming all system resources:
api:
  deploy:
    resources:
      limits:
        cpus: '2.0'
        memory: 2G
      reservations:
        cpus: '1.0'
        memory: 1G
5

Enable container restart policies

Ensure services restart after failures:
api:
  restart: unless-stopped

Troubleshooting

Containers won’t start

Check logs for errors:
docker compose logs

Database connection errors

Verify PostgreSQL is healthy:
docker compose ps postgres
docker compose exec postgres pg_isready -U privateconnect

Port conflicts

If port 3000, 3001, or 5433 is already in use, modify docker-compose.yml:
ports:
  - "8000:3000"  # Use port 8000 instead of 3000

Reset everything

Completely reset the deployment:
docker compose down -v
docker compose up --build -d
docker compose exec api pnpm db:push

Next Steps

Connect Agents

Connect your first agent to the self-hosted hub

Build from Source

Advanced: Build and run components manually

Build docs developers (and LLMs) love