# Documenso

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

[Documenso](https://github.com/documenso/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&#39;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=&quot;--max-old-space-size=8192&quot;
npx turbo run build --filter=@documenso/remix...

if [ &quot;$CRON&quot; = &quot;true&quot; ]; 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 &amp;&amp; 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.
