Setup Document Encryption
Document encryption in Papra provides end-to-end protection for your stored documents using industry-standard AES-256-GCM encryption. This guide will walk you through enabling encryption, understanding how it works, and managing encryption keys.
How Encryption Works
Section titled “How Encryption Works”Papra uses a two-layer encryption approach that provides both security and flexibility:
Key Encryption Architecture
Section titled “Key Encryption Architecture”- Key Encryption Key (KEK): A master key that you provide, used to encrypt document-specific keys
- Document Encryption Key (DEK): Unique per-document keys that actually encrypt your files
- File Encryption: Each document gets its own random 256-bit encryption key for maximum security
Encryption Flow
Section titled “Encryption Flow”-
Document Upload: When you upload a document, Papra generates a unique 256-bit encryption key (DEK)
-
File Encryption: The document is encrypted using AES-256-GCM with the DEK
-
Key Wrapping: The DEK is encrypted (wrapped) using your Key Encryption Key (KEK)
-
Storage: The encrypted document and wrapped DEK are stored separately - the file in your storage backend, the wrapped key in the database along with the document metadata
-
Retrieval: When accessing a document, Papra unwraps the DEK using your KEK, then decrypts the file stream
Quick Setup
Section titled “Quick Setup”-
Generate an encryption key
Generate a secure random 256-bit key in hex format, using this generator or OpenSSL command.
Generated locally in your browser - no network or server involvedTerminal window openssl rand -hex 32This will output something like:
0deba5534bd70548de92d1fd4ae37cf901cca3dc20589b7e022ddb680c98e50c
-
Enable encryption in your configuration
Add the following environment variables to your
.env
file or Docker configuration:Terminal window DOCUMENT_STORAGE_ENCRYPTION_IS_ENABLED=trueDOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=<your-encryption-key> -
Restart Papra
Restart your Papra instance to apply the encryption settings.
Configuration Options
Section titled “Configuration Options”Environment Variables
Section titled “Environment Variables”Variable | Description | Required |
---|---|---|
DOCUMENT_STORAGE_ENCRYPTION_IS_ENABLED | Enable/disable document encryption | No |
DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS | Key encryption keys for document encryption | Yes (if encryption enabled) |
Key Formats
Section titled “Key Formats”For simple setups, provide a single 32-byte hex string:
DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=<your-encryption-key>
This key will automatically be assigned version 1
.
For key rotation and advanced setups, provide versioned keys:
DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=1:<your-encryption-key-1>,2:<your-encryption-key-2>
- The highest version key encrypts new documents
- All keys can decrypt existing documents
- Versions can be any alphabetically sortable string
- Order in the list doesn’t matter
Docker Compose Setup
Section titled “Docker Compose Setup”Add encryption configuration to your Docker Compose file:
services: papra: container_name: papra image: ghcr.io/papra-hq/papra:latest restart: unless-stopped environment: # ... other environment variables ... - DOCUMENT_STORAGE_ENCRYPTION_IS_ENABLED=true - DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=<your-encryption-key> volumes: - ./app-data:/app/app-data ports: - "1221:1221"
services: papra: container_name: papra image: ghcr.io/papra-hq/papra:latest restart: unless-stopped volumes: - ./app-data:/app/app-data - ./papra.config.yaml:/app/app-data/papra.config.yaml ports: - "1221:1221"
documentsStorage: encryption: isEncryptionEnabled: true documentKeyEncryptionKeys: "<your-encryption-key>"
Key Management
Section titled “Key Management”Key Rotation
Section titled “Key Rotation”Key rotation allows you to replace encryption keys without losing access to existing documents:
-
Generate a new key
Terminal window openssl rand -hex 32 -
Add the new key with a higher version
Terminal window DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=1:old_key_here,2:new_key_here -
Restart Papra
New documents will use the highest version key (version 2), while existing documents remain accessible with the old key.
-
Optional: Remove old keys
Once you’re confident all documents are using the new key, you can remove old keys. However, this will make any documents encrypted with old keys inaccessible.
Key Security Best Practices
Section titled “Key Security Best Practices”- Store keys securely: Use a secrets management system in production
- Use different keys per environment: Development, staging, and production should have separate keys
- Backup your keys: Loss of encryption keys means permanent loss of document access
- Rotate keys periodically: Consider rotating keys annually or after security incidents
- Limit key access: Only authorized personnel should have access to encryption keys
Docker Secrets Example
Section titled “Docker Secrets Example”For production environments, store your encryption keys securely using external secret management systems or secure file systems, and reference them via environment variables.
Compatibility and Migration
Section titled “Compatibility and Migration”Enabling Encryption on Existing Instances
Section titled “Enabling Encryption on Existing Instances”When you enable encryption on a Papra instance that already has documents:
- Existing documents: Remain unencrypted but accessible
- New documents: Are encrypted using the current KEK
- Mixed storage: Papra automatically handles both encrypted and unencrypted documents
Migrating Existing Documents to Encrypted Format
Section titled “Migrating Existing Documents to Encrypted Format”If you want to encrypt all existing unencrypted documents after enabling encryption, Papra provides a maintenance command to handle this migration automatically.
-
Verify encryption is properly configured
Ensure encryption is enabled and working for new documents before migrating existing ones:
Terminal window # Check that your configuration includes:DOCUMENT_STORAGE_ENCRYPTION_IS_ENABLED=trueDOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS=<your-key> -
Run dry-run to preview changes
Terminal window # Run dry-run inside the Docker containerdocker compose exec papra pnpm maintenance:encrypt-all-documents --dry-runTerminal window # Run dry-run inside the Docker containerdocker exec -it papra pnpm maintenance:encrypt-all-documents --dry-runTerminal window # From your Papra server directorypnpm maintenance:encrypt-all-documents --dry-runThis will show you:
- How many documents will be encrypted
- Which documents will be affected
- No actual encryption will be performed
-
Run the migration
Terminal window # Run migration inside the Docker containerdocker compose exec papra pnpm maintenance:encrypt-all-documentsTerminal window # Run migration inside the Docker containerdocker exec -it papra pnpm maintenance:encrypt-all-documentsTerminal window # From your Papra server directorypnpm maintenance:encrypt-all-documentsThe command will:
- Find all unencrypted documents
- Encrypt each document using your configured KEK
- Update database records with encryption metadata
- Remove original unencrypted files from storage
- Provide progress logging throughout the process
-
Verify migration success
After migration:
- Test document access through the Papra interface
- Check that storage files are now encrypted (should start with
PP01
) - Verify all documents are accessible and downloadable
Troubleshooting Migration Issues
Section titled “Troubleshooting Migration Issues”Migration fails with “Document encryption is not enabled”
- Verify
DOCUMENT_STORAGE_ENCRYPTION_IS_ENABLED=true
is set - Restart Papra after configuration changes
Migration fails with “Document encryption keys are not set”
- Ensure
DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS
contains valid keys - Verify key format is correct (64-character hex string)
Migration stops or fails partway
- Check available disk space
- Review Papra logs for specific error messages
- Restore from backup and retry after fixing the issue
Documents inaccessible after migration
- Verify encryption keys are still properly configured
- Check that Papra can access your storage backend
- Restore from backup if necessary
Disabling Encryption
Section titled “Disabling Encryption”If you disable encryption:
- Encrypted documents: Remain encrypted but are automatically decrypted when accessed (if KEK is still available)
- New documents: Are stored unencrypted
- Data loss risk: If you remove the KEK while encrypted documents exist, those documents become inaccessible
Storage Driver Compatibility
Section titled “Storage Driver Compatibility”The encryption layer sits between Papra and your chosen storage driver, providing consistent encryption regardless of where files are stored (S3, Azure Blob Storage, File System, etc.).
Technical Details
Section titled “Technical Details”Encryption Algorithm
Section titled “Encryption Algorithm”- Algorithm: AES-256-GCM (Authenticated Encryption)
- Key size: 256 bits (32 bytes)
- IV size: 96 bits (12 bytes)
- Authentication tag: 128 bits (16 bytes)
File Format
Section titled “File Format”Encrypted files use a custom format with a magic number for identification:
| Magic (4 bytes) | IV (12 bytes) | Encrypted Data | Auth Tag (16 bytes) |
- Magic number:
PP01
- identifies Papra encrypted files - IV: Initialization vector for GCM mode
- Encrypted Data: The actual encrypted document content
- Auth Tag: Authentication tag for integrity verification
Performance Considerations
Section titled “Performance Considerations”- Streaming encryption: Files are encrypted/decrypted in streams, minimizing memory usage
- No size overhead: Minimal storage overhead (32 bytes per file for headers)
- CPU impact: Modern processors handle AES encryption efficiently
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”“Document KEK required” error
- Ensure
DOCUMENT_STORAGE_DOCUMENT_KEY_ENCRYPTION_KEYS
is set - Verify the key format is correct (64 character hex string)
“Document KEK not found” error
- The document was encrypted with a key version that’s no longer available
- Add the missing key version back to your configuration
“Unsupported encryption algorithm” error
- The document uses an encryption algorithm not supported by this Papra version
- This shouldn’t occur in normal operation
Performance issues
- Consider your storage driver’s performance characteristics
- Encryption adds minimal overhead, but network/disk I/O remains the bottleneck
Verification
Section titled “Verification”To verify encryption is working:
- Upload a document after enabling encryption
- Check your storage backend - the file should not be readable as plain text
- The file should start with the magic number
PP01
if you examine it directly
Security Considerations
Section titled “Security Considerations”Threat Model
Section titled “Threat Model”Document encryption in Papra protects against:
- Storage compromise: If your file storage is breached, documents remain encrypted
- Database-only breach: Without the KEK, wrapped DEKs cannot be unwrapped
- Configuration exposure: If the KEK is exposed, the files remain encrypted as long as the DEK are not exposed
Limitations
Section titled “Limitations”Encryption does not protect against:
- Application-level access: Users with document access can view decrypted content
- Memory dumps: Decrypted content exists temporarily in application memory
- Key and database compromise: If KEKs are stolen, all DEKs can be decrypted if the database is compromised
- Full system compromise: If the entire Papra instance is compromised, documents can be accessed