Encrypt backups before uploading them to S3 destinations

Open
#5,837 1 comment 0 reactions 0 assignees View on GitHub

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
Domain
backend, security

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

enhancement
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:

  1. Opt-in: S3 Destinations gets an "Encrypt backups" option with a password and a salt. Existing destinations don't change.
  2. 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.
  3. 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.
  4. Full coverage: database, compose, volume and web server backups, across backup, retention, listing, download and restore.
  5. Readable file names: filename_encryption=off, so listing and retention should keep working. Names, sizes and modification times stay visible; contents don't.
  6. Secrets handling: password and salt use the existing encryptedText column type and reach rclone through RCLONE_CRYPT_PASSWORD and RCLONE_CRYPT_PASSWORD2, not command-line arguments. redactRcloneCredentials covers them, and the --s3-* flags stay as they are, keeping the current quoting and redaction.
  7. 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 migration
  • packages/server/src/utils/backups/utils.ts: one helper that builds the rclone remote
  • packages/server/src/utils/{backups,restore,volume-backups}/*: use that helper instead of building :s3: paths
  • packages/server/src/utils/backups/redact.ts: redact the new secrets
  • apps/dokploy/components/dashboard/settings/destination/handle-destinations.tsx: form
  • apps/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 canary and 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 current canary and 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:

  1. Is this something you'd want in Dokploy?
  2. Is rclone crypt an acceptable direction, or would you prefer public-key encryption from the start?
  3. Does this belong in the Apache-licensed core, or do you see it as an enterprise feature?
  4. #5696 changes the same rclone helpers. Should this wait for it and build on top?
  5. 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

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Dokploy/dokploy

All issues in Dokploy/dokploy

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.