Self-Host Docuseal: Open Source Document Signing 2026
·OSSAlt Team
docusealdocument-signingesignatureself-hostingdocker2026
TL;DR
Docuseal (AGPL 3.0, ~6K GitHub stars, Ruby) is a self-hosted document signing platform. Upload a PDF, drag-and-drop signature fields onto it, send to signers, and collect legally binding signatures — all from your own server. DocuSign charges $10-$25/month per user; HelloSign charges $15/month. Docuseal gives you unlimited signatures, unlimited templates, and unlimited users for free.
Key Takeaways
- Docuseal: AGPL 3.0, ~6K stars, Ruby — full document signing with template builder
- Template builder: Drag-and-drop field placement — signature, date, text, checkbox
- Multiple signers: Routing order, sequential or parallel signing
- REST API: Programmatic document generation and signing from any app
- Mobile friendly: Signers can sign on any device — no app install required
- Audit trail: Complete signing history with timestamps and IP addresses
Docuseal vs DocuSign vs Documenso
| Feature | Docuseal | DocuSign | Documenso |
|---|---|---|---|
| Price | Free (self-host) | $10-25/user/mo | Free (self-host) |
| Template builder | Drag-and-drop | Drag-and-drop | Basic |
| Multi-signer | Yes (ordered) | Yes | Yes |
| API | REST | REST | REST |
| Branding | Customizable | Limited (paid) | Customizable |
| Audit trail | Yes | Yes | Yes |
| Self-hosted | Yes | No | Yes |
| Stars | ~6K | N/A | ~8K |
Part 1: Docker Setup
# docker-compose.yml
services:
docuseal:
image: docuseal/docuseal:latest
container_name: docuseal
restart: unless-stopped
ports:
- "3000:3000"
volumes:
- docuseal_data:/data
environment:
DATABASE_URL: "sqlite3:///data/docuseal.db"
# Or use PostgreSQL:
# DATABASE_URL: "postgresql://docuseal:password@db:5432/docuseal"
SECRET_KEY_BASE: "${SECRET_KEY}" # openssl rand -hex 64
volumes:
docuseal_data:
echo "SECRET_KEY=$(openssl rand -hex 64)" >> .env
docker compose up -d
Visit http://your-server:3000 → create your admin account.
Part 2: HTTPS with Caddy
sign.yourdomain.com {
reverse_proxy localhost:3000
}
Part 3: Creating Templates
Upload a document
- Templates → + New Template
- Upload PDF (contract, NDA, agreement, offer letter, etc.)
- The PDF pages appear in the editor
Add signature fields
Drag fields onto the PDF:
| Field Type | Description |
|---|---|
| Signature | Drawn or typed signature |
| Initials | Short initials field |
| Date | Auto-filled signing date |
| Text | Free text input (name, address, etc.) |
| Checkbox | Agreement checkboxes |
| Select | Dropdown menu |
| Image | Upload an image (ID, photo) |
| Stamp | Company stamp/seal |
Multi-signer templates
- Add signers:
Client,Company Representative,Witness - Assign fields to specific signers (color-coded)
- Set signing order: sequential (client first → company second) or parallel
Template variables
Use {{variables}} in templates that get filled programmatically:
Client Name: {{client_name}}
Date: {{contract_date}}
Amount: {{total_amount}}
Part 4: Sending Documents for Signing
Via web UI
- Templates → Select template → Create submission
- Enter signer details:
- Name: John Smith
- Email: john@example.com
- Send → signer receives email with signing link
- Signer opens link → reviews document → signs → done
Signing experience
Signers see:
- Document preview with highlighted fields
- Click each field to fill it
- Draw signature (mouse, touch, or type)
- Submit → PDF sealed with signatures
- All parties receive signed copy via email
Part 5: REST API
Create and send via API
TOKEN="your-api-token" # Settings → API
BASE="https://sign.yourdomain.com"
# List templates:
curl "$BASE/api/templates" \
-H "X-Auth-Token: $TOKEN" | jq '.[].name'
# Create a submission (send for signing):
curl -X POST "$BASE/api/submissions" \
-H "X-Auth-Token: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"template_id": 1,
"send_email": true,
"submitters": [
{
"role": "Client",
"email": "client@example.com",
"name": "John Smith",
"fields": [
{"name": "client_name", "default_value": "John Smith"},
{"name": "contract_date", "default_value": "2026-03-09"}
]
},
{
"role": "Company",
"email": "ceo@company.com",
"name": "Jane Doe"
}
]
}'
# Check submission status:
curl "$BASE/api/submissions/1" \
-H "X-Auth-Token: $TOKEN" | jq '{status: .status, signers: [.submitters[].status]}'
# Download signed PDF:
curl "$BASE/api/submissions/1/documents/1" \
-H "X-Auth-Token: $TOKEN" \
-o signed-contract.pdf
Webhook notifications
# Configure webhook to get notified when documents are signed:
# Settings → Webhooks → Add
# URL: https://yourapp.com/webhook/docuseal
# Events: submission.completed, submission.created
# Webhook payload:
{
"event_type": "submission.completed",
"data": {
"id": 1,
"template_id": 1,
"status": "completed",
"submitters": [
{"email": "client@example.com", "status": "completed", "signed_at": "2026-03-09T15:30:00Z"}
]
}
}
Part 6: Branding and Customization
Company branding
Settings → Branding:
- Logo: upload your company logo
- Company name: appears on signing pages
- Primary color: match your brand
- Email templates: customize notification emails
Custom signing page
The signing page shows:
- Your logo and company name
- The document
- A clean, distraction-free interface
- No Docuseal branding (on self-hosted)
Part 7: Use Cases
Employment contracts
- Create template from your standard employment agreement
- Add fields: employee name, position, salary, start date, signature
- API integration: HR system auto-sends when new hire is confirmed
NDAs
- Upload NDA PDF
- Fields: company name, individual name, date, signature
- Send via API before sharing confidential docs
Invoices and Purchase Orders
- Create invoice template
- Fields: line items (via variables), total, approval signature
- Integration with accounting system
Client proposals
- Upload proposal PDF
- Fields: scope, timeline, budget, acceptance signature
- Track acceptance status via API
Part 8: Audit Trail
Every document signing includes a complete audit trail:
- Created: timestamp, created by
- Sent: email sent to each signer
- Viewed: when each signer opened the document
- Signed: timestamp, IP address, user agent for each signature
- Completed: final document sealed
Access via:
Submissions → Select submission → Audit Log
Or via API:
curl "$BASE/api/submissions/1" \
-H "X-Auth-Token: $TOKEN" | jq '.audit_log'
Maintenance
# Update:
docker compose pull
docker compose up -d
# Backup:
tar -czf docuseal-backup-$(date +%Y%m%d).tar.gz \
$(docker volume inspect docuseal_docuseal_data --format '{{.Mountpoint}}')
# Logs:
docker compose logs -f docuseal
See all open source business tools at OSSAlt.com/categories/business.