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 -dAfter starting, access:
- Web Dashboard: http://localhost:3002
- Documentation: http://localhost:3005
- API: http://localhost:4002
- Handler (serves deployments): http://localhost:4001
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:latestNote: 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 -dOption 2: Separate Services (Recommended for Production)
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 -dServices 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:
- Go to GitHub Settings → Developer settings → OAuth Apps
- Click New OAuth App
- Fill in:
- Application name: Ploy
- Homepage URL:
http://localhost:3002(or your domain) - Authorization callback URL:
http://localhost:3002/api/auth/callback/github
- Click Register application
- Copy the Client ID and generate a Client Secret
2. GitHub App (for Repository Access)
Create a GitHub App for repository access and webhooks:
- Go to GitHub Settings → Developer settings → GitHub Apps
- Click New GitHub App
- 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
- Set permissions:
- Repository permissions:
- Contents: Read
- Metadata: Read
- Webhooks: Read & Write
- Repository permissions:
- Subscribe to events:
- Push
- Repository
- Click Create GitHub App
- Generate and download a private key
- 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/fs4. Generate Secrets
Generate secure random strings for secrets:
# Generate AUTH_SECRET
openssl rand -hex 32
# Generate GITHUB_WEBHOOK_SECRET
openssl rand -hex 32Production Configuration
For production deployments, consider these additional settings:
Domain Setup
- Point your domain to your server's IP
- 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/githubSSL/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 runResource Limits
Add resource limits to your docker-compose.yml:
services:
api:
deploy:
resources:
limits:
cpus: "1"
memory: 1G
reservations:
cpus: "0.5"
memory: 512MMonitoring
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 statsManagement 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 -vDocker 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 downDatabase 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 ployTroubleshooting
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 :4002Database connection errors:
# Check PostgreSQL is running
docker compose ps postgres
# Verify DATABASE_URL in .env
# Ensure POSTGRES_PASSWORD matches in DATABASE_URLGitHub webhook not working:
- Check webhook URL is publicly accessible
- Verify GITHUB_WEBHOOK_SECRET matches GitHub App
- Check API logs:
docker compose logs -f api - 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/fsDebug Mode
Enable debug logging:
# Add to .env
LOG_LEVEL=debug
# Restart services
docker compose restartUpdating 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 -fBuild 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 -dPerformance 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=100Redis
Configure Redis memory limits:
# Add to docker-compose.yml redis service
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lruWorker Concurrency
Adjust worker concurrency:
# Add to .env
WORKER_CONCURRENCY=5Security Best Practices
- Use strong passwords for database and secrets
- Enable HTTPS in production with valid SSL certificates
- Keep secrets secure - never commit
.envfiles - Regular backups of database and deployment files
- Update regularly to get security patches
- Firewall rules - only expose necessary ports
- Limit GitHub App permissions to minimum required
Next Steps
Once Ploy is running:
- Sign in at http://localhost:3002 (or your domain)
- Create an organization and project
- Connect a repository and deploy your first app
- Configure custom domains for production deployments
- Explore the API at http://localhost:4002/docs
Support
- Documentation: https://docs.meetploy.com
- GitHub Issues: https://github.com/theopenco/ploy/issues
- Community: Join our Discord or discussions
Happy self-hosting! ✨
How is this guide?
Last updated on