Back Up Dokploy Postgres to S3 Automatically
17 Oct 2025Dokploy ships with database backups built in. Most people never turn them on until the day they need them.
Here is the five-minute setup.
1. Create the destination bucket
Any S3-compatible bucket works — AWS S3, Cloudflare R2, Backblaze B2, or your own MinIO. Create a bucket and an access key scoped to just that bucket.
You need four values:
- Endpoint URL
- Region
- Access key ID
- Secret access key
2. Add the destination in Dokploy
Go to Settings → S3 Destinations → Add Destination. Paste the four values, give it a name, and hit Test Connection. If the test fails, it is almost always the endpoint URL — R2 and B2 use a different format from AWS.
3. Attach a backup schedule to the database
Open your Postgres service, go to the Backups tab, and add a backup:
- Destination: the one you just created
- Schedule: a cron expression, e.g.
0 3 * * *for 3am daily - Database: the database name inside the Postgres instance
- Prefix: something like
myapp/postgres/so backups from different apps stay separate
Save it, then click Run Manually once. Do not wait for the schedule to prove it works.
4. Verify the restore, not the backup
This is the step everyone skips. Download the dump and restore it locally:
aws s3 cp s3://your-bucket/myapp/postgres/backup-latest.sql.gz . \
--endpoint-url https://your-endpoint
gunzip backup-latest.sql.gz
psql -h localhost -U postgres -d restore_test -f backup-latest.sql
If that runs clean, you have a backup. If it errors, you had a file, not a backup.
5. Set a retention rule
Dokploy will happily upload a dump every day forever. Add a lifecycle rule on the bucket to delete objects older than 30 days, and to move anything older than 7 days to a cheaper storage class.
On R2 there are no egress fees, so restores cost nothing. On S3 they do — factor that in before you pick a region far from your server.
A note on timing
Run backups when traffic is lowest, and check how long the dump takes. pg_dump holds a consistent snapshot, which is fine, but on a large database it can push disk I/O hard enough to slow queries. If your dump takes more than a couple of minutes, consider a read replica or move to physical backups with pgBackRest.
For most small apps, a nightly logical dump to object storage is enough. The failure mode you are protecting against is not usually hardware — it is a bad migration or a DELETE without a WHERE.