Encrypt backups before uploading them to S3 destinations
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 15/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- postgresql, typescript
Research direction
This is a design proposal, so start by reading the maintainers' replies on the design questions (rclone crypt versus public-key encryption, licensing, and the overlap with #5696), not by changing code. The files it names are packages/server/src/db/schema/destination.ts, packages/server/src/utils/backups/utils.ts and redact.ts, and the restore and volume-backups helpers. Done would mean an agreed design, not a patch.
Written by the indexing model from the issue text.
Description
What problem will this feature address?
Dokploy uploads backups to S3 destinations without client-side encryption. Each backup goes straight from the dump to rclone, for example:
pg_dump -Fc ... | gzip | rclone rcat :s3:<bucket>/<path>
Anyone who can read the bucket can therefore read the backups:
- the storage provider, or anyone with access to the provider account
- anyone holding a leaked S3 key
- anyone reaching a bucket that was made public by mistake
The web server backup raises the stakes. It contains a dump of the Dokploy database, including the S3 credentials of each destination, and the .env files that Dokploy writes for compose services (createEnvFile is on by default). With "Include encryption key", also on by default, it carries the keys that decrypt the environment variables stored in that dump. One file can expose the secrets of every service.
Encrypting environment variables at rest (#4789) protects the database, but the backup remains a way around it. Teams with data protection obligations such as GDPR or LGPD also need backups that the storage provider cannot read.
Describe the solution you'd like
Optional encryption per destination, using rclone's crypt backend to encrypt on the server before anything is uploaded.
Why crypt:
- No new binary: rclone already ships in the Dokploy image and is installed on remote servers.
- One integration point: it wraps the existing
:s3:remote, so every backup type can use it. - No lock-in: backups can be restored without Dokploy, using only rclone and the password.
- Established format: XSalsa20-Poly1305 with authenticated 64 KiB chunks and about 0.03% size overhead.
Proposed behavior:
- Opt-in: S3 Destinations gets an "Encrypt backups" option with a password and a salt. Existing destinations don't change.
- Chosen at creation: it can't be toggled later, so a destination never mixes plaintext and encrypted files. To adopt encryption, create a new destination. Older backups remain restorable from the old one.
- Fail closed: an encrypted destination never receives plaintext. If the password is missing or can't be decrypted, the backup fails and sends the usual error notification.
- Full coverage: database, compose, volume and web server backups, across backup, retention, listing, download and restore.
- Readable file names:
filename_encryption=off, so listing and retention should keep working. Names, sizes and modification times stay visible; contents don't. - Secrets handling: password and salt use the existing
encryptedTextcolumn type and reach rclone throughRCLONE_CRYPT_PASSWORDandRCLONE_CRYPT_PASSWORD2, not command-line arguments.redactRcloneCredentialscovers them, and the--s3-*flags stay as they are, keeping the current quoting and redaction. - Clear warning in the UI: a lost password means lost backups. The web server backup can't be decrypted with a password stored only inside it, so users must keep a copy outside Dokploy.
Limitation: the password lives on the server, so this protects against the storage side, not against a compromised host.
Expected changes:
packages/server/src/db/schema/destination.ts: new columns and migrationpackages/server/src/utils/backups/utils.ts: one helper that builds the rclone remotepackages/server/src/utils/{backups,restore,volume-backups}/*: use that helper instead of building:s3:pathspackages/server/src/utils/backups/redact.ts: redact the new secretsapps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx: formapps/dokploy/__test__/backups/: tests
Describe alternatives you've considered
- Revive #3194 (rclone crypt): it's the same idea and the closest prior work, but it conflicts with
canaryand predates libSQL backups and backup downloads. It also puts S3 credentials inside connection strings, outside the quoting and redaction added since. If this moves forward, I'd start from currentcanaryand credit the author. - GPG, as in #2833, or
age: with a public key on the server, a compromised host can't decrypt older backups, which is a real advantage. The cost is a new binary on every server, private key handling during restore, and a much larger change. This could come later as a second option. - SSE-C through
additionalFlags: the provider still receives the key on each request, so this isn't client-side encryption. The key would also be missing from log redaction. - A custom backup job outside Dokploy: this works for databases, but loses restore and retention in the UI and can't cover the web server backup.
Additional context
I haven't started on this, and I'd like to hear what the maintainers think first. The design above is only a starting point, and I'm happy to change it or drop it if it doesn't fit the project:
- Is this something you'd want in Dokploy?
- Is rclone
cryptan acceptable direction, or would you prefer public-key encryption from the start? - Does this belong in the Apache-licensed core, or do you see it as an enterprise feature?
- #5696 changes the same rclone helpers. Should this wait for it and build on top?
- If you approve the approach, would it go on your team's list, or can anyone implement it and send a PR?
If it's open to outside contributors, I can implement what we agree on here and test backup, retention, listing, download and restore with each database type, on the local and on a remote server, against MinIO and Cloudflare R2.
Related: #416, #2833, #3194, #4789, #5696
Will you send a PR to implement it?
Maybe, need help
- Dominant language
- TypeScript
- Stars
- 38.2k
- Forks
- 3.1k
- Avg merge
- 2d 11h
- Merged PRs (30d)
- 65
Getting set up
Starts the project's dev container in your browser, under your own GitHub account.
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from Dokploy/dokploy
-
needs-triage🔍
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Dokploy/dokploy#5836 · 1 comment ·
Maintainers usually reply within 1 day
-
Server threshold (CPU/Memory) alerts for the main Dokploy server never reach any notificationPossibly taken @ghazy2001 claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Dokploy/dokploy#5830 · 1 comment ·
Maintainers usually reply within 1 day
-
Add a "System" option to the dark/light mode setting (follow OS appearance)Possibly taken @fabianfrankwerner claimed this 22 days ago. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
Dokploy/dokploy#5638 · 1 comment ·
Maintainers usually reply within 1 day
-
compose.search omits services missing from member accessedServices, even for owners/adminsPossibly taken @imrja8 claimed this 3 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Dokploy/dokploy#5361 · 2 comments · 1 reaction ·
Maintainers usually reply within 1 day
-
[Feature Request] Show usage example for File Mounts created in the UIPossibly taken @jereok91 claimed this 45 days ago. Openenhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Dokploy/dokploy#5147 · 3 comments · 1 reaction ·
Maintainers usually reply within 1 day
Similar issues
-
check:passed streams:remove
Difficulty 1/5 Under an hour Newbie friendliness 62/100
Maintainers usually reply within 1 day
-
bug needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
actions/setup-node#1659 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
vercel-labs/wterm#267 ·
Maintainers usually reply within 2 days
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
microsoft/AI-Engineering-Coach#355 · 1 reaction ·
Maintainers usually reply within 4 days
-
level1 nsoc26
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
GauravKarakoti/SecureFlow#1501 ·
Maintainers usually reply within 1 day