Self-Hosting OpnForm with Docker Compose
What Is OpnForm?
OpnForm is an open-source form builder that lets you create forms, surveys, and quizzes without writing code. It offers a drag-and-drop editor, conditional logic, file uploads, webhooks, and integrations — similar to Typeform or Google Forms but running on your own server. Built with Laravel (PHP) and Nuxt (Vue.js), it provides a polished, modern interface for form creation and response management.
Updated February 2026: Verified with latest Docker images and configurations.
Official site: opnform.com | GitHub
Prerequisites
- A Linux server (Ubuntu 22.04+ recommended)
- Docker and Docker Compose installed (guide)
- 2 GB of free disk space
- 1 GB of RAM minimum (2 GB recommended)
- A domain name (recommended for public forms)
Docker Compose Configuration
Create a project directory and the following files:
# docker-compose.yml
services:
api:
image: jhumanj/opnform-api:1.13.1
container_name: opnform-api
restart: unless-stopped
env_file:
- ./api.env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- opnform_storage:/app/storage
api-worker:
image: jhumanj/opnform-api:1.13.1
container_name: opnform-worker
restart: unless-stopped
command: php artisan queue:work
env_file:
- ./api.env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
volumes:
- opnform_storage:/app/storage
api-scheduler:
image: jhumanj/opnform-api:1.13.1
container_name: opnform-scheduler
restart: unless-stopped
command: php artisan schedule:work
env_file:
- ./api.env
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
ui:
image: jhumanj/opnform-client:1.13.1
container_name: opnform-ui
restart: unless-stopped
environment:
NUXT_PUBLIC_APP_URL: https://forms.example.com
NUXT_PUBLIC_API_BASE: /api
ingress:
image: nginx:1.27-alpine
container_name: opnform-ingress
restart: unless-stopped
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- api
- ui
db:
image: postgres:16-alpine
container_name: opnform-db
restart: unless-stopped
environment:
POSTGRES_DB: opnform
POSTGRES_USER: opnform
POSTGRES_PASSWORD: change-this-db-password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U opnform"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: opnform-redis
restart: unless-stopped
volumes:
- redis_data:/data
volumes:
postgres_data:
opnform_storage:
redis_data:
Create api.env alongside your compose file:
# Application settings
APP_ENV=production
APP_KEY=base64:GENERATE_WITH_php_artisan_key_generate
APP_DEBUG=false
APP_URL=https://forms.example.com
# Database
DB_CONNECTION=pgsql
DB_HOST=db
DB_PORT=5432
DB_DATABASE=opnform
DB_USERNAME=opnform
DB_PASSWORD=change-this-db-password
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# PHP settings
PHP_MEMORY_LIMIT=512M
PHP_MAX_EXECUTION_TIME=300
PHP_UPLOAD_MAX_FILESIZE=64M
# Mail (optional — for form response notifications)
MAIL_MAILER=smtp
MAIL_HOST=smtp.example.com
MAIL_PORT=587
MAIL_USERNAME=
MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
[email protected]
MAIL_FROM_NAME="OpnForm"
Create nginx.conf for the reverse proxy:
server {
listen 80;
client_max_body_size 64m;
location /api/ {
proxy_pass http://api:8000/;
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;
}
location / {
proxy_pass http://ui:3000;
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;
}
}
Generate an application key:
docker compose run --rm api php artisan key:generate --show
Copy the output (starts with base64:) and paste it as the APP_KEY value in api.env.
Start the stack:
docker compose up -d
Run database migrations:
docker compose exec api php artisan migrate --force
Initial Setup
Access OpnForm at http://your-server:8080. Create your first admin account through the registration form. After registration, you can start building forms immediately using the drag-and-drop editor.
Key first steps:
- Create your admin account
- Set up email notifications in
api.envif you want form submission alerts - Create your first form using the visual editor
- Share the form URL or embed it on your website
Configuration
Form Features
OpnForm supports:
- Field types: Text, email, number, date, select, multi-select, checkbox, file upload, rating, signature, phone number
- Conditional logic: Show/hide fields based on previous answers
- Form logic: Thank-you pages, redirect after submission, webhook notifications
- Styling: Custom themes, colors, fonts, and branding
- Embedding: iframe or JavaScript embed on external sites
- Pre-filling: URL parameters to pre-fill form fields
- Submissions: View, export (CSV), and filter responses
Email Notifications
Configure SMTP settings in api.env to receive email notifications when forms are submitted. OpnForm supports notification emails to form creators and confirmation emails to respondents.
File Uploads
File uploads are stored in the opnform_storage volume. The default upload limit is 64 MB per file (set via PHP_UPLOAD_MAX_FILESIZE and the nginx client_max_body_size). Adjust both values if you need larger uploads.
Webhooks
OpnForm can send form submission data to external URLs via webhooks. Configure webhooks per form in the form settings. Useful for integrating with automation tools like n8n or Huginn.
Reverse Proxy
The built-in Nginx ingress listens on port 8080. For production, place it behind your main reverse proxy with SSL:
Nginx Proxy Manager / Caddy / Traefik: Point your domain to localhost:8080 and enable SSL. Update APP_URL in api.env and NUXT_PUBLIC_APP_URL in the ui service to match your domain.
Backup
Back up the PostgreSQL database and storage volume:
# Database backup
docker compose exec db pg_dump -U opnform opnform > opnform-backup-$(date +%Y-%m-%d).sql
# Storage backup (uploaded files)
docker compose cp api:/app/storage ./storage-backup-$(date +%Y-%m-%d)
Troubleshooting
Forms Not Loading After Setup
Symptom: Blank page or API errors when accessing OpnForm.
Fix: Verify APP_URL and NUXT_PUBLIC_APP_URL match your actual domain. Run docker compose exec api php artisan config:cache after changing environment variables.
File Uploads Failing
Symptom: Upload errors on large files.
Fix: Increase both PHP_UPLOAD_MAX_FILESIZE in api.env and client_max_body_size in nginx.conf. Restart all containers.
Queue Jobs Not Processing
Symptom: Emails not sending, webhooks not firing.
Fix: Check the worker container: docker compose logs api-worker. Verify Redis is running: docker compose exec redis redis-cli ping (should return PONG).
Resource Requirements
- RAM: ~400 MB idle (API + worker + scheduler + UI + DB + Redis), ~600 MB under load
- CPU: Low to medium
- Disk: ~500 MB for application, plus storage for file uploads
Verdict
OpnForm is a strong self-hosted alternative to Typeform and JotForm. The form builder is polished, conditional logic works well, and the submission management interface is clean. It requires more infrastructure than simpler alternatives (6 containers including worker, scheduler, and nginx), but the feature set justifies the complexity. For teams that need a full-featured form builder without SaaS subscriptions, OpnForm is the best open-source option alongside Formbricks.
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments