Local signing uses a .p12 (PKCS#12) certificate file to sign PDF documents. This is the simplest method to get started and works well for most deployments.
Prerequisites
You’ll need a .p12 certificate file. You can either:
Use your own certificate from a Certificate Authority
Generate a self-signed certificate for testing/development
Generating a Self-Signed Certificate
For development or testing, you can create a self-signed certificate using OpenSSL:
# Generate a private key and certificate
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Convert to .p12 format (you'll be prompted for a passphrase)
openssl pkcs12 -export -out certificate.p12 -inkey key.pem -in cert.pem
When prompted, enter:
Common Name (CN) : Your organization or app name (e.g., “Documenso”)
Export Password : A strong passphrase (you’ll need this for configuration)
Self-signed certificates work but won’t show as “trusted” in PDF viewers. For production, consider purchasing a certificate from a trusted CA like DigiCert or GlobalSign.
Configuration Methods
Documenso supports two ways to provide the certificate:
File path - Store the .p12 file on disk
Base64-encoded - Store the certificate as an environment variable (recommended for containers)
Method 1: File Path
Place your .p12 file somewhere accessible to the application:
# Signing configuration
NEXT_PRIVATE_SIGNING_TRANSPORT = "local"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH = "/path/to/certificate.p12"
NEXT_PRIVATE_SIGNING_PASSPHRASE = "your-certificate-passphrase"
Example with Docker:
# Mount the certificate file
docker run -d \
-v /host/path/to/certificate.p12:/app/certificate.p12 \
-e NEXT_PRIVATE_SIGNING_TRANSPORT="local" \
-e NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH="/app/certificate.p12" \
-e NEXT_PRIVATE_SIGNING_PASSPHRASE="your-passphrase" \
documenso/documenso
Method 2: Base64-Encoded (Recommended for Containers)
Convert your .p12 file to base64 and store it as an environment variable:
# Convert certificate to base64
base64 -i certificate.p12 | tr -d '\n' > certificate.base64.txt
# Or on macOS:
base64 -i certificate.p12 | pbcopy
Then configure:
NEXT_PRIVATE_SIGNING_TRANSPORT = "local"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS = "MIIKPAIBAzCCCgYGCSqGSIb3DQEHA..."
NEXT_PRIVATE_SIGNING_PASSPHRASE = "your-certificate-passphrase"
The base64 method is ideal for serverless environments (Vercel, AWS Lambda) and container platforms where mounting files is inconvenient.
Environment Variables Reference
NEXT_PRIVATE_SIGNING_TRANSPORT
Set to "local" to use file-based signing. NEXT_PRIVATE_SIGNING_TRANSPORT = "local"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH
Path to the .p12 certificate file. Use this OR NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS. NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH = "/app/certs/certificate.p12"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS
Base64-encoded contents of the .p12 file. Use this OR NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH. NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS = "MIIKPAIBAzCCC..."
NEXT_PRIVATE_SIGNING_PASSPHRASE
Passphrase for the .p12 certificate. Leave empty if the certificate has no password. NEXT_PRIVATE_SIGNING_PASSPHRASE = "my-secure-passphrase"
Complete Configuration Example
File Path
Base64-Encoded
Docker Compose
# Signing configuration
NEXT_PRIVATE_SIGNING_TRANSPORT = "local"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH = "/app/certs/certificate.p12"
NEXT_PRIVATE_SIGNING_PASSPHRASE = "your-passphrase"
# Optional: Add timestamp authorities for LTV
NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY = "http://timestamp.digicert.com,http://timestamp.globalsign.com/tsa/r6advanced1"
# Optional: Customize contact info
NEXT_PUBLIC_SIGNING_CONTACT_INFO = "support@example.com"
# Signing configuration
NEXT_PRIVATE_SIGNING_TRANSPORT = "local"
NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS = "MIIKPAIBAzCCCgYGCSqGSIb3DQEHAaCCCfcEggn..."
NEXT_PRIVATE_SIGNING_PASSPHRASE = "your-passphrase"
# Optional: Add timestamp authorities for LTV
NEXT_PRIVATE_SIGNING_TIMESTAMP_AUTHORITY = "http://timestamp.digicert.com"
# Optional: Customize contact info
NEXT_PUBLIC_SIGNING_CONTACT_INFO = "support@example.com"
version : '3.8'
services :
documenso :
image : documenso/documenso:latest
environment :
NEXT_PRIVATE_SIGNING_TRANSPORT : local
NEXT_PRIVATE_SIGNING_PASSPHRASE : your-passphrase
# Use file path
NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH : /app/certs/certificate.p12
# Or use base64 contents
# NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS: MIIKPAIBAzCCC...
volumes :
- ./certificate.p12:/app/certs/certificate.p12:ro
Development Mode
In non-production environments, if no certificate is configured, Documenso will automatically use an example certificate located at ./example/cert.p12.
The example certificate is only for development. Always configure your own certificate for production deployments.
Security Best Practices
Secure the Certificate File
Set restrictive file permissions on the .p12 file: chmod 600 certificate.p12
chown app-user:app-group certificate.p12
Use Strong Passphrases
Always protect your .p12 file with a strong passphrase (minimum 16 characters).
Store Secrets Securely
Never commit certificates or passphrases to version control. Use:
Environment variables
Secret management services (AWS Secrets Manager, HashiCorp Vault)
Encrypted configuration files
Rotate Certificates Regularly
Replace certificates before they expire. Most CAs issue certificates valid for 1-2 years.
Monitor Certificate Expiration
Set up alerts to notify you before certificate expiration.
Troubleshooting
”No certificate found for local signing”
Cause: Neither NEXT_PRIVATE_SIGNING_LOCAL_FILE_PATH nor NEXT_PRIVATE_SIGNING_LOCAL_FILE_CONTENTS is set.
Solution: Provide the certificate using one of the two methods above.
”Failed to load certificate”
Possible causes:
Incorrect passphrase
Corrupted .p12 file
Invalid base64 encoding
Solution: Verify the passphrase and re-encode the certificate:
# Test the certificate with OpenSSL
openssl pkcs12 -info -in certificate.p12 -noout
# Re-encode to base64
base64 -i certificate.p12 | tr -d '\n'
“Signature not trusted” in PDF viewer
Cause: Self-signed certificate or certificate not in Adobe Approved Trust List (AATL).
Solution: This is expected behavior for self-signed certificates. To show as “trusted”:
Purchase a certificate from an AATL-approved CA (DigiCert, GlobalSign, etc.)
Or users can manually trust your certificate in their PDF viewer
Migrating to Google Cloud KMS
If you need enhanced security later, you can migrate from local signing to Google Cloud KMS without changing your documents:
Set up Google Cloud KMS (see Google Cloud KMS Setup )
Update your environment variables to use gcloud-hsm transport
Restart your application
All new signatures will use the KMS key, while existing signatures remain valid.
Next Steps
Environment Variables View all configuration options
Google Cloud KMS Upgrade to hardware-secured signing