Docker is the fastest way to get Documenso running in production. This guide covers two deployment options: a complete stack with Docker Compose, or a standalone container.
Prerequisites
Option 1: Docker Compose (Recommended)
This setup includes PostgreSQL and Documenso in a single compose file. Perfect for production deployments.
Step 1: Download Configuration
Download the production Docker Compose file:
curl -O https://raw.githubusercontent.com/documenso/documenso/main/docker/production/compose.yml
Or create compose.yml manually with the configuration from the repository .
Create a .env file in the same directory as compose.yml:
# Generate secrets with: openssl rand -hex 32
NEXTAUTH_SECRET = "your-secret-here"
NEXT_PRIVATE_ENCRYPTION_KEY = "your-encryption-key-here"
NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY = "your-secondary-key-here"
# Your application URL
NEXT_PUBLIC_WEBAPP_URL = "https://documenso.example.com"
# Database Configuration
POSTGRES_USER = "documenso"
POSTGRES_PASSWORD = "your-secure-database-password"
POSTGRES_DB = "documenso"
NEXT_PRIVATE_DATABASE_URL = "postgresql://${ POSTGRES_USER }:${ POSTGRES_PASSWORD }@database:5432/${ POSTGRES_DB }"
NEXT_PRIVATE_DIRECT_DATABASE_URL = "postgresql://${ POSTGRES_USER }:${ POSTGRES_PASSWORD }@database:5432/${ POSTGRES_DB }"
# SMTP Configuration
NEXT_PRIVATE_SMTP_TRANSPORT = "smtp-auth"
NEXT_PRIVATE_SMTP_HOST = "smtp.example.com"
NEXT_PRIVATE_SMTP_PORT = 587
NEXT_PRIVATE_SMTP_USERNAME = "your-smtp-username"
NEXT_PRIVATE_SMTP_PASSWORD = "your-smtp-password"
NEXT_PRIVATE_SMTP_FROM_NAME = "Documenso"
NEXT_PRIVATE_SMTP_FROM_ADDRESS = "[email protected] "
# Signing Certificate
NEXT_PRIVATE_SIGNING_PASSPHRASE = "your-certificate-password"
Replace all placeholder values with your actual configuration. Never use the example values in production.
Step 3: Generate Signing Certificate
You have two options for setting up the signing certificate:
Start the containers first, then generate a self-signed certificate inside the running container:
Generate certificate
# Set certificate password securely
read -s -p "Enter certificate password: " CERT_PASS
echo
# Generate certificate inside container
docker exec -e CERT_PASS=" $CERT_PASS " -it documenso-production-documenso-1 bash -c "
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /tmp/private.key \
-out /tmp/certificate.crt \
-subj '/C=US/ST=State/L=City/O=Organization/CN=localhost' && \
openssl pkcs12 -export -out /opt/documenso/cert.p12 \
-inkey /tmp/private.key -in /tmp/certificate.crt \
-passout env:CERT_PASS && \
rm /tmp/private.key /tmp/certificate.crt
"
Restart Documenso
docker compose restart documenso
The certificate password you enter must match the NEXT_PRIVATE_SIGNING_PASSPHRASE in your .env file.
If you have an existing .p12 certificate file:
Place certificate file
Copy your certificate to /opt/documenso/cert.p12 on your host machine: sudo mkdir -p /opt/documenso
sudo cp your-cert.p12 /opt/documenso/cert.p12
sudo chmod 644 /opt/documenso/cert.p12
sudo chown 1001:1001 /opt/documenso/cert.p12
Update compose.yml
Ensure the volume binding in compose.yml matches: volumes :
- /opt/documenso/cert.p12:/opt/documenso/cert.p12:ro
Step 4: Start Documenso
Start all services with Docker Compose:
docker compose --env-file .env up -d
This will:
Start the PostgreSQL database
Start the Documenso application
Run database migrations automatically
Expose the application on port 3000
Step 5: Access Your Instance
Open your browser and navigate to:
For production, set up a reverse proxy (nginx, Caddy, Traefik) to handle HTTPS and point to http://localhost:3000.
Check the health of your instance at http://localhost:3000/api/health
Option 2: Standalone Container
Use this option if you’re managing your own database and want to deploy the Documenso container separately.
Step 1: Pull the Docker Image
Docker Hub
GitHub Container Registry
docker pull documenso/documenso:latest
Step 2: Prepare Signing Certificate
Ensure you have a .p12 certificate file ready at a known path (e.g., /path/to/cert.p12).
Step 3: Run the Container
docker run -d \
--name documenso \
-p 3000:3000 \
-e NEXTAUTH_SECRET="your-nextauth-secret" \
-e NEXT_PRIVATE_ENCRYPTION_KEY="your-encryption-key" \
-e NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY="your-secondary-key" \
-e NEXT_PUBLIC_WEBAPP_URL="https://documenso.example.com" \
-e NEXT_PRIVATE_INTERNAL_WEBAPP_URL="http://localhost:3000" \
-e NEXT_PRIVATE_DATABASE_URL="postgresql://user:password@host:5432/documenso" \
-e NEXT_PRIVATE_DIRECT_DATABASE_URL="postgresql://user:password@host:5432/documenso" \
-e NEXT_PRIVATE_SMTP_TRANSPORT="smtp-auth" \
-e NEXT_PRIVATE_SMTP_HOST="smtp.example.com" \
-e NEXT_PRIVATE_SMTP_PORT= 587 \
-e NEXT_PRIVATE_SMTP_USERNAME="your-username" \
-e NEXT_PRIVATE_SMTP_PASSWORD="your-password" \
-e NEXT_PRIVATE_SMTP_FROM_NAME="Documenso" \
-e NEXT_PRIVATE_SMTP_FROM_ADDRESS="[email protected] " \
-e NEXT_PRIVATE_SIGNING_PASSPHRASE="your-cert-password" \
-v /path/to/cert.p12:/opt/documenso/cert.p12:ro \
documenso/documenso:latest
Replace all environment variables with your actual values.
Container Management
View Logs
docker compose logs -f documenso
Restart Container
docker compose restart documenso
Stop Services
Update to Latest Version
docker compose pull
docker compose up -d
Troubleshooting
Certificate Errors
If you see “Failed to read signing certificate” errors:
Check file exists
docker exec -it documenso-production-documenso-1 ls -la /opt/documenso/cert.p12
Verify permissions
# On host machine
ls -la /opt/documenso/cert.p12
# Should show: -rw-r--r-- 1 1001 1001
Check certificate status
curl http://localhost:3000/api/certificate-status
Database Connection Issues
If the application can’t connect to the database:
Verify database is running
docker compose ps database
Check database logs
docker compose logs database
Test connection manually
docker exec -it documenso-production-database-1 \
psql -U documenso -d documenso -c "SELECT 1;"
Port Already in Use
If port 3000 is already in use, change it in compose.yml:
ports :
- "8080:3000" # Use port 8080 on host
And update your PORT environment variable if needed.
Advanced Configuration
Using S3 for Document Storage
Add these environment variables to use S3 instead of database storage:
NEXT_PUBLIC_UPLOAD_TRANSPORT = s3
NEXT_PRIVATE_UPLOAD_REGION = us-east-1
NEXT_PRIVATE_UPLOAD_BUCKET = documenso-documents
NEXT_PRIVATE_UPLOAD_ACCESS_KEY_ID = your-access-key
NEXT_PRIVATE_UPLOAD_SECRET_ACCESS_KEY = your-secret-key
IPv6 Support
To run Documenso on IPv6-only networks, modify the start command in compose.yml:
command : [ "/bin/sh" , "-c" , "npm run start -- -H ::" ]
Custom Port
To run on a different port, set the PORT environment variable:
And update the port mapping in compose.yml.
Reverse Proxy Setup
For production deployments, use a reverse proxy to handle HTTPS:
server {
listen 80 ;
server_name documenso.example.com;
return 301 https://$ server_name $ request_uri ;
}
server {
listen 443 ssl http2;
server_name documenso.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $ host ;
proxy_set_header X-Real-IP $ remote_addr ;
proxy_set_header X-Forwarded-For $ proxy_add_x_forwarded_for ;
proxy_set_header X-Forwarded-Proto $ scheme ;
}
}
documenso.example.com {
reverse_proxy localhost:3000
}
Caddy automatically handles HTTPS with Let’s Encrypt.
Backup and Recovery
Backup Database
docker exec documenso-production-database-1 \
pg_dump -U documenso documenso > backup.sql
Restore Database
cat backup.sql | docker exec -i documenso-production-database-1 \
psql -U documenso -d documenso
Backup Certificate
sudo cp /opt/documenso/cert.p12 ~/documenso-cert-backup.p12
Store certificate backups securely. They are critical for signature validation.
Next Steps
Environment Variables Learn about all available configuration options
OAuth Setup Configure Google or Microsoft sign-in
Email Configuration Set up email delivery with different providers
Signing Certificates Advanced certificate configuration