Documenso is an open-source e-signature platform: upload a PDF, drop signature, text and date fields on it, send it to signers, and watch it complete. It's the FOSS answer to DocuSign, with templates, bulk sending, and an API for generating agreements from your own system.
What it is
Templates with reusable field layouts, sequential or parallel signing order, email reminders, an audit trail with timestamps and IP addresses, and completed PDFs you can hand straight to a counterparty. It's the practical choice for contracts, NDAs and internal paperwork.
Before you start
- Set
NEXT_PUBLIC_APP_URLto the exact external URL, trailing slash included. It goes into every signing link, and a wrong value produces links that 404 for the recipient only. - Mail delivery is required for a usable product. Configure SMTP before you invite anyone, or signers never receive the request.
- You'll need a real domain. Signing links are sent to people outside your network, and a LAN-only URL makes the whole thing pointless.
1 — Create the directory
mkdir -p ~/services/documenso/{data,pgdata}
cd ~/services/documenso
openssl rand -hex 32
openssl rand -base64 24
2 — Write the compose file
services:
app:
image: documenso/documenso:latest
container_name: documenso
restart: unless-stopped
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "127.0.0.1:3000:3000"
volumes:
- ./data:/app/data
environment:
DATABASE_URL: postgresql://documenso:CHANGE_ME@db:5432/documenso
DATABASE_URL_DIRECT: postgresql://documenso:CHANGE_ME@db:5432/documenso
REDIS_URL: redis://redis:6379
NEXTAUTH_SECRET: CHANGE_ME
NEXTAUTH_URL: https://sign.example.com
NEXT_PUBLIC_APP_URL: https://sign.example.com/
PORT: 3000
TZ: UTC
redis:
image: redis:7-alpine
container_name: documenso-redis
restart: unless-stopped
command: redis-server --requirepass CHANGE_ME --save ""
healthcheck:
test: ["CMD", "redis-cli", "-a", "CHANGE_ME", "ping"]
interval: 30s
timeout: 5s
retries: 3
db:
image: postgres:16-alpine
container_name: documenso-db
restart: unless-stopped
environment:
POSTGRES_USER: documenso
POSTGRES_PASSWORD: CHANGE_ME
POSTGRES_DB: documenso
volumes:
- ./pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U documenso"]
interval: 10s
timeout: 5s
retries: 5
3 — Start it
docker compose up -d
docker compose logs -f app | grep -i "ready\|prisma\|error"
4 — First-run setup
- Register the first account at
https://sign.example.com. It becomes the organisation owner — the person who can set billing and delete the org. - Set up SMTP via the admin settings. Send yourself a test document and confirm both the request and the reminder emails arrive from a domain with correct SPF and DKIM, or they land in spam.
- Build a template from a real document. This is the feature that makes Documenso worth the setup time: upload a PDF once, define the signature/date/initial fields, and reuse it for every contract.
- Send a test to yourself, complete it, and download the result. Check the audit trail shows timestamps, IPs, and an email-verification state for each signer.
- Grab an API key from Settings → API and note the key and URL. The v1 API is documented and stable enough to generate documents from a form submission.
5 — Back it up
docker exec -u postgres documenso-db pg_dump -U documenso documenso | gzip > documenso-$(date +%F).sql.gz
# and every uploaded/signed PDF lives in ./data — back that up too
tar -czf documenso-data.tgz ./data
./data, you keep the metadata and lose the agreements. Treat the data directory as the important half.