Ploy

Self Host Ploy

Deploy Ploy on your own infrastructure using Docker.

Self Host Ploy

Ploy is a self-hostable serverless deployment platform and Vercel alternative. This guide will help you deploy Ploy on your own infrastructure, giving you complete control over your deployments, code, and data.

Prerequisites

  • Docker (latest version) and Docker Compose
  • GitHub OAuth App (for authentication)
  • Domain (optional, but recommended for production)
  • 2GB+ RAM (4GB+ recommended for production)
  • 10GB+ disk space (more for storing deployments)

Quick Start

The fastest way to get started is with Docker Compose:

# Clone the repository
git clone https://github.com/theopenco/ploy.git
cd ploy

# Copy environment variables
cp .env.example .env

# Edit .env with your configuration (see below)
nano .env

# Start all services
docker compose up -d

After starting, access:

Option 1: Unified Docker Image (Simplest)

This option uses a single Docker container with all services bundled together. Perfect for testing or small deployments.

# Run the unified container
docker run -d \
  --name ploy \
  --restart unless-stopped \
  -p 3002:3002 \
  -p 3005:3005 \
  -p 4001:4001 \
  -p 4002:4002 \
  -v ~/ploy_data:/var/lib/postgresql/data \
  -v ~/ploy_fs:/app/fs \
  -e AUTH_SECRET=your-secret-key-here \
  -e GITHUB_CLIENT_ID=your-github-client-id \
  -e GITHUB_CLIENT_SECRET=your-github-client-secret \
  ghcr.io/theopenco/ploy-unified:latest

Note: Replace latest with a specific version from releases.

Using Docker Compose (Unified)

# Download the compose file
curl -O https://raw.githubusercontent.com/theopenco/ploy/main/infra/docker-compose.unified.yml

# Copy and configure environment
curl -O https://raw.githubusercontent.com/theopenco/ploy/main/.env.example
cp .env.example .env
# Edit .env with your configuration

# Start the service
docker compose -f docker-compose.unified.yml up -d

This option runs each service in its own container, providing better scalability and resource management.

# Clone the repository
git clone https://github.com/theopenco/ploy.git
cd ploy

# Configure environment
cp .env.example .env
# Edit .env with your configuration

# Start all services
docker compose -f infra/docker-compose.split.yml up -d

Services in Split Mode

The split deployment includes:

  • postgres - PostgreSQL database
  • redis - Redis cache and session store
  • api - REST API server
  • ui - Web dashboard (Next.js)
  • worker - Background job processor
  • handler - Deployment handler (serves deployed apps)
  • docs - Documentation site

Required Configuration

1. GitHub OAuth App

Create a GitHub OAuth App for authentication:

  1. Go to GitHub Settings → Developer settings → OAuth Apps
  2. Click New OAuth App
  3. Fill in:
    • Application name: Ploy
    • Homepage URL: http://localhost:3002 (or your domain)
    • Authorization callback URL: http://localhost:3002/api/auth/callback/github
  4. Click Register application
  5. Copy the Client ID and generate a Client Secret

2. GitHub App (for Repository Access)

Create a GitHub App for repository access and webhooks:

  1. Go to GitHub Settings → Developer settings → GitHub Apps
  2. Click New GitHub App
  3. Fill in:
    • GitHub App name: Ploy Deployments
    • Homepage URL: http://localhost:3002
    • Webhook URL: http://localhost:4002/webhooks/github
    • Webhook secret: Generate a random string
  4. Set permissions:
    • Repository permissions:
      • Contents: Read
      • Metadata: Read
      • Webhooks: Read & Write
  5. Subscribe to events:
    • Push
    • Repository
  6. Click Create GitHub App
  7. Generate and download a private key
  8. Note the App ID

3. Environment Variables

Edit your .env file with the following required variables:

# Database
POSTGRES_PASSWORD=your_secure_password_here
DATABASE_URL=postgresql://postgres:your_secure_password_here@postgres:5432/ploy

# Redis
REDIS_URL=redis://redis:6379

# Authentication
AUTH_SECRET=your-secret-key-here
BETTER_AUTH_URL=http://localhost:3002

# GitHub OAuth (for user authentication)
GITHUB_CLIENT_ID=your-github-oauth-client-id
GITHUB_CLIENT_SECRET=your-github-oauth-client-secret

# GitHub App (for repository access)
GITHUB_APP_ID=your-github-app-id
GITHUB_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
GITHUB_WEBHOOK_SECRET=your-webhook-secret

# API URLs
NEXT_PUBLIC_API_URL=http://localhost:4002
API_HANDLER_URL=http://handler:4001

# Deployment Storage
FS_PATH=/app/fs

4. Generate Secrets

Generate secure random strings for secrets:

# Generate AUTH_SECRET
openssl rand -hex 32

# Generate GITHUB_WEBHOOK_SECRET
openssl rand -hex 32

Production Configuration

For production deployments, consider these additional settings:

Domain Setup

  1. Point your domain to your server's IP
  2. Update environment variables:
# Frontend URL
BETTER_AUTH_URL=https://ploy.yourdomain.com
NEXT_PUBLIC_API_URL=https://api.yourdomain.com

# Update GitHub OAuth callback
# In GitHub OAuth App settings, set callback to:
# https://ploy.yourdomain.com/api/auth/callback/github

# Update GitHub App webhook URL
# In GitHub App settings, set webhook to:
# https://api.yourdomain.com/webhooks/github

SSL/TLS Certificates

Use a reverse proxy like Nginx or Caddy for SSL:

Caddy Example

Create a Caddyfile:

ploy.yourdomain.com {
    reverse_proxy localhost:3002
}

api.yourdomain.com {
    reverse_proxy localhost:4002
}

*.ploy-deployments.yourdomain.com {
    reverse_proxy localhost:4001
}

Run Caddy:

caddy run

Resource Limits

Add resource limits to your docker-compose.yml:

services:
  api:
    deploy:
      resources:
        limits:
          cpus: "1"
          memory: 1G
        reservations:
          cpus: "0.5"
          memory: 512M

Monitoring

Enable logging and monitoring:

# View logs for all services
docker compose logs -f

# View logs for specific service
docker compose logs -f api

# View resource usage
docker stats

Management Commands

Docker Compose (Unified)

# Start services
docker compose -f docker-compose.unified.yml up -d

# View logs
docker compose -f docker-compose.unified.yml logs -f

# Restart services
docker compose -f docker-compose.unified.yml restart

# Stop services
docker compose -f docker-compose.unified.yml down

# Stop and remove volumes
docker compose -f docker-compose.unified.yml down -v

Docker Compose (Split)

# Start all services
docker compose -f infra/docker-compose.split.yml up -d

# Start specific service
docker compose -f infra/docker-compose.split.yml up -d api

# View logs
docker compose -f infra/docker-compose.split.yml logs -f

# Restart services
docker compose -f infra/docker-compose.split.yml restart

# Stop services
docker compose -f infra/docker-compose.split.yml down

Database Operations

# Backup database
docker exec ploy-postgres pg_dump -U postgres ploy > backup.sql

# Restore database
docker exec -i ploy-postgres psql -U postgres ploy < backup.sql

# Access database shell
docker exec -it ploy-postgres psql -U postgres ploy

Troubleshooting

Common Issues

Services won't start:

# Check logs
docker compose logs -f

# Verify environment variables
docker compose config

# Ensure ports are not in use
lsof -i :3002
lsof -i :4002

Database connection errors:

# Check PostgreSQL is running
docker compose ps postgres

# Verify DATABASE_URL in .env
# Ensure POSTGRES_PASSWORD matches in DATABASE_URL

GitHub webhook not working:

  1. Check webhook URL is publicly accessible
  2. Verify GITHUB_WEBHOOK_SECRET matches GitHub App
  3. Check API logs: docker compose logs -f api
  4. Test webhook delivery in GitHub App settings

Deployments failing:

# Check worker logs
docker compose logs -f worker

# Check handler logs
docker compose logs -f handler

# Verify FS_PATH volume is writable
docker exec ploy-worker ls -la /app/fs

Debug Mode

Enable debug logging:

# Add to .env
LOG_LEVEL=debug

# Restart services
docker compose restart

Updating Ploy

To update to the latest version:

# Pull latest changes
git pull origin main

# Pull latest images
docker compose pull

# Restart services
docker compose down
docker compose up -d

# Check logs for any issues
docker compose logs -f

Build from Source

To build Ploy from source:

# Clone repository
git clone https://github.com/theopenco/ploy.git
cd ploy

# Install dependencies
pnpm install

# Build all packages
pnpm build

# Start services with local build
docker compose -f infra/docker-compose.local.yml up -d

Performance Tuning

PostgreSQL

Optimize PostgreSQL for your workload:

# Add to docker-compose.yml postgres service
environment:
  - POSTGRES_SHARED_BUFFERS=256MB
  - POSTGRES_EFFECTIVE_CACHE_SIZE=1GB
  - POSTGRES_MAX_CONNECTIONS=100

Redis

Configure Redis memory limits:

# Add to docker-compose.yml redis service
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru

Worker Concurrency

Adjust worker concurrency:

# Add to .env
WORKER_CONCURRENCY=5

Security Best Practices

  1. Use strong passwords for database and secrets
  2. Enable HTTPS in production with valid SSL certificates
  3. Keep secrets secure - never commit .env files
  4. Regular backups of database and deployment files
  5. Update regularly to get security patches
  6. Firewall rules - only expose necessary ports
  7. Limit GitHub App permissions to minimum required

Next Steps

Once Ploy is running:

  1. Sign in at http://localhost:3002 (or your domain)
  2. Create an organization and project
  3. Connect a repository and deploy your first app
  4. Configure custom domains for production deployments
  5. Explore the API at http://localhost:4002/docs

Support

Happy self-hosting! ✨

How is this guide?

Last updated on

Self Host Ploy