Self-Hosting Documenso with Docker Compose
Why Documenso
Documenso is an MIT-licensed document signing platform built with TypeScript and React Router. Upload PDFs, drag signature fields onto them, send to signers, collect legally-binding e-signatures. It handles audit trails, email notifications, and digital certificate signing — all from infrastructure you control.
What sets Documenso apart from other self-hosted signing tools is its focus on digital signatures using .p12 certificates, giving documents cryptographic proof of integrity. The MIT license (rather than AGPL) also makes it more permissive for embedding in commercial applications.
Prerequisites
- Linux server with Docker and Docker Compose (setup guide)
- 2 GB RAM minimum (Node.js + PostgreSQL)
- 5 GB disk space plus document storage
- SMTP server or Resend account for sending signing requests
- A .p12 signing certificate (optional — for digital signatures with cryptographic verification)
Docker Compose Setup
Create a project directory:
mkdir -p ~/documenso && cd ~/documenso
Create a .env file with your configuration:
# Generate secrets
NEXTAUTH_SECRET=$(openssl rand -hex 32)
NEXT_PRIVATE_ENCRYPTION_KEY=$(openssl rand -hex 32)
NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=$(openssl rand -hex 32)
# Application
NEXT_PUBLIC_WEBAPP_URL=https://sign.example.com
PORT=3000
# Database
POSTGRES_USER=documenso
POSTGRES_PASSWORD=change-this-strong-password
POSTGRES_DB=documenso
NEXT_PRIVATE_DATABASE_URL=postgresql://documenso:change-this-strong-password@database:5432/documenso
# Email (SMTP example — also supports Resend and MailChannels)
NEXT_PRIVATE_SMTP_TRANSPORT=smtp-auth
NEXT_PRIVATE_SMTP_HOST=smtp.example.com
NEXT_PRIVATE_SMTP_PORT=587
NEXT_PRIVATE_SMTP_USERNAME=your-smtp-username
NEXT_PRIVATE_SMTP_PASSWORD=your-smtp-password
NEXT_PRIVATE_SMTP_FROM_NAME=Documenso
NEXT_PRIVATE_SMTP_FROM_ADDRESS=[email protected]
Create docker-compose.yml:
services:
documenso:
image: documenso/documenso:v2.6.1
restart: unless-stopped
depends_on:
database:
condition: service_healthy
ports:
- "${PORT:-3000}:${PORT:-3000}"
env_file: .env
environment:
- NEXT_PRIVATE_DIRECT_DATABASE_URL=${NEXT_PRIVATE_DATABASE_URL}
- NEXT_PRIVATE_INTERNAL_WEBAPP_URL=http://localhost:${PORT:-3000}
healthcheck:
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
interval: 15s
timeout: 5s
retries: 3
database:
image: postgres:15
restart: unless-stopped
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
Start the stack:
docker compose up -d
Initial Configuration
- Open
http://your-server:3000— the login page appears immediately - Create your admin account through the signup form
- Upload a PDF, place signature fields, and send your first document
Adding a Signing Certificate
For documents with verifiable digital signatures, mount a .p12 certificate:
# Add to the documenso service in docker-compose.yml
volumes:
- ./cert.p12:/opt/documenso/cert.p12:ro
environment:
- NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH=/opt/documenso/cert.p12
- NEXT_PRIVATE_SIGNING_PASSPHRASE=your-certificate-passphrase
Generate a self-signed certificate for testing:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
openssl pkcs12 -export -out cert.p12 -inkey key.pem -in cert.pem
Configuration Options
| Variable | Purpose | Default |
|---|---|---|
NEXT_PUBLIC_WEBAPP_URL | Public URL (shown in emails) | Required |
NEXT_PUBLIC_UPLOAD_TRANSPORT | File storage: database or s3 | database |
NEXT_PUBLIC_DISABLE_SIGNUP | Block new user registration | Not set |
NEXT_PRIVATE_SMTP_TRANSPORT | smtp-auth, smtp-api, resend, mailchannels | Required |
S3 Document Storage
By default, Documenso stores uploaded documents in PostgreSQL. For large volumes of documents, switch to S3:
# Add to .env
NEXT_PUBLIC_UPLOAD_TRANSPORT=s3
NEXT_PRIVATE_UPLOAD_ENDPOINT=https://s3.amazonaws.com
NEXT_PRIVATE_UPLOAD_BUCKET=documenso-docs
NEXT_PRIVATE_UPLOAD_REGION=us-east-1
NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID=your-key
NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY=your-secret
Works with AWS S3, MinIO, DigitalOcean Spaces, and any S3-compatible provider.
Reverse Proxy
For SSL termination with Caddy:
sign.example.com {
reverse_proxy localhost:3000
}
See Reverse Proxy Setup for Nginx and Traefik configurations.
Backup
The Documenso application container is stateless — all data lives in PostgreSQL (and optionally S3).
# Database backup
docker compose exec database pg_dump -U documenso documenso > documenso-backup.sql
# Restore
cat documenso-backup.sql | docker compose exec -T database psql -U documenso documenso
If using the default database upload transport, document files are also in PostgreSQL and included in the dump. If using S3, back up the bucket separately.
See Backup Strategy for automated approaches.
Troubleshooting
Health check fails after startup
Symptom: Container restarts with health check failures
Fix: Documenso runs database migrations on first start, which can take 30-60 seconds. Increase the health check start_period to 60s if the container keeps restarting during initial setup.
”Invalid encryption key” error
Symptom: Application crashes with encryption key validation error
Fix: NEXT_PRIVATE_ENCRYPTION_KEY and NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY must each be at least 32 characters. Generate with openssl rand -hex 32. Once set, do not change these — existing signed documents will become unreadable.
Emails not being sent
Symptom: Signers don’t receive signing requests
Fix: Verify SMTP credentials. Documenso requires NEXT_PRIVATE_SMTP_TRANSPORT to be explicitly set — it won’t fall back to another method silently. Test your SMTP server independently first. If using Resend, set the transport to resend and add NEXT_PRIVATE_RESEND_API_KEY.
Resource Requirements
| Resource | Minimum | Recommended |
|---|---|---|
| RAM | 1 GB | 2 GB |
| CPU | 1 vCPU | 2 vCPUs |
| Disk | 3 GB + documents | 10 GB + documents |
Verdict
Documenso is the best choice if you need verifiable digital signatures with .p12 certificates and want permissive MIT licensing. The setup is more involved than DocuSeal (more environment variables, mandatory SMTP), but the signing workflow and API are solid.
For most small teams just replacing DocuSign, DocuSeal is simpler to get running. Choose Documenso when you need: digital certificate signing, OAuth/SSO integration, or when the MIT license matters for your use case. See the full 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