Skip to content

lumizone/formto

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FormTo

The self-hosted form backend you'll actually enjoy running.

Add one action attribute to any HTML form and start collecting submissions. No coding. No SaaS subscription. No vendor lock-in.

License: AGPL v3 Docker Node.js React PostgreSQL

Quick Start Β· Features Β· Configuration Β· Self-host


What is FormTo?

FormTo is an open-source, self-hosted alternative to Formspree, Formcarry and Basin. Point your HTML form at FormTo, and every submission is saved, searchable, exportable, and delivered to your inbox (or Telegram, or Slack, or any webhook).

<form action="https://forms.example.com/f/contact-abc123" method="POST">
  <input name="name" required />
  <input name="email" type="email" required />
  <textarea name="message"></textarea>
  <button type="submit">Send</button>
</form>

That's it. No JavaScript. No API keys. Submissions appear in your dashboard instantly.


Features

πŸ“₯ Submissions inbox Read, archive, reply by email, add internal notes, change status (new / in-progress / resolved)
πŸ“§ Email notifications Bring your own SMTP β€” Gmail, Mailgun, Postmark, Resend, anything
πŸ’¬ Telegram & Slack Native integrations via bot token or incoming webhook
πŸ”— Webhooks POST every submission as JSON to Zapier, Make, n8n, Discord, or your own endpoint
🎨 Custom email templates Brand your notifications with HTML and your logo
πŸ“Š Analytics Submissions over time, per-form breakdown, top fields
🌐 Hosted form pages Share a standalone form at /f/:endpoint β€” no HTML required
πŸ›‘οΈ Spam protection Built-in honeypot, rate limiting, and block-by email/domain/IP
πŸ”’ Auto-close Stop accepting submissions after N responses or on a specific date
🏷️ Tags & filters Organize forms with labels and search across everything
πŸ“¦ CSV + JSON export Own your data β€” download it anytime
πŸ§™ First-run wizard Zero config. Open the app, create your account, done

Quick Start

Requires Docker and Docker Compose. That's the only dependency.

# 1. Clone
git clone https://github.com/lumizone/formto
cd formto

# 2. Configure
cp formto.env.example formto.env
# Edit formto.env β€” set DOMAIN, POSTGRES_PASSWORD, JWT_SECRET

# 3. Launch
docker compose up -d

Open https://your-domain.com β†’ the first-run setup wizard will greet you β†’ create your account β†’ create your first form.

HTTPS is automatic. Caddy obtains and renews Let's Encrypt certificates for your domain. No certbot, no cron jobs, no --renew flags.


Configuration

Everything lives in a single formto.env file.

Required

DOMAIN=forms.example.com
POSTGRES_PASSWORD=<openssl rand -base64 32>
JWT_SECRET=<openssl rand -hex 32>

Optional (SMTP fallback)

SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=you@gmail.com
SMTP_PASS=your-app-password
FROM_EMAIL=FormTo <noreply@forms.example.com>

SMTP, Telegram and Slack credentials can also be configured per account in the UI (Account β†’ Notifications), so you don't have to bake them into env vars.

Running without a domain

On a VPS with IP only? Edit Caddyfile, replace {$DOMAIN} with :80, leave DOMAIN= empty. Access the app at http://your-server-ip.


Self-hosting

Architecture

                Internet
                    β”‚
                    β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚   Caddy     β”‚  ← auto HTTPS (Let's Encrypt)
            β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
                   β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό          β–Ό          β–Ό
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β”‚Frontendβ”‚ β”‚Backend β”‚ β”‚ /f/*     β”‚
   β”‚ React  β”‚ β”‚Fastify β”‚ β”‚ (public  β”‚
   β”‚ :80    β”‚ β”‚ :3001  β”‚ β”‚  forms)  β”‚
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”¬β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β–Ό
            β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
            β”‚PostgreSQLβ”‚
            β”‚    :16   β”‚
            β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Everyday commands

docker compose up -d              # start
docker compose down               # stop
docker compose logs -f backend    # tail logs
docker compose up -d --build      # rebuild after pulling updates

Backup & restore

# Backup
docker compose exec postgres pg_dump -U formto formto > backup_$(date +%F).sql

# Restore
cat backup.sql | docker compose exec -T postgres psql -U formto formto

Updating

git pull
docker compose up -d --build

Schema migrations run automatically on boot β€” no manual steps.


Tech Stack

Layer Technology
Frontend React 19, Vite, Tailwind CSS v4, Radix UI
Backend Fastify, Node.js 20, postgres.js, jose (JWT), nodemailer
Database PostgreSQL 16
Reverse proxy Caddy 2 (automatic HTTPS)
Deployment Docker Compose

Security

FormTo ships with sensible defaults out of the box:

  • πŸ” Passwords hashed with bcrypt
  • 🎫 JWT auth (HS256, 7-day TTL) with startup warnings on default secrets
  • πŸ•ΈοΈ SSRF protection on webhook URLs (DNS pinning, private-IP blocking)
  • 🧱 Rate limiting on all public endpoints
  • 🍯 Honeypot and spam detection on every form
  • 🚫 SQL injection–proof β€” 100% parameterized queries (postgres.js tagged templates)
  • πŸ›‘οΈ XSS-safe email templates and hosted forms

Found a vulnerability? Please open a private security advisory on GitHub.


Contributing

Pull requests are welcome! For major changes, please open an issue first to discuss what you'd like to change.

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

AGPL-3.0 β€” free to use, modify, and self-host. If you distribute a modified version or run it as a public service, you must publish your changes under the same license.


Built with ❀️ for developers who value ownership of their data.

⭐ Star this repo if you find it useful!

About

FormTo, a simple, self-hosted backend for HTML forms. Add one action attribute to your form and submissions land in your dashboard. Email, Telegram, Slack and webhook notifications.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors