All Collections › Open Source Apps › Documenso

Documenso

Documenso is an open source document signing platform, an alternative to DocuSign

Updated

Documenso lets you send documents for electronic signature, with templates, teams, an API and webhooks. It is a Node.js monorepo (React Router on a Hono server, Prisma, Turborepo) backed by PostgreSQL, licensed under AGPL-3.0.

Requirements

Create a PostgreSQL database (version 14 or newer) on the app's Databases tab. When attaching it, name the variable NEXT_PRIVATE_DATABASE_URL instead of DATABASE_URL.

Documenso signs completed PDFs with an X.509 certificate that it does not ship with. Create a .p12 file before going to production, for example a self-signed one:

openssl genrsa -out private.key 2048
openssl req -new -x509 -key private.key -out certificate.crt -days 365
openssl pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt

Set a password when prompted; certificates without one fail at signing time. Base64-encode the file (base64 -w0 certificate.p12 on Linux, base64 -i certificate.p12 on macOS) for the environment variable below.

Documenso requires Node.js 24 and npm 11.17 or newer. The build needs a lot of memory: build on a server with at least 8 GB of RAM.

Repository

Fork the upstream repository and deploy your fork from a release tag such as v2.19.0.

https://github.com/documenso/documenso.git

In your fork, add a .node-version file containing 24.21.0 (upstream has no Node version file; its Docker image uses Node 24) and add the .hatchbox/post-build script below.

Environment Variables

NEXTAUTH_SECRET=...                            # `openssl rand -hex 32`
NEXT_PRIVATE_ENCRYPTION_KEY=... # `openssl rand -hex 32`
NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY=... # `openssl rand -hex 32`
NEXT_PUBLIC_WEBAPP_URL=https://sign.example.com
NEXT_PRIVATE_DATABASE_URL=postgres://... # set by Hatchbox when attaching the database
NEXT_PRIVATE_DIRECT_DATABASE_URL=postgres://... # same value as NEXT_PRIVATE_DATABASE_URL
NEXT_PRIVATE_SIGNING_TRANSPORT=local
NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS=... # base64 of certificate.p12
NEXT_PRIVATE_SIGNING_PASSPHRASE=... # the .p12 password
NEXT_PRIVATE_SMTP_TRANSPORT=smtp-auth
NEXT_PRIVATE_SMTP_HOST=smtp.example.com
NEXT_PRIVATE_SMTP_PORT=587
NEXT_PRIVATE_SMTP_USERNAME=...
NEXT_PRIVATE_SMTP_PASSWORD=...
NEXT_PRIVATE_SMTP_FROM_NAME=Documenso
NEXT_PRIVATE_SMTP_FROM_ADDRESS=noreply@example.com

NEXT_PUBLIC_WEBAPP_URL is the domain you add on the Domains tab. Email is required for sending signing requests; NEXT_PRIVATE_SMTP_TRANSPORT can also be resend with NEXT_PRIVATE_RESEND_API_KEY.

Uploaded documents are stored in PostgreSQL by default. For S3 storage, set NEXT_PUBLIC_UPLOAD_TRANSPORT=s3 and the NEXT_PRIVATE_UPLOAD_* variables from .env.example.

Background jobs run inside the web process using PostgreSQL by default. For production, upstream recommends BullMQ: add a Redis database, attach it as NEXT_PRIVATE_REDIS_URL, and set NEXT_PRIVATE_JOBS_PROVIDER=bullmq.

Build Scripts

Hatchbox runs npm install. The script below builds only the web app and its workspace dependencies, the same way the upstream Dockerfile does, and applies Prisma migrations on the cron server.

.hatchbox/post-build

#!/usr/bin/env bash
set -e

export NODE_OPTIONS="--max-old-space-size=8192"
npx turbo run build --filter=@documenso/remix...

if [ "$CRON" = "true" ]; then
npx prisma migrate deploy --schema packages/prisma/schema.prisma
fi

Make the file executable before committing it.

Processes

The server reads PORT from the environment. Add one process on the web servers:

  • web: cd apps/remix && NODE_ENV=production node build/server/main.js

First Login

There is no default account. Open your domain and create the first user on the sign-up page. New accounts must confirm their email address before they can sign in, so set up SMTP (or Resend) before signing up. Once your team has accounts, set NEXT_PUBLIC_DISABLE_SIGNUP=true to close public registration.

Notes

Check https://sign.example.com/api/certificate-status after deploying to confirm the signing certificate loaded. Documenso keeps everything in PostgreSQL (or S3), so nothing on disk needs to persist between deploys. To update, merge a newer release tag into your fork and deploy; the build script applies migrations.