Dokploy Postgres Backups: What Its Job Does When a Dump Fails

backupsdevopsdockerpostgresqlself-hosting
Dokploy Postgres Backups: What Its Job Does When a Dump Fails

Dokploy v0.31.0 handles a failed Postgres dump only in part. A failed run removes its partial object if the key can delete, and a key that can't leaves a cut object that gzip -t and pg_restore --list accept. This comes from its source and a simulation, and I didn't install Dokploy.

Does Dokploy Handle a Failed Postgres Backup?

Partly, going by its source. I read the Dokploy v0.31.0 source and ran shell rendered from its backup template in a simulation. Its UI, job queue, notifications, and restore flow are untested. The simulation ran on MinIO in a lab under WSL2, with PostgreSQL 18.6 and rclone 1.75.2, never on a real provider.

PartPer its v0.31.0 source
Dumppg_dump -Fc --no-acl --no-owner through gzip into rclone rcat, with pipefail, so its dumps hold no grants or owners
Failed runRuns rclone deletefile with errors ignored, sends an error notification, exits 1, skips retention
Keep LatestCounts objects without checking them
Standalone databasesRun as Swarm services, so a filter on Compose labels finds nothing
The .sql.gz nameHolds a gzipped custom archive
Object key<appName>/<prefix>/<file>, so the app name comes before the prefix you typed

On the rendered shell, I ended the dump with pg_terminate_backend. A key that could delete removed the partial object, and a key that couldn't left this (trimmed):

##### v0.31.0, same failure, key that can list, read and write but NOT delete
exit status of the generated script: 1
   79751699 2026-11-05 14:48:08.909893471 2026-11-05T14-48-08-833Z.sql.gz
    gzip -t exit 0
    gunzip | pg_restore --list exit 0
    gunzip | pg_restore -f /dev/null exit 1 pg_restore: error: could not read from input file: end of file

The object passed gzip -t and pg_restore --list, and only the full read rejected it. My comparison of dump checks has more cases.

In the simulation, Keep Latest kept a truncated object over a good one. That object came from the older v0.29.14 template, which has no delete step, and I didn't repeat this with an object left by v0.31.0.

Under an R2 bucket lock, I'd expect a failed Dokploy run to leave its partial object, because the delete would be refused. That is an inference from Dokploy's source and Cloudflare's docs, and nobody ran it.

How Do I Check a Dokploy .sql.gz Backup?

These commands assume the offsite rclone remote and RCLONE_CONFIG from my off-site backups guide, with the remote pointed at your Dokploy S3 destination. Replace shop-backups with its bucket and <CHANGE-DOKPLOY-PREFIX> with the database's app name, followed by the job's prefix if it has one, because per the v0.31.0 source a standalone database's key is <appName>/<prefix>/<file>. <CHANGE-APP-NAME> is that same app name, which is the database's Swarm service name, and the docker ps line in that guide shows it in column 4. You also need jq. psql refused an object I made with Dokploy's pipeline, so check a .sql.gz this way:

prefix=offsite:shop-backups/<CHANGE-DOKPLOY-PREFIX>
pg=$(docker ps -q --filter label=com.docker.swarm.service.name=<CHANGE-APP-NAME>)
newest=$(rclone lsjson --files-only --use-server-modtime "$prefix" | jq -r 'sort_by(.ModTime) | last | .Path')
rclone cat "$prefix/$newest" | gunzip | docker exec -i "$pg" pg_restore -f /dev/null; echo "${PIPESTATUS[*]}"
rclone cat "$prefix/$newest" | gunzip | docker exec -i "$pg" pg_restore --list | grep -c ' TABLE DATA '

The output was 0 0 0 and 3. If you keep Dokploy's job, I'd run those two checks against its newest object on a schedule, because a failed run can leave a partial object behind. To restore one, gunzip it first and follow my restore drill, which expects a custom-format archive.

If you use the pg-backup script in my off-site backups guide instead, its default Compose filter finds nothing on a standalone database, so its filter line becomes this, which I tested only on a plain Swarm service:

pg_filters=(--filter label=com.docker.swarm.service.name=<CHANGE-APP-NAME>)

Summary

Per its v0.31.0 source, a failed Dokploy run deletes its object only if the key can, and Keep Latest counts objects without checking them. With a key that couldn't delete, the rendered shell left a cut object that gzip -t and pg_restore --list accepted, so run the two checks above against the newest object.

All of this comes from the source and a simulation on MinIO, and I didn't install Dokploy. Run a failed backup on your real server and provider before you count on it.

My off-site backups guide has a script that checks a dump before it uploads, and my self-hosting course sets up database backups to storage outside the server.

Thanks for reading.

And stay awesome!


Frequently Asked Questions

What happens when a Dokploy Postgres backup fails?

Per its v0.31.0 source, it runs rclone deletefile with errors ignored, sends an error notification, exits 1, and skips retention. On rendered shell, a key that could not delete left the partial object. I did not install Dokploy.

Why does psql refuse a Dokploy .sql.gz backup?

Per the v0.31.0 source, the .sql.gz name holds a gzipped custom archive. psql refused an object I made with that pipeline, so read it with gunzip and pg_restore. Dokploy did not make that object, and I did not run its restore flow.

Does Dokploy Keep Latest check the backups it keeps?

Per its source, it counts objects without checking them. In a simulation, Keep Latest kept a truncated object from the older v0.29.14 template over a good one, and I did not repeat this with an object left by v0.31.0.

Browse all Self-Hosting guides →
Loading comments...

Whenever you're ready, there are 5 ways I can help you:

  1. Pragmatic Self-Hosting: Learn to deploy and run your apps on a VPS with Dokploy and Tailscale. Keep administration private, automate releases, and practice restoring backups, with source code and a runbook you can reuse.
  2. Pragmatic Clean Architecture: Join 5,000+ students in this comprehensive course that will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture.
  3. Modular Monolith Architecture: Join 2,800+ engineers in this in-depth course that will transform the way you build modern systems. You will learn the best practices for applying the Modular Monolith architecture in a real-world scenario.
  4. Pragmatic REST APIs: Join 1,900+ students in this course that will teach you how to build production-ready REST APIs using the latest ASP.NET Core features and best practices. It includes a fully functional UI application that we'll integrate with the REST API.
  5. Patreon Community: Join a community of 5,000+ engineers and software architects. You will also unlock access to the source code I use in my YouTube videos, early access to future videos, and exclusive discounts for my courses.

The .NET Weekly

One practical .NET tip, every Saturday.

Join 66,000+ engineers who read it. Free, and you can unsubscribe any time.