Formbricks is an open-source survey platform for link, embedded website and in-app surveys. This guide runs it with PostgreSQL (pgvector), Valkey/Redis-compatible cache, Nginx and HTTPS on one VPS.
Prerequisites
| Item | Minimum | Recommended |
|---|---|---|
| VPS | 2 vCPU, 2 GB RAM, 30 GB NVMe | 2–4 vCPU, 4 GB RAM, 50 GB NVMe |
| OS | Ubuntu 24.04 LTS | Ubuntu 26.04 LTS |
| DNS | A record for surveys.example.com | AAAA record too, if IPv6 is configured |
| SMTP | Optional | Recommended for invites, resets and verification |
Deploy the VPS, point DNS to its IP and confirm dig +short surveys.example.com resolves before requesting TLS. Replace the example domain and admin@example.com below. Commands assume root (su - if needed).
Step 1: Prepare the server
ssh root@YOUR_VPS_IP
apt update && apt -y upgrade
apt -y install curl ca-certificates openssl ufw nginx certbot python3-certbot-nginx
hostnamectl set-hostname surveys
timedatectl set-timezone America/New_YorkOn a 2 GB plan, add swap for startup and migrations:
fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstabIf your SSH port is not 22, allow the correct port before enabling the firewall.
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw --force enable
ufw statusStep 2: Install Docker
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
docker --version
docker compose versionDocker-published ports can bypass UFW. Only the app port is bound to 127.0.0.1 below; the database and cache are not published.
Step 3: Configure the stack
mkdir -p /opt/formbricks
cd /opt/formbricks
cat > .env <<EOF_ENV
FORMBRICKS_VERSION=latest
WEBAPP_URL=https://surveys.example.com
NEXTAUTH_URL=https://surveys.example.com
NEXTAUTH_SECRET=$(openssl rand -hex 32)
ENCRYPTION_KEY=$(openssl rand -hex 32)
CRON_SECRET=$(openssl rand -hex 32)
POSTGRES_PASSWORD=$(openssl rand -hex 24)
EMAIL_VERIFICATION_DISABLED=1
PASSWORD_RESET_DISABLED=1
#MAIL_FROM=surveys@example.com
#SMTP_HOST=smtp.example.com
#SMTP_PORT=587
#SMTP_USER=surveys@example.com
#SMTP_PASSWORD=change-me
#SMTP_SECURE_ENABLED=0
EOF_ENV
chmod 600 .envKeep ENCRYPTION_KEY safe with the database backups. Without the original key, encrypted data cannot be read after a restore. When SMTP is configured, remove the two _DISABLED lines and add your mail settings. Pin FORMBRICKS_VERSION to a tested tag from Formbricks releases rather than latest in production.
Create /opt/formbricks/docker-compose.yml:
services:
postgres:
image: pgvector/pgvector:pg17
restart: unless-stopped
environment:
POSTGRES_USER: formbricks
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: formbricks
volumes:
- postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U formbricks"]
interval: 10s
timeout: 5s
retries: 5
redis:
image: valkey/valkey:8-alpine
restart: unless-stopped
command: valkey-server --appendonly yes
volumes:
- redis:/data
formbricks:
image: ghcr.io/formbricks/formbricks:${FORMBRICKS_VERSION}
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_started
env_file: .env
environment:
DATABASE_URL: postgresql://formbricks:${POSTGRES_PASSWORD}@postgres:5432/formbricks?schema=public
REDIS_URL: redis://redis:6379
ports:
- "127.0.0.1:3000:3000"
volumes:
- uploads:/home/nextjs/apps/web/uploads
volumes:
postgres:
redis:
uploads:For external uploads, Formbricks also supports S3-compatible storage through its S3_* environment settings.
Step 4: Start Formbricks
cd /opt/formbricks
docker compose pull
docker compose up -d
docker compose logs -f formbricksStartup migrations can take a couple of minutes. Press Ctrl+C once ready, then check curl -sI http://127.0.0.1:3000 | head -n 1 for a 200 or redirect response.
Step 5: Configure Nginx and HTTPS
Create /etc/nginx/sites-available/formbricks:
server {
listen 80;
listen [::]:80;
server_name surveys.example.com;
client_max_body_size 50M;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
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;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 300s;
}
}ln -s /etc/nginx/sites-available/formbricks /etc/nginx/sites-enabled/
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx
certbot --nginx -d surveys.example.com --redirect -m admin@example.com --agree-tos -n
certbot renew --dry-runStep 6: Create the owner account
Open https://surveys.example.com and register with a strong password. The first account owns the first organization; complete onboarding to create a project. Once your team has joined, close public registration by adding SIGNUP_DISABLED=1 to /opt/formbricks/.env and run cd /opt/formbricks && docker compose up -d. Invitations through Organization settings > Members require SMTP.
Backups and restore
Back up the PostgreSQL database, uploads and .env (including ENCRYPTION_KEY). Create /usr/local/bin/formbricks-backup:
#!/bin/bash
set -euo pipefail
DEST=/var/backups/formbricks
STAMP=$(date +%F-%H%M)
mkdir -p "$DEST"
cd /opt/formbricks
docker compose exec -T postgres pg_dump -U formbricks formbricks | gzip > "$DEST/db-$STAMP.sql.gz"
docker run --rm -v formbricks_uploads:/data -v "$DEST":/backup alpine \
tar czf "/backup/uploads-$STAMP.tar.gz" -C /data .
cp .env "$DEST/env-$STAMP"
chmod 600 "$DEST"/*
find "$DEST" -type f -mtime +14 -deletechmod 700 /usr/local/bin/formbricks-backup
/usr/local/bin/formbricks-backup && ls -lh /var/backups/formbricks
echo '15 3 * * * root /usr/local/bin/formbricks-backup' > /etc/cron.d/formbricks-backupCopy backups off the VPS. To restore a database dump with the original .env:
cd /opt/formbricks
docker compose stop formbricks
gunzip -c /var/backups/formbricks/db-STAMP.sql.gz | docker compose exec -T postgres psql -U formbricks formbricks
docker compose start formbricksRestore the matching uploads archive too if recovering the full installation.
Updating Formbricks
Read release notes, take a backup and change FORMBRICKS_VERSION in .env:
/usr/local/bin/formbricks-backup
cd /opt/formbricks
docker compose pull
docker compose up -d
docker compose logs -f formbricks
docker image prune -fMigrations run on startup. Keep the OS patched with apt update && apt -y upgrade.
Troubleshooting
| Symptom | Check |
|---|---|
| 502 Bad Gateway | Run docker compose ps and docker compose logs formbricks. |
| Database errors on restart | Check the database health and that POSTGRES_PASSWORD has not changed since volume creation. |
| Exit 137 | Increase memory or add swap. |
| Login redirects to localhost | Set both WEBAPP_URL and NEXTAUTH_URL to your HTTPS domain, then recreate the app. |
| Certificate challenge fails | Check DNS, port 80, UFW and Nginx. |
| Survey uploads fail | Check client_max_body_size and the uploads volume or S3 settings. |
| Invitations or resets do not send | Configure SMTP, remove the _DISABLED settings and recreate the app. |
