Coolify is an open-source, self-hosted PaaS for deploying applications and databases. Its backup engine ships with first-class support for S3-compatible object storage, so PostgreSQL backups can flow straight to Vultr Object Storage, AWS S3, Wasabi, Backblaze B2, or MinIO without extra tooling. This guide deploys a PostgreSQL service in Coolify, schedules automated backups to an S3 bucket, simulates accidental data loss, and restores the database from the backup. By the end, you'll have a working backup-and-restore loop covering a self-hosted Postgres service in Coolify.
Prerequisite: A running Coolify install (2 CPU cores, 4 GB RAM minimum) and an S3-compatible bucket with access key and secret key.
Deploy a PostgreSQL Service in Coolify
- Open the Coolify dashboard at
http://SERVER_IP:8000. -
Projects → Add — name the project (e.g.
Pg Backup) and continue. - Add New Resource → Databases → PostgreSQL (standalone — not Supabase or pgVector variants).
- Click Start to deploy.
Insert Sample Data
1. Connect to the running database from the service's terminal in the Coolify UI:
$ psql -U postgres
2. Create a table and insert a couple of rows:
postgres=# CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100),
email VARCHAR(100)
);
postgres=# INSERT INTO users (name, email) VALUES ('John Doe', 'john@example.com');
postgres=# INSERT INTO users (name, email) VALUES ('Jane Smith', 'jane@example.com');
postgres=# SELECT * FROM users;
id | name | email
----+------------+------------------
1 | John Doe | john@example.com
2 | Jane Smith | jane@example.com
(2 rows)
Register S3-Compatible Storage in Coolify
- Create a bucket in your S3 provider (e.g.
pg-backups). Capture the bucket name, endpoint URL, access key, and secret key. - In Coolify: S3 Storages → Add:
-
Name:
Backup Storage -
Endpoint: provider URL — e.g.
ewr1.vultrobjects.com,s3.us-east-1.amazonaws.com, ors3.wasabisys.com -
Bucket:
pg-backups -
Region: e.g.
us-east-1 - Access Key / Secret Key: S3 credentials
-
Name:
- Click Validate Connection & Continue.
Enable Scheduled Backups
- Open the PostgreSQL resource dashboard → Backup tab.
-
Add a backup schedule:
-
Frequency:
*/1 * * * *for a one-minute test cadence (drop to daily before production) - Check Save to S3
- Save
-
Frequency:
- Open the schedule → Settings → enable Backup All Databases (otherwise only the default
postgresdatabase gets dumped). - Wait one minute for the first run. Confirm the dump (e.g.
pg-dump-all-1771242721.gz) lands in the S3 bucket.
Simulate Data Loss
$ psql -U postgres
postgres=# DROP TABLE users;
postgres=# SELECT * FROM users;
ERROR: relation "users" does not exist
LINE 1: SELECT * FROM users;
^
Restore from S3
- Open the S3 bucket, locate the backup file, and copy its object key (the path without the bucket name) — e.g.:
data/coolify/backups/databases/root-team-0/postgresql-database-k8480c44sogcswc0w4oskg4c-k8480c44sogcswc0w4oskg4c/pg-dump-all-1771242721.gz
- In the PostgreSQL resource → Configuration → Import Backup → Choose Restore Method → Select from S3.
- Pick the configured S3 storage (
Backup Storage), paste the object key into S3 File Path, and enable Backup includes all databases for multi-database dumps. - Click Check File — Coolify confirms it can read the file.
- Click Restore Database from S3, type the case-sensitive confirmation text, click Continue, and enter the Coolify password to confirm.
Verify the Restore
$ psql -U postgres
postgres=# SELECT * FROM users;
id | name | email
----+------------+------------------
1 | John Doe | john@example.com
2 | Jane Smith | jane@example.com
(2 rows)
The original rows are back — the backup captured the database state before the drop.
Next Steps
You now have working backups and restores for Coolify-managed PostgreSQL. From here you can:
- Lower the schedule frequency (
0 2 * * *for nightly) and set retention - Apply the same pattern to MySQL, MariaDB, MongoDB, and other Coolify-managed databases
- Mirror backups to a second S3 region for disaster recovery
For the full guide with additional tips, visit the original article on Vultr Docs.
Top comments (1)
It's always good to see more tools making database backups to object storage easier. In my experience, while setting up the backup process itself is often straightforward, the real engineering challenge and the source of most production incidents around data safety usually comes down to the restore. We had a close call early on where our
pg_dumpbackups were running perfectly, but when we tried to restore a staging environment from a recent dump, the process took far longer than our RTO dictated for production.That experience pushed us to look deeper into recovery strategies beyond simple logical dumps. For larger PostgreSQL instances, especially those with high write throughput, point-in-time recovery using WAL archiving (like what tools like
WAL-GorBarmanfacilitate) becomes a critical consideration. Whilepg_dumpis excellent for smaller datasets or schema migrations, the time taken to re-apply transactions from a base backup, rather than re-inserting rows from a logical dump, can drastically cut down recovery times. It’s a trade-off between complexity and recovery speed.Beyond the method, there are always the standard but crucial security layers: ensuring separate IAM roles or access keys for backup processes that are strictly limited to write-only access on the backup bucket, and ensuring server-side encryption is enabled on the S3 bucket itself. But perhaps the most overlooked step, even with robust tooling, is regularly testing the full restore process end-to-end to a distinct, non-production environment. That's where you catch issues with permissions, network throttling, or even just the raw time it takes, before you're in a real incident.