Overview
This guide covers deploying OpnForm to production using Docker Compose. This is the recommended method for self-hosting OpnForm.Before deploying to production, review the production considerations guide.
Prerequisites
- Docker Engine 20.10+ and Docker Compose v2+
- Server with at least 2GB RAM (4GB+ recommended)
- Domain name with DNS configured
- SSL certificate (or Let’s Encrypt setup)
- Basic knowledge of Docker and Linux administration
Architecture
The production Docker setup includes:- api: Laravel API server (PHP-FPM + Nginx)
- api-worker: Background job processor
- api-scheduler: Scheduled task runner
- ui: Nuxt 3 client application
- db: PostgreSQL 16 database
- redis: Redis for caching and queues
- ingress: Nginx reverse proxy
Installation
# Core Settings
APP_NAME="OpnForm"
APP_ENV=production
APP_DEBUG=false
APP_URL=https://yourdomain.com
# Generate secure keys
APP_KEY=base64:YOUR_GENERATED_KEY_HERE
JWT_SECRET=YOUR_GENERATED_JWT_SECRET_HERE
# Frontend URL
FRONT_URL=https://yourdomain.com
FRONT_API_SECRET=YOUR_SECURE_SECRET_HERE
# Database Configuration
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=opnform
DB_USERNAME=opnform
DB_PASSWORD=YOUR_SECURE_DB_PASSWORD
# Redis Configuration
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
# Cache & Queue Settings
CACHE_STORE=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
# Mail Configuration
MAIL_MAILER=smtp
MAIL_HOST=your-smtp-host.com
MAIL_PORT=587
MAIL_USERNAME=your-smtp-username
MAIL_PASSWORD=your-smtp-password
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=[email protected]
MAIL_FROM_NAME="${APP_NAME}"
# Storage Configuration
FILESYSTEM_DRIVER=local
# For production with S3:
# FILESYSTEM_DRIVER=s3
# AWS_ACCESS_KEY_ID=your-key
# AWS_SECRET_ACCESS_KEY=your-secret
# AWS_DEFAULT_REGION=us-east-1
# AWS_BUCKET=your-bucket
# Captcha (optional but recommended)
H_CAPTCHA_SITE_KEY=your-hcaptcha-site-key
H_CAPTCHA_SECRET_KEY=your-hcaptcha-secret
# Admin Configuration
ADMIN_EMAILS=[email protected]
# Generate APP_KEY (run on your local machine with PHP)
php -r "echo 'base64:' . base64_encode(random_bytes(32)) . PHP_EOL;"
# Generate JWT_SECRET
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"
# Generate FRONT_API_SECRET
php -r "echo bin2hex(random_bytes(32)) . PHP_EOL;"
NUXT_PUBLIC_APP_URL=https://yourdomain.com
NUXT_PUBLIC_API_BASE=https://yourdomain.com
NUXT_API_SECRET=YOUR_FRONT_API_SECRET_FROM_API_ENV
NUXT_PUBLIC_ENV=production
# Optional: Analytics
# NUXT_PUBLIC_GOOGLE_ANALYTICS_CODE=UA-XXXXXXXXX-X
# NUXT_PUBLIC_AMPLITUDE_CODE=your-amplitude-key
# Optional: Support Chat
# NUXT_PUBLIC_CRISP_WEBSITE_ID=your-crisp-id
# Captcha (must match API configuration)
NUXT_PUBLIC_H_CAPTCHA_SITE_KEY=your-hcaptcha-site-key
echo "DB_DATABASE=opnform" > .env
echo "DB_USERNAME=opnform" >> .env
echo "DB_PASSWORD=YOUR_SECURE_DB_PASSWORD" >> .env
Service Configuration
Container Resources
Thedocker-compose.yml configures PHP with the following limits:
docker-compose.yml if needed for your workload.
Persistent Volumes
The following volumes persist data:postgres-data: PostgreSQL databaseopnform_storage: Uploaded files and application storageredis-data: Redis cache and queue data
Health Checks
All services include health checks:- API: Checks Laravel is responding (
php artisan about) - API Worker: Verifies queue worker process is running
- API Scheduler: Confirms scheduler is executing
- UI: Tests HTTP endpoint availability
- Database: PostgreSQL readiness check
- Redis: Ping/pong test
- Ingress: Nginx configuration test + HTTP check
SSL/HTTPS Configuration
The default setup exposes port 80. For production, you need SSL:Option 1: External Reverse Proxy (Recommended)
Use Nginx, Caddy, or Traefik in front of OpnForm:- Keep ingress on port 80
- Configure your reverse proxy to:
- Terminate SSL
- Proxy to
http://localhost:80 - Set appropriate headers (
X-Forwarded-*)
Option 2: Let’s Encrypt with Certbot
Mount certificates into the ingress container:docker/nginx.conf to handle SSL.
Managing the Deployment
View Logs
Restart Services
Stop the Application
Update OpnForm
Backup and Recovery
Database Backup
Storage Backup
Troubleshooting
Container Won’t Start
Check logs for the specific service:- Missing environment variables
- Invalid database credentials
- Port conflicts (80/443 already in use)
Database Connection Errors
Verify database is healthy:.env and api/.env.
Permission Issues
Ensure storage volumes have correct permissions:Worker Not Processing Jobs
Check worker logs:api/.env.
Next Steps
- Review production considerations
- Set up monitoring and alerting
- Configure automated backups
- Review security hardening
- Set up log aggregation
Support
For deployment issues:- Check GitHub Issues
- Join Discord community
- Review Technical Documentation