142 lines
4.3 KiB
Markdown
142 lines
4.3 KiB
Markdown
# FormBuilder
|
|
|
|
Self-hosted form builder for one workspace with Authentik OIDC sign-in, Prisma/Postgres storage, per-form response ACLs, public form links, webhooks, uploads, and an MCP endpoint.
|
|
|
|
## Portainer Deployment
|
|
|
|
This repo is ready to deploy as a Portainer stack with `docker-compose.yml`.
|
|
|
|
1. Create a new git repo and push this directory.
|
|
2. In Portainer, create a stack from the git repository.
|
|
3. Copy `.env.example` to `.env` in the stack environment and fill the values below.
|
|
4. Deploy the stack.
|
|
|
|
The app container runs `prisma migrate deploy` before starting the Next.js standalone server.
|
|
|
|
## Required `.env`
|
|
|
|
```bash
|
|
APP_PORT=3080
|
|
POSTGRES_PASSWORD=replace-with-a-strong-password
|
|
|
|
AUTH_SECRET=replace-with-openssl-rand-base64-32
|
|
AUTH_URL=https://forms.example.com
|
|
PUBLIC_FORM_URL=https://forms-public.example.com
|
|
|
|
OIDC_ISSUER=https://authentik.example.com/application/o/formbuilder/
|
|
OIDC_CLIENT_ID=replace-with-authentik-client-id
|
|
OIDC_CLIENT_SECRET=replace-with-authentik-client-secret
|
|
OIDC_PROVIDER_NAME=Authentik
|
|
|
|
AUTH_BOOTSTRAP_ADMINS=[email protected]
|
|
```
|
|
|
|
Optional values are documented in `.env.example` for Redis rate limiting, email, file storage, hCaptcha, and webhook worker auth.
|
|
|
|
## Reverse Proxy
|
|
|
|
Run the app behind your reverse proxy with HTTP upstream, then terminate TLS at the proxy.
|
|
|
|
For Nginx Proxy Manager or openresty outside this Compose network:
|
|
|
|
- Scheme: `http`
|
|
- Forward hostname/IP: the Docker host running this stack
|
|
- Forward port: `${APP_PORT}`; default `3080`
|
|
- Public URL: set `AUTH_URL` to the final external URL, for example `https://forms.internal.vyntehome.com`
|
|
|
|
If openresty is attached to the same Docker network as this stack, proxy to `http://app:3000` instead of the host-published port.
|
|
|
|
Minimal openresty location:
|
|
|
|
```nginx
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3080;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-Host $host;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
}
|
|
```
|
|
|
|
`502 Bad Gateway` means openresty cannot reach the upstream. First verify the app from the proxy host with `curl http://127.0.0.1:3080/signin` or `curl http://<docker-host-ip>:3080/signin`.
|
|
|
|
### Separate Builder And Public Forms Domains
|
|
|
|
To build/manage forms at `forms.internal.vyntehome.com` and serve published forms at `forms.vyntehome.com`, point both reverse-proxy hosts to the same app upstream and set:
|
|
|
|
```bash
|
|
AUTH_URL=https://forms.internal.vyntehome.com
|
|
PUBLIC_FORM_URL=https://forms.vyntehome.com
|
|
```
|
|
|
|
Keep the Authentik redirect URI on the internal builder domain:
|
|
|
|
```text
|
|
https://forms.internal.vyntehome.com/api/auth/callback/oidc
|
|
```
|
|
|
|
The public proxy host must forward these paths to the app:
|
|
|
|
```text
|
|
/f/*
|
|
/embed.js
|
|
/_next/*
|
|
/api/forms/*
|
|
/api/files/*
|
|
```
|
|
|
|
Published forms intended for `forms.vyntehome.com` must use **Public** visibility. Workspace-only forms require an authenticated session and should be opened on the internal builder domain.
|
|
|
|
## Authentik Setup
|
|
|
|
Create an OAuth2/OpenID provider in Authentik:
|
|
|
|
- Provider type: OAuth2/OpenID
|
|
- Client type: Confidential
|
|
- Redirect URI: `${AUTH_URL}/api/auth/callback/oidc`
|
|
- Scopes: `openid`, `profile`, `email`
|
|
- Issuer mode: use the provider's OpenID Configuration Issuer URL
|
|
|
|
Then create an Authentik application and bind it to that provider. Put the issuer, client ID, and client secret in `.env`.
|
|
|
|
The first successful signer becomes an admin. Any emails listed in `AUTH_BOOTSTRAP_ADMINS` are also promoted on first sign-in.
|
|
|
|
## Persistent Data
|
|
|
|
The compose stack creates two named volumes:
|
|
|
|
- `postgres_data`: bundled Postgres database
|
|
- `uploads`: local uploaded files mounted at `/app/uploads`
|
|
|
|
For multi-instance deployments, set `RATE_LIMIT_DRIVER=redis` and provide `REDIS_URL`. For durable object storage outside the app container, configure the S3 values in `.env.example`.
|
|
|
|
## Useful Commands
|
|
|
|
```bash
|
|
npm ci
|
|
npm test
|
|
npm run build
|
|
docker compose up --build
|
|
```
|
|
|
|
## MCP Endpoint
|
|
|
|
The MCP endpoint is available at:
|
|
|
|
```text
|
|
POST /api/mcp
|
|
```
|
|
|
|
Create a token in `/app/account`, then send requests with:
|
|
|
|
```text
|
|
Authorization: Bearer fb_xxxxxxxxxxxxxxxx
|
|
```
|
|
|
|
## Stack
|
|
|
|
Next.js 15 App Router, React 19, Auth.js v5, Authentik OIDC, Prisma, Postgres, Tailwind, and Docker Compose.
|