Skip to main content

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

FeatureDocusealDocuSignDocumenso
PriceFree (self-host)$10-25/user/moFree (self-host)
Template builderDrag-and-dropDrag-and-dropBasic
Multi-signerYes (ordered)YesYes
APIRESTRESTREST
BrandingCustomizableLimited (paid)Customizable
Audit trailYesYesYes
Self-hostedYesNoYes
Stars~6KN/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

  1. Templates → + New Template
  2. Upload PDF (contract, NDA, agreement, offer letter, etc.)
  3. The PDF pages appear in the editor

Add signature fields

Drag fields onto the PDF:

Field TypeDescription
SignatureDrawn or typed signature
InitialsShort initials field
DateAuto-filled signing date
TextFree text input (name, address, etc.)
CheckboxAgreement checkboxes
SelectDropdown menu
ImageUpload an image (ID, photo)
StampCompany stamp/seal

Multi-signer templates

  1. Add signers: Client, Company Representative, Witness
  2. Assign fields to specific signers (color-coded)
  3. 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

  1. Templates → Select template → Create submission
  2. Enter signer details:
  3. Send → signer receives email with signing link
  4. Signer opens link → reviews document → signs → done

Signing experience

Signers see:

  1. Document preview with highlighted fields
  2. Click each field to fill it
  3. Draw signature (mouse, touch, or type)
  4. Submit → PDF sealed with signatures
  5. 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

  1. Create template from your standard employment agreement
  2. Add fields: employee name, position, salary, start date, signature
  3. API integration: HR system auto-sends when new hire is confirmed

NDAs

  1. Upload NDA PDF
  2. Fields: company name, individual name, date, signature
  3. Send via API before sharing confidential docs

Invoices and Purchase Orders

  1. Create invoice template
  2. Fields: line items (via variables), total, approval signature
  3. Integration with accounting system

Client proposals

  1. Upload proposal PDF
  2. Fields: scope, timeline, budget, acceptance signature
  3. 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.

Comments