π Production-Ready Multi-Purpose Disaster Recovery with Oracle Cloud Free Tier
Automated backups β’ Databases & Files β’ Encryption β’ Monitoring β’ Zero-cost infrastructure
Features β’ Quick Start β’ Documentation β’ Contributing
Built with β€οΈ using Go, Terraform, Oracle Cloud, and Prometheus
Cloud DR Orchestrator is a production-grade disaster recovery solution for databases and file systems, leveraging Oracle Cloud's generous Free Tier (20GB storage, 50k API calls/month). Perfect for backing up:
- ποΈ PostgreSQL databases - Full dumps with compression
- π Application configs - Nginx, Apache, app settings
- π§ System files - SSL certificates, SSH keys, scripts
- π User data - Documents, logs, any files/directories
- π MySQL databases (coming soon)
- π° $0/month - Runs entirely on Oracle Cloud Free Tier
- π― Multi-purpose - Databases, files, configs - all in one tool
- π AES-256-GCM encryption for data at rest
- π Prometheus metrics + Grafana dashboards included
- π€ Automated scheduling with Cronify integration
- ποΈ Infrastructure as Code - Full Terraform setup
- π― Production tested - Used in real-world applications
|
|
|
|
|
|
|
Before you begin, ensure you have:
- β Go 1.21 or higher
- β
PostgreSQL with
pg_dumpandpg_restore - β Oracle Cloud Free Tier account
- β
OCI credentials in
~/.oci/config - β (Optional) Cronify for automated schedules
Option 1: Build from source
git clone https://github.com/Kobeep/cloud-dr-orchestrator.git
cd cloud-dr-orchestrator
go build -o orchestrator ./cmd/orchestrator
sudo mv orchestrator /usr/local/bin/Option 2: Go install
go install github.com/Kobeep/cloud-dr-orchestrator/cmd/orchestrator@latestOption 3: Download binary (coming soon)
# Linux
wget https://github.com/Kobeep/cloud-dr-orchestrator/releases/latest/download/orchestrator-linux-amd64
chmod +x orchestrator-linux-amd64
sudo mv orchestrator-linux-amd64 /usr/local/bin/orchestratorDeploy Oracle Cloud infrastructure with Terraform:
cd terraform
terraform init
terraform plan
terraform applyThis creates:
- Object Storage bucket (20GB Free Tier)
- IAM policies
- Compartment structure
- API keys
PostgreSQL Database Backup:
# Create database backup
orchestrator backup \
--type postgres \
--name prod-db \
--db-name myapp \
--db-host localhost \
--db-user postgres \
--db-password secret
# With encryption
orchestrator backup \
--type postgres \
--name prod-db \
--db-name myapp \
--encryptFile & Directory Backup:
# Backup nginx configs
orchestrator backup \
--type files \
--name nginx-configs \
--source /etc/nginx \
--source /etc/ssl/nginx
# Backup with exclusions
orchestrator backup \
--type files \
--name app-data \
--source /var/www/myapp \
--exclude "*.log" \
--exclude "tmp/*" \
--exclude "cache/*"
# Backup multiple directories
orchestrator backup \
--type files \
--name system-configs \
--source /etc/systemd \
--source /etc/cron.d \
--source ~/.ssh \
--encryptUpload to Oracle Cloud:
orchestrator upload \
--file backup-20251209-092658.tar.gz \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.compartment.oc1..xxx3. List backups in cloud:
orchestrator list \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.compartment.oc1..xxx \
--year 2025 --month 124. Download backup from cloud:
orchestrator download \
--object backups/2025/12/backup-20251209-092658.tar.gz \
--output ./restored-backup.tar.gz \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.compartment.oc1..xxx5. Restore from local backup:
orchestrator restore \
--file backup-20251209-092658.tar.gz \
--db-name mydb \
--db-host localhost \
--db-user postgres \
--db-password secretEncrypt your backups before uploading to Oracle Cloud for maximum security! π
# Generate a secure 256-bit key
orchestrator keygen
# Output:
# π Generated 256-bit encryption key:
# s0m3R4nd0mB4s364Enc0d3dK3y==# Save to environment variable
export BACKUP_ENCRYPTION_KEY="your-key-here"
# Or save to config file
echo "BACKUP_ENCRYPTION_KEY=your-key-here" > ~/.backup-encryption.env
export $(cat ~/.backup-encryption.env | xargs)# Backup with encryption
orchestrator backup \
--name prod-db \
--db-name myapp \
--db-host localhost \
--db-user postgres \
--db-password secret \
--encrypt
# Output: backup-20251209-104235.tar.gz.encrypted# Automatic decryption (detects .encrypted extension)
orchestrator restore \
--file backup-20251209-104235.tar.gz.encrypted \
--db-name myapp \
--db-host localhost \
--db-user postgres \
--db-password secret
# Manual decryption (if needed)
orchestrator restore \
--file backup.tar.gz \
--decrypt \
--decryption-key "$BACKUP_ENCRYPTION_KEY" \
--db-name myapp ...- Algorithm: AES-256-GCM (industry standard)
- Key Derivation: PBKDF2 with 100,000 iterations
- Security: Each file has unique salt and nonce
- Authentication: GCM mode provides built-in integrity check
- File Format:
.tar.gz.encrypted
- Never lose your encryption key! Lost key = lost backups
- Store keys securely (use secret managers in production)
- Never commit keys to version control
- Backup your keys in a secure location
- Rotate keys periodically
6. Restore directly from cloud:
orchestrator restore \
--from-cloud backups/2025/12/backup-20251209-092658.tar.gz \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.compartment.oc1..xxx \
--db-name mydb \
--db-host localhost \
--db-user postgres \
--db-password secretSchedule automated backups using Cronify integration! π
Install Cronify (YAML-driven cron job manager):
git clone https://github.com/Kobeep/Cronify.git
cd Cronify
sudo ./install.sh# Create example backup-schedule.yaml
orchestrator schedule init
# Or specify custom output file
orchestrator schedule init --output my-schedule.yamljobs:
- name: daily-backup
schedule: "0 0 * * *" # Every day at midnight
command: /usr/local/bin/orchestrator backup --name prod-db --db-name myapp --encrypt
env:
BACKUP_ENCRYPTION_KEY: "your-key-here"
PATH: "/usr/local/bin:/usr/bin:/bin"
- name: weekly-backup
schedule: "0 3 * * 0" # Every Sunday at 3 AM
command: /usr/local/bin/orchestrator backup --name prod-db-weekly --encrypt
- name: monthly-backup
schedule: "0 2 1 * *" # 1st of month at 2 AM
command: /usr/local/bin/orchestrator backup --name prod-db-monthly --encrypt# Check cron expressions and commands
orchestrator schedule validate --file backup-schedule.yaml
# Simulate next 5 run times
orchestrator schedule validate --file backup-schedule.yaml --simulate# Preview without deploying
orchestrator schedule deploy --file backup-schedule.yaml --dry-run
# Deploy to crontab
orchestrator schedule deploy --file backup-schedule.yaml# View current crontab
crontab -lThe tool reads credentials from ~/.oci/config:
[DEFAULT]
user=ocid1.user.oc1..xxx
fingerprint=aa:bb:cc:dd:ee:ff
tenancy=ocid1.tenancy.oc1..xxx
region=eu-frankfurt-1
key_file=/home/user/.oci/oci_api_key.pemYou can override the config file path and profile:
orchestrator upload --oci-config /path/to/config --oci-profile MYPROFILE ...Here's a complete disaster recovery workflow:
# 1. Create a PostgreSQL backup (compressed)
orchestrator backup \
--name production-db \
--db-name myapp \
--db-host localhost \
--db-user postgres \
--db-password secretpass
# Output: backup-20251209-104235.tar.gz
# 2. Upload to Oracle Cloud (automatically organized in backups/2025/12/)
orchestrator upload \
--file backup-20251209-104235.tar.gz \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.tenancy.oc1..xxx
# β Upload successful in 90ms
# 3. List all backups from December 2025
orchestrator list \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.tenancy.oc1..xxx \
--year 2025 --month 12
# Found 1 backup(s)
# 4. Download when disaster strikes
orchestrator download \
--object backups/2025/12/backup-20251209-104235.tar.gz \
--output ./restore.tar.gz \
--bucket cloud-dr-orchestrator-dr-backups \
--compartment ocid1.tenancy.oc1..xxx
# β Download successful in 81ms
# 5. Extract and restore
tar xzf restore.tar.gz
psql myapp < backup-20251209-104235.sqlSet up automated backups with systemd (Linux) or cron:
# Run the setup script
sudo ./scripts/setup-automation.sh
# Edit configuration
sudo nano /etc/cloud-dr-orchestrator/backup.env
# Start the timer
sudo systemctl start orchestrator-backup.timer
sudo systemctl enable orchestrator-backup.timer
# Check status
systemctl status orchestrator-backup.timer
journalctl -u orchestrator-backup.serviceThe timer runs daily at 2 AM by default. Edit /etc/systemd/system/orchestrator-backup.timer to customize.
# Run setup script (creates wrapper)
sudo ./scripts/setup-automation.sh
# Edit configuration
sudo nano /etc/cloud-dr-orchestrator/backup.env
# Add to crontab
crontab -e
# Daily at 2 AM
0 2 * * * /usr/local/bin/orchestrator-backup-cron.sh
# Every 6 hours
0 */6 * * * /usr/local/bin/orchestrator-backup-cron.sh
# Weekly on Sunday at 3 AM
0 3 * * 0 /usr/local/bin/orchestrator-backup-cron.shFree Tier Note: With 20GB storage and automated daily backups, keep ~30 days of backups before rotation needed.
Monitor your backups with Grafana Alloy and Grafana Cloud (free tier)! π
# Start metrics server
orchestrator metrics --port 9090
# Available endpoints:
# - http://localhost:9090/metrics (Prometheus metrics)
# - http://localhost:9090/health (Health check JSON)The orchestrator exposes comprehensive metrics:
Backup Metrics:
orchestrator_backup_duration_seconds- Backup operation time (histogram)orchestrator_backup_size_bytes- Backup file size (histogram)orchestrator_backup_success_total- Successful backup counterorchestrator_backup_failure_total- Failed backup counter (with reason labels)
Cloud Operations:
orchestrator_upload_duration_seconds- Upload time to Oracle Cloudorchestrator_upload_success_total/_failure_total- Upload countersorchestrator_download_duration_seconds- Download time from Oracle Cloudorchestrator_download_success_total/_failure_total- Download counters
Restore Operations:
orchestrator_restore_duration_seconds- Restore operation timeorchestrator_restore_success_total/_failure_total- Restore counters
-
Sign up: https://grafana.com/auth/sign-up/create-user
- Free tier: 10k metrics, 50GB logs, 14 days retention
- Our app uses ~50 metrics series (well within limit!)
-
Install Grafana Alloy:
# Linux (Debian/Ubuntu) wget -q -O - https://apt.grafana.com/gpg.key | gpg --dearmor | sudo tee /usr/share/keyrings/grafana.gpg echo "deb [signed-by=/usr/share/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list sudo apt update && sudo apt install alloy # macOS brew install grafana/grafana/alloy
-
Configure:
# Copy config templates cp configs/grafana-cloud.env.example configs/grafana-cloud.env cp configs/alloy-config.alloy /etc/alloy/config.alloy # Edit with your Grafana Cloud credentials nano configs/grafana-cloud.env
-
Start Alloy:
export $(cat configs/grafana-cloud.env | xargs) sudo alloy run configs/alloy-config.alloy
-
Import Dashboard:
- Go to Grafana Cloud β Dashboards β Import
- Upload
configs/grafana-dashboard.json - Done! π
Your dashboard includes:
- β Overall health status indicator
- π Backup success rate (24h)
- β±οΈ Backup duration trends (p95, median)
- π¦ Backup size distribution over time
- βοΈ Upload/download performance
- π΄ Recent failures table with error reasons
Automatic alerts for:
- BackupFailed - Immediate alert on backup failure
- BackupNotRunRecently - No backup in 25 hours
- BackupTakingTooLong - Duration > 30 minutes
- UploadFailed - Cloud upload errors
- OrchestratorDown - Service unavailable
Configure notifications via:
- Slack
- PagerDuty
- Webhook
π Full setup guide: docs/MONITORING.md
οΏ½ Active Development - Core features implemented and tested!
-
β Issue #2: Terraform infrastructure for Oracle Cloud Object Storage
- Bucket with versioning enabled
- Free Tier configuration (20GB storage)
-
β Issue #3: PostgreSQL backup with compression
pg_dumpintegration- tar.gz compression (40-50% size reduction)
- Backup metadata and statistics
-
β Issue #4: Oracle Cloud Object Storage integration
- Upload backups to OCI (90ms average)
- Download backups from OCI (81ms average)
- List backups with filtering by date
- Automatic folder organization (backups/YYYY/MM/)
- Tested with real OCI bucket β
-
β Issue #7: Restore functionality
- Restore from local .tar.gz backups
- Download from cloud and restore
- Confirmation prompt before restore
- Support for target database override
-
β Issue #8: Scheduling and automation
- systemd service and timer
- Cron wrapper script
- Automated installation script
- Works on Linux and macOS
-
β Issue #9: Monitoring and observability
- Prometheus metrics endpoint
- Grafana Alloy configuration
- Grafana Cloud integration (free tier)
- Pre-built dashboard with 11 panels
- Comprehensive alerting rules
- Health check endpoint
-
β Issue #10: Backup encryption
- AES-256-GCM encryption
- PBKDF2 key derivation (100k iterations)
- Key generation command
- Environment variable support
-
β Issue #13: Cronify integration
- YAML-based schedule management
- Automated cron deployment
- Schedule validation and simulation
We welcome contributions! Here's how you can help:
π‘ Ways to Contribute
- π Report bugs - Open an issue with reproduction steps
- β¨ Suggest features - Share your ideas for improvements
- π Improve docs - Help make documentation clearer
- π§ Submit PRs - Fix bugs or implement features
- β Star the repo - Show your support!
π§ Development Setup
# Clone repository
git clone https://github.com/Kobeep/cloud-dr-orchestrator.git
cd cloud-dr-orchestrator
# Install dependencies
go mod download
# Run tests
go test ./...
# Build
go build -o orchestrator ./cmd/orchestrator
# Run linter
golangci-lint runBe respectful, inclusive, and collaborative. See CODE_OF_CONDUCT.md for details.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Copyright 2024-2025 Jakub Pospieszny
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
![]() Oracle Cloud Free Tier Infrastructure |
![]() Terraform Infrastructure as Code |
Prometheus Metrics & Monitoring |
Grafana Dashboards & Alerts |
- Cronify - YAML-based cron management
- PostgreSQL Community - Excellent database and tools
- Go Community - Amazing language and ecosystem
β Star this repo if you find it useful! β
Made with β€οΈ by Jakub Pospieszny
Report Bug β’ Request Feature β’ Documentation

