Self-Hosting DocuSeal with Docker Compose
What DocuSeal Does
DocuSeal is an open-source document signing platform that lets you create PDF forms with a drag-and-drop builder, send them to recipients, and collect e-signatures through a mobile-optimized interface. It replaces services like DocuSign, Adobe Sign, and HelloSign with something you control entirely.
Built with Ruby on Rails, DocuSeal supports 12 field types (signature, date, file, checkbox, and more), multiple submitters per document, and SMTP-based email notifications. It stores files on disk or optionally in S3-compatible cloud storage.
Prerequisites
- A Linux server (Ubuntu 22.04+ or Debian 12+)
- Docker and Docker Compose installed (Docker Compose guide)
- 1 GB RAM minimum (2 GB recommended with PostgreSQL)
- 2 GB of free disk space, plus storage for uploaded documents
- A domain name for remote access (optional but recommended)
Docker Compose Configuration
Create a directory for DocuSeal and a docker-compose.yml file:
mkdir -p ~/docuseal && cd ~/docuseal
services:
app:
image: docuseal/docuseal:2.3.5
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
ports:
- "3000:3000"
volumes:
- docuseal-data:/data/docuseal
environment:
- DATABASE_URL=postgresql://docuseal:changeme-db-password@postgres:5432/docuseal
- SECRET_KEY_BASE=generate-a-64-char-random-string-here-use-openssl-rand-hex-32
postgres:
image: postgres:16
restart: unless-stopped
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_USER: docuseal
POSTGRES_PASSWORD: changeme-db-password # Must match DATABASE_URL above
POSTGRES_DB: docuseal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U docuseal"]
interval: 5s
timeout: 5s
retries: 5
volumes:
docuseal-data:
postgres-data:
Generate a secret key before starting:
openssl rand -hex 32
Replace generate-a-64-char-random-string-here-use-openssl-rand-hex-32 with the output, and change changeme-db-password to a strong password in both the app and postgres service sections.
Start the stack:
docker compose up -d
DocuSeal will be available at http://your-server-ip:3000.
Initial Setup
- Open
http://your-server-ip:3000in your browser - Create an admin account on first visit
- Navigate to Settings → Email to configure SMTP for sending signing requests (SMTP is configured through the web UI, not environment variables)
- Upload your first PDF document and use the form builder to add signature fields
Key Features
| Feature | Details |
|---|---|
| Form builder | WYSIWYG drag-and-drop with 12 field types |
| Multi-signer | Multiple submitters per document with configurable order |
| File storage | Local disk (default) or S3-compatible cloud storage |
| API | REST API and webhooks for automation |
| Embedding | React, Vue, Angular, and JavaScript SDKs for embedded signing |
| Languages | UI in 7 languages, signing interface in 14 languages |
| Database | PostgreSQL (recommended), MySQL, or SQLite |
S3 Storage Configuration
To store documents in S3-compatible storage instead of local disk, add these environment variables to the app service:
environment:
- AWS_ACCESS_KEY_ID=your-access-key
- AWS_SECRET_ACCESS_KEY=your-secret-key
- AWS_REGION=us-east-1
- AWS_BUCKET=your-bucket-name
This works with AWS S3, MinIO, DigitalOcean Spaces, and other S3-compatible providers.
Reverse Proxy
Place DocuSeal behind a reverse proxy for SSL termination. With Caddy:
sign.example.com {
reverse_proxy localhost:3000
}
See the full Reverse Proxy Setup Guide for Nginx Proxy Manager and Traefik configurations.
Backup
Back up these volumes regularly:
docuseal-data— uploaded documents and application datapostgres-data— the PostgreSQL database
# Database backup
docker compose exec postgres pg_dump -U docuseal docuseal > backup.sql
See Backup Strategy for automated backup approaches.
Troubleshooting
Container fails to start with database connection error
Symptom: PG::ConnectionBad: could not connect to server
Fix: Ensure POSTGRES_PASSWORD in the postgres service matches the password in DATABASE_URL. Wait for the health check — the depends_on condition ensures PostgreSQL is ready.
Emails not sending
Symptom: Signing requests don’t arrive via email Fix: Configure SMTP through the DocuSeal admin UI at Settings → Email. SMTP is not set via environment variables — it’s managed in the web interface.
Permission denied on volume mount
Symptom: Permission denied errors on /data/docuseal
Fix: The container runs as a non-root user. Ensure the volume directory is writable: sudo chown -R 1000:1000 ./docuseal if using bind mounts.
Resource Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 512 MB (with SQLite) | 1 GB (with PostgreSQL) |
| CPU | 1 vCPU | 2 vCPUs |
| Disk | 2 GB + document storage | 5 GB + document storage |
Verdict
DocuSeal is the most polished self-hosted document signing platform available. The WYSIWYG form builder is genuinely good — better than most commercial alternatives at the basic tier. It handles the common document signing workflow (upload PDF, place fields, send for signature) without any rough edges.
Choose DocuSeal if you sign documents regularly and want to stop paying DocuSign’s per-envelope pricing. The PostgreSQL setup is straightforward, SMTP configuration through the web UI is convenient, and the API is solid for automation. If you need a simpler setup with fewer features, look at DocuSeal vs Documenso for a comparison.
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