Backups
Configure backup destinations, create schedules, and manage retention policies with GFS tiering.
oCore provides a comprehensive backup system with support for multiple storage destinations, scheduled backups with Grandfather-Father-Son (GFS) retention, durable WAL archiving, and one-click logical backup restore. WAL segments are retained for durability and future recovery support, but point-in-time restore is not currently available because full backups are logical pg_dump archives rather than physical PostgreSQL base backups. This page covers configuring backup destinations, creating manual and scheduled backups, restoring from backups, and managing retention policies.
Backup Management
View and manage backups for your environment.
Backup Destinations
Before creating backups, configure at least one storage destination where backup files will be stored.
Supported Destination Types
| Type | Description |
|---|---|
s3 | Amazon S3 bucket |
s3_compatible | S3-compatible storage (MinIO, Wasabi, Backblaze B2, etc.) |
sftp | SFTP server |
local | Local filesystem on the server |
onedrive | Microsoft OneDrive |
gdrive | Google Drive |
Creating a Destination
Navigate to Settings > Backup Destinations in your organization settings.
Click Add Destination and select the type.
Provide the required configuration for your chosen type. For example, S3 requires:
- Bucket name
- Region
- Access key ID
- Secret access key
- Optional: custom endpoint, path prefix
Click Test Connection to verify the destination is reachable and writable.
Click Save to create the destination.
curl -X POST https://ocore.example.com/api/backup-destinations \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Production S3 Bucket",
"destinationType": "s3",
"config": {
"bucket": "ocore-backups",
"region": "eu-west-1",
"accessKeyId": "AKIA...",
"secretAccessKey": "..."
}
}'ocore backup-destination create \
--name "Production S3 Bucket" \
--type s3 \
--bucket ocore-backups \
--region eu-west-1Encrypted Storage
Destination credentials (access keys, passwords) are encrypted at rest using AES-256 before being stored in the database. The plaintext credentials are never persisted.
Testing a Destination
Verify connectivity and write permissions:
curl -X POST https://ocore.example.com/api/backup-destinations/{destId}/test \
-H "Authorization: Bearer $TOKEN"Listing Destinations
curl https://ocore.example.com/api/backup-destinations \
-H "Authorization: Bearer $TOKEN"The response includes the isVerified flag and lastTestedAt timestamp for each destination.
Creating Manual Backups
Create an on-demand backup for any environment:
curl -X POST https://ocore.example.com/api/environments/{envId}/backups \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"type": "full"}'ocore backup create --environment ENV_UUID --type fullBackup Types
| Type | Includes | Use Case |
|---|---|---|
db | Database dump only | Quick backups, database-only restores |
full | Database + filestore + config | Complete instance state, disaster recovery |
Each backup records:
- Status --
pending,in_progress,completed,failed - Size -- Total backup size in bytes
- Checksums -- SHA-256 checksums for database, filestore, and config components
- GFS Tiers -- Which retention tiers this backup belongs to
- Remote Paths -- Where the backup is stored per destination
- Timestamps -- Start time, completion time, creation time
Setting Up Scheduled Backups
Configure automatic backups on a recurring schedule with GFS (Grandfather-Father-Son) retention.
Creating a Schedule
curl -X PUT https://ocore.example.com/api/environments/{envId}/backup-schedule \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"dbFrequency": "6h",
"fullFrequency": "daily",
"retainHourly": 24,
"retainDaily": 7,
"retainWeekly": 4,
"retainMonthly": 12,
"walEnabled": true,
"walRetentionDays": 7,
"destinationIds": ["DEST_UUID_1", "DEST_UUID_2"]
}'ocore backup schedule set \
--environment ENV_UUID \
--db-frequency 6h \
--full-frequency daily \
--retain-hourly 24 \
--retain-daily 7 \
--destinations DEST_UUID_1,DEST_UUID_2Schedule Options
| Field | Values | Description |
|---|---|---|
dbFrequency | hourly, 6h, 12h, daily | How often to take database-only backups |
fullFrequency | daily, weekly | How often to take full backups |
retainHourly | Integer (>= 0) | Number of hourly backups to keep |
retainDaily | Integer (>= 0) | Number of daily backups to keep |
retainWeekly | Integer (>= 0) | Number of weekly backups to keep |
retainMonthly | Integer (>= 0) | Number of monthly backups to keep |
walEnabled | Boolean | Enable durable WAL archiving. This does not enable PITR restore for logical full backups. |
walRetentionDays | Integer (>= 1) | Days to retain archived WAL segments |
destinationIds | Array of UUIDs | Where to store backups |
Viewing Schedule
curl https://ocore.example.com/api/environments/{envId}/backup-schedule \
-H "Authorization: Bearer $TOKEN"The response includes nextDbBackupAt and nextFullBackupAt timestamps showing when the next backups will run.
Restoring from Backups
Restore a backup to the same environment or a different existing environment in the same project. Restore-to-new orchestration and point-in-time restore are not currently available. See the Databases page for additional database restore guidance.
Restore Overwrites Data
Restoring to the same or other target type overwrites the existing database and filestore. The restore process creates a pre-restore snapshot automatically for safety.
Cross-Environment Restore
oCore supports restoring backups across environments within the same project. This is useful for:
- Refreshing staging from a production backup
- Creating test environments from known-good data
- Disaster recovery to a different environment on a different server
The restore dialog supports two target types:
| Target | Description | Use Case |
|---|---|---|
same | Restore to the same environment | Rollback to a known state |
other | Restore to a different existing environment in the same project | Refresh staging from production |
targetType: "new" is rejected until create-and-restore orchestration is implemented.
When restoring to a different environment:
- The dialog lists all environments in the project
- You can restore both backups and snapshots
- The source environment type is shown for reference
- A pre-restore snapshot is created on the target for safety
Post-Restore Neutralization
When restoring a production backup to a staging or development environment, oCore runs neutralization before marking the target ready. If neutralization cannot be verified, the restore is reported as partial and the target remains degraded for operator review.
Point-in-Time Recovery Availability
PITR restore is currently unavailable
Current full backups contain logical pg_dump/pg_restore artifacts. They do not record the authoritative physical base-backup checkpoint/LSN, PostgreSQL system identifier, and timeline needed to bind archived WAL to a restore base. WAL archiving remains durable storage, but it must not be treated as proof that a timestamp is recoverable.
The coverage endpoint reports this state explicitly:
{
"available": false,
"reasonCode": "physical_base_metadata_unavailable",
"message": "Point-in-time restore is unavailable because current full backups are logical pg_dump archives and do not include authoritative physical base-backup checkpoint metadata required to bind WAL segments.",
"baseBackups": [],
"walRanges": [],
"gaps": []
}The restore dialog does not offer an interactive PITR selection while coverage is unavailable. API restore requests that include a non-null pitrTimestamp are rejected synchronously with HTTP 409 and error code PITR_UNAVAILABLE; no restore log, reservation, operation lock, or background job is created.
Backup Retention Policies
GFS Tiering
oCore implements Grandfather-Father-Son retention to balance storage costs with recovery options:
| Tier | Description | Typical Retention |
|---|---|---|
| Hourly | Most recent backups for quick recovery | 24 backups |
| Daily | One backup per day for short-term history | 7 backups |
| Weekly | One backup per week for medium-term history | 4 backups |
| Monthly | One backup per month for long-term archival | 12 backups |
When a scheduled backup runs, oCore automatically assigns it to the appropriate GFS tiers based on timing. Backups outside retention windows are automatically deleted from all destinations.
Recommended Retention Policies
| Environment | DB Frequency | Full Frequency | Hourly | Daily | Weekly | Monthly |
|---|---|---|---|---|---|---|
| Production | 6h | daily | 24 | 7 | 4 | 12 |
| Staging | daily | weekly | 0 | 7 | 2 | 0 |
| Development | daily | weekly | 0 | 3 | 0 | 0 |
Backup Alerts
oCore generates alerts for backup-related events:
- Backup failed -- A scheduled or manual backup did not complete
- Destination unreachable -- A backup destination failed connectivity test
- Retention warning -- Backup retention is running low
View alerts:
curl https://ocore.example.com/api/backup-alerts \
-H "Authorization: Bearer $TOKEN"Each alert includes:
alertType-- The type of alertseverity--info,warning,error,criticalmessage-- Human-readable descriptionisRead-- Whether the alert has been acknowledged
Multi-Destination Backups
You can configure a schedule to write backups to multiple destinations simultaneously. This provides redundancy -- if one destination fails, backups are still available from others.
{
"destinationIds": ["s3-primary-uuid", "sftp-secondary-uuid"]
}The backup records remotePaths showing the storage location per destination.
Required Permissions
Backup management requires manage:environments permission. Viewing backups requires view:environments. Backup destination management requires manage:org_settings.
Troubleshooting
Backup fails with "destination unreachable"
- Test the backup destination to verify connectivity
- Check that the destination credentials are still valid (keys not rotated)
- For S3 destinations, bucket versioning must be Enabled (not Suspended). The IAM policy must allow bucket-versioning inspection, current-object listing, version listing, writes, exact-version reads, and exact-version deletion:
s3:GetBucketVersioning,s3:ListBucket,s3:ListBucketVersions,s3:PutObject,s3:GetObject,s3:GetObjectVersion, ands3:DeleteObjectVersion. Test Connection explicitly verifiesListBucketVersions; without it, browser/orphan scans cannot enumerate historical versions safely. - For SFTP destinations, verify the SSH key or password is correct
Scheduled backups not running
- Check that the schedule is
enabled: true - Verify at least one destination is configured
- Check the backup alert list for error details
- Verify the oCore job queue is running (River workers)
Backup size growing unexpectedly
- Check the filestore for large uploads or attachments
- Review database growth with
pg_database_size() - Consider more frequent full backups with shorter retention to manage storage
Restore hangs or takes very long
- Large databases take longer to restore -- check the restore progress endpoint
- Verify sufficient disk space on the target server
- For cross-server restores, network bandwidth is the bottleneck
- Check the operation logs for detailed step timing
WAL archiving filling up disk
- Reduce
walRetentionDaysto clean up older WAL segments - Ensure WAL segments are being uploaded to the backup destination
- Check that the backup destination has sufficient storage