Skip to content

Deployment Guide

Production self-hosting guide for FlowForm. Covers Docker Compose, one-click deploys, and hardening.

1. Clone the repository

bash
git clone https://github.com/flowformhq/flowform.git
cd flowform

2. Create your environment file

bash
cp .env.example .env

Edit .env with production values:

bash
APP_NAME=FlowForm
APP_ENV=production
APP_KEY=base64:generate-a-32-char-key
APP_DEBUG=false
APP_URL=https://your-domain.com

DB_CONNECTION=mysql
DB_HOST=db
DB_PORT=3306
DB_DATABASE=flowform
DB_USERNAME=flowform
DB_PASSWORD=a-strong-password

CACHE_STORE=redis
SESSION_DRIVER=redis
QUEUE_CONNECTION=database

LOG_CHANNEL=stderr
LOG_LEVEL=warning

FLOWFORM_TELEMETRY_ENABLED=true

3. Generate an app key

bash
php artisan key:generate --env

4. Start the stack

bash
docker compose up -d

5. Run migrations

bash
docker compose exec flowform php artisan migrate --force

6. Create an admin user

bash
docker compose exec flowform php artisan tinker
php
\App\Models\User::create([
    'name' => 'Admin',
    'email' => 'admin@yourdomain.com',
    'password' => bcrypt('your-secure-password'),
]);

7. Optimize for production

bash
docker compose exec flowform php artisan config:cache
docker compose exec flowform php artisan route:cache
docker compose exec flowform php artisan view:cache

One-click deploy

Railway

Deploy on Railway

Railway deploys from the GitHub repo with automatic SSL and a managed database.

Render

Deploy to Render

DigitalOcean App Platform

Use the deploy-do.json manifest in the repository root.

Production hardening checklist

Security

  • [ ] APP_DEBUG=false in production
  • [ ] APP_KEY is a strong, randomly generated key
  • [ ] Database uses a strong, unique password
  • [ ] TLS/HTTPS enabled (via reverse proxy or platform)
  • [ ] SESSION_DRIVER set to redis or database (not file)
  • [ ] CACHE_STORE set to redis or database
  • [ ] Rate limiting is enabled (default: 60 req/min public, 120 req/min authenticated)
  • [ ] Sanctum token expiration configured
  • [ ] CORS configured to allow only your frontend domains

Database

  • [ ] Using MySQL or PostgreSQL (not SQLite) for production
  • [ ] Automated daily backups configured
  • [ ] Connection encryption (TLS to database) enabled
  • [ ] Database user has minimal required permissions

Application

  • [ ] Config cache enabled: php artisan config:cache
  • [ ] Route cache enabled: php artisan route:cache
  • [ ] View cache enabled: php artisan view:cache
  • [ ] OpCache configured (included in Docker image)
  • [ ] Queue worker running via Supervisor (included in Docker image)
  • [ ] Log retention configured (rotate logs, don't let disk fill)

Networking

  • [ ] Application behind a reverse proxy (Nginx, Caddy, or platform load balancer)
  • [ ] Security headers set: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
  • [ ] Upload size limits configured (upload_max_filesize, post_max_size)
  • [ ] Only necessary ports exposed (80/443)

Monitoring

  • [ ] Health check endpoint configured: GET /api/v1/forms (returns 200)
  • [ ] Log aggregation set up (stdout → your log collector)
  • [ ] Alert on 5xx error rate spikes
  • [ ] Disk space monitoring on volumes

Backups

  • [ ] Database: daily automated backups, tested restore
  • [ ] storage/ volume: backed up (contains uploaded files and logs)
  • [ ] .env file: stored securely outside the server (secrets manager)

Environment variables reference

VariableDefaultDescription
APP_NAMEFlowFormApplication display name
APP_ENVlocallocal, staging, or production
APP_KEYEncryption key (generate with php artisan key:generate)
APP_DEBUGtrueShow detailed errors. Must be false in production
APP_URLhttp://localhostCanonical URL for the application
DB_CONNECTIONsqlitesqlite, mysql, or pgsql
DB_HOSTDatabase host
DB_PORTDatabase port
DB_DATABASEDatabase name
DB_USERNAMEDatabase user
DB_PASSWORDDatabase password
CACHE_STOREdatabasefile, database, or redis
SESSION_DRIVERdatabasefile, database, or redis
QUEUE_CONNECTIONdatabasesync, database, or redis
FLOWFORM_TELEMETRY_ENABLEDtrueEnable/disable telemetry
FLOWFORM_TELEMETRY_ENDPOINTTelemetry ingestion URL
GITHUB_CLIENT_IDGitHub OAuth app client ID
GITHUB_CLIENT_SECRETGitHub OAuth app client secret
GOOGLE_CLIENT_IDGoogle OAuth client ID
GOOGLE_CLIENT_SECRETGoogle OAuth client secret

Licensed under CC BY 4.0.