Add Docker-based cross-platform solution (v1.2.0)
Major addition: Full Docker implementation for Windows, macOS, and Linux support New Features: - Docker container with PBS client in Debian environment - Platform-specific docker-compose files (linux/windows/macos) - Daemon mode with internal cron scheduler - One-shot backup mode for manual execution - Optional REST API server for remote management - Health monitoring and status endpoints - Automatic encryption key generation and management Docker Structure: - docker/Dockerfile - Container build definition - docker/scripts/ - Entrypoint, backup, healthcheck, and API scripts - docker/build.sh - Build script for Docker image - docker/deploy.sh - Interactive deployment script - docker/docker-compose-*.yml - Platform-specific configurations Documentation: - docker/README-DOCKER.md - Complete Docker documentation - docker/QUICKSTART-DOCKER.md - Quick start guide - docker/DOCKER-SOLUTION-SUMMARY.md - Architecture overview - BACKUP-TYPES-GUIDE.md - File vs block device backup guide Updated: - README.md - Added cross-platform support section and platform matrix - CHANGELOG.md - Documented all Docker features This enables PBSClientTool to backup Windows and Mac systems via Docker, while maintaining native Linux performance for full disk images. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
e5a4b7abf4
commit
fbe81d28ae
16 changed files with 2503 additions and 1 deletions
404
BACKUP-TYPES-GUIDE.md
Normal file
404
BACKUP-TYPES-GUIDE.md
Normal file
|
|
@ -0,0 +1,404 @@
|
||||||
|
# Backup Types and VM Conversion Guide
|
||||||
|
|
||||||
|
## Three Backup Strategies
|
||||||
|
|
||||||
|
When running the installer, you'll be asked to choose between three backup types:
|
||||||
|
|
||||||
|
### 1. File-level Only (.pxar)
|
||||||
|
**What it does:** Backs up files and directories as archives
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Very fast backups (uses metadata change detection)
|
||||||
|
- Excellent deduplication (20-40x typical)
|
||||||
|
- Small backup size
|
||||||
|
- Selective file restoration
|
||||||
|
- Perfect for daily backups
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Cannot be directly booted as a VM
|
||||||
|
- Requires manual steps to restore to bare metal
|
||||||
|
- Need to reinstall bootloader after restore
|
||||||
|
|
||||||
|
**Best for:**
|
||||||
|
- File recovery
|
||||||
|
- Configuration backups
|
||||||
|
- User data protection
|
||||||
|
- Systems where you just need files, not full disaster recovery
|
||||||
|
|
||||||
|
**Example use case:** Backing up a development laptop where you mainly care about code and configs
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Block Device Only (.img)
|
||||||
|
**What it does:** Creates full disk/partition images
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- **Directly bootable as a VM** - just restore to VM disk and start
|
||||||
|
- Bare metal restore with dd
|
||||||
|
- Complete system snapshot (including bootloader, partitions, etc.)
|
||||||
|
- No post-restore configuration needed
|
||||||
|
- Perfect for disaster recovery
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- Much larger backups (backs up entire disk including empty space)
|
||||||
|
- Slower backup process
|
||||||
|
- Less deduplication
|
||||||
|
- More storage required on PBS
|
||||||
|
|
||||||
|
**Best for:**
|
||||||
|
- Disaster recovery
|
||||||
|
- Converting physical machines to VMs
|
||||||
|
- Hardware migration
|
||||||
|
- Systems you want to boot as VMs later
|
||||||
|
|
||||||
|
**Example use case:** Production laptop you want to be able to boot as a VM in Proxmox if hardware fails
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Both (Hybrid) - RECOMMENDED
|
||||||
|
**What it does:** Daily file-level backups + Weekly block device backups
|
||||||
|
|
||||||
|
**How it works:**
|
||||||
|
- File-level backup runs on your schedule (e.g., daily at 2 AM)
|
||||||
|
- Block device backup runs every **Sunday** regardless of your schedule
|
||||||
|
- Both stored in the same datastore
|
||||||
|
|
||||||
|
**Pros:**
|
||||||
|
- Best of both worlds
|
||||||
|
- Fast daily backups for file recovery
|
||||||
|
- Weekly bootable snapshots for disaster recovery
|
||||||
|
- Reasonable storage usage
|
||||||
|
- Maximum flexibility
|
||||||
|
|
||||||
|
**Cons:**
|
||||||
|
- More complex
|
||||||
|
- Requires more storage than file-only
|
||||||
|
- Block device backups take longer when they run
|
||||||
|
|
||||||
|
**Best for:**
|
||||||
|
- Production systems
|
||||||
|
- Critical laptops/workstations
|
||||||
|
- Any system where both file recovery AND disaster recovery matter
|
||||||
|
|
||||||
|
**Example use case:** Your main work laptop - daily backups protect recent work, weekly images let you boot as VM if laptop dies
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Storage Requirements Comparison
|
||||||
|
|
||||||
|
Example: 256GB laptop with 120GB used space
|
||||||
|
|
||||||
|
| Backup Type | First Backup | Subsequent Backups | Weekly Storage Growth |
|
||||||
|
|------------|--------------|-------------------|---------------------|
|
||||||
|
| File-level | ~120GB | ~1-5GB (changed files only) | ~7-35GB |
|
||||||
|
| Block device | ~256GB | ~256GB each time | ~256GB |
|
||||||
|
| Both (Hybrid) | ~376GB | ~1-5GB daily, +256GB Sunday | ~263-291GB |
|
||||||
|
|
||||||
|
**Note:** Deduplication dramatically reduces actual storage - PBS typically achieves 10-40x deduplication on file-level backups.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Converting to VMs
|
||||||
|
|
||||||
|
### File-level Backups → VM
|
||||||
|
**NOT RECOMMENDED** - Requires manual work:
|
||||||
|
|
||||||
|
1. Create new VM with blank disk
|
||||||
|
2. Install minimal OS in VM
|
||||||
|
3. Boot VM into rescue mode
|
||||||
|
4. Restore .pxar backup over the minimal install
|
||||||
|
5. Reinstall bootloader (grub-install)
|
||||||
|
6. Fix /etc/fstab for new disk UUIDs
|
||||||
|
7. Configure network for VM environment
|
||||||
|
8. Reboot and troubleshoot
|
||||||
|
|
||||||
|
**Complexity:** High
|
||||||
|
**Success rate:** ~60-70%
|
||||||
|
**Time:** 1-3 hours
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Block Device Backups → VM
|
||||||
|
**RECOMMENDED** - Almost automatic:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On Proxmox VE host (must have PBS client installed)
|
||||||
|
|
||||||
|
# 1. List available backups
|
||||||
|
proxmox-backup-client snapshot list
|
||||||
|
|
||||||
|
# 2. Create VM shell (via GUI or CLI)
|
||||||
|
qm create 999 --name "laptop-vm" --memory 4096 --cores 2
|
||||||
|
|
||||||
|
# 3. Create disk for VM (size >= original disk)
|
||||||
|
qm set 999 --scsi0 local-lvm:32
|
||||||
|
|
||||||
|
# 4. Find VM disk device
|
||||||
|
VM_DISK=$(lvdisplay | grep "vm-999-disk-0" | awk '{print $3}')
|
||||||
|
# Or typically: /dev/pve/vm-999-disk-0
|
||||||
|
|
||||||
|
# 5. Restore backup directly to VM disk
|
||||||
|
# Replace sda.img with your actual backup name (e.g., nvme0n1.img)
|
||||||
|
proxmox-backup-client restore \
|
||||||
|
host/your-laptop/2025-11-01T03:00:00Z \
|
||||||
|
sda.img \
|
||||||
|
"$VM_DISK"
|
||||||
|
|
||||||
|
# 6. Configure VM boot
|
||||||
|
qm set 999 --boot order=scsi0
|
||||||
|
|
||||||
|
# 7. Start VM
|
||||||
|
qm start 999
|
||||||
|
```
|
||||||
|
|
||||||
|
**Complexity:** Low
|
||||||
|
**Success rate:** ~95%+
|
||||||
|
**Time:** 10-30 minutes (mostly waiting for restore)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Post-VM-Conversion Tasks
|
||||||
|
|
||||||
|
After booting the restored laptop as a VM, you'll likely need to:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Fix network (VM uses virtio, laptop had different interface)
|
||||||
|
# Ubuntu/Debian:
|
||||||
|
sudo nano /etc/netplan/01-netcfg.yaml
|
||||||
|
# Change interface name to ens18 or whatever shows in 'ip a'
|
||||||
|
|
||||||
|
# Arch:
|
||||||
|
sudo nano /etc/systemd/network/20-wired.network
|
||||||
|
|
||||||
|
# 2. Install QEMU guest agent (highly recommended)
|
||||||
|
sudo apt install qemu-guest-agent # Ubuntu/Debian
|
||||||
|
sudo pacman -S qemu-guest-agent # Arch
|
||||||
|
sudo systemctl enable --now qemu-guest-agent
|
||||||
|
|
||||||
|
# 3. Remove laptop-specific packages (optional)
|
||||||
|
sudo apt remove laptop-mode-tools tlp # Power management
|
||||||
|
sudo pacman -Rs laptop-mode-tools
|
||||||
|
|
||||||
|
# 4. Update fstab if needed (usually not required)
|
||||||
|
# Only if you see errors about missing disks
|
||||||
|
|
||||||
|
# 5. Reboot to ensure everything works
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
**That's it!** Your laptop is now running as a VM.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bare Metal Restoration (New Laptop/Hardware)
|
||||||
|
|
||||||
|
### Scenario: Laptop died, bought new one with bigger SSD
|
||||||
|
|
||||||
|
**Using Block Device Backup:**
|
||||||
|
|
||||||
|
1. Boot new laptop from Ubuntu/Arch USB
|
||||||
|
2. Install PBS client on live system
|
||||||
|
3. Configure connection to your PBS
|
||||||
|
4. List backups and find latest
|
||||||
|
5. Restore directly to new disk:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# On live USB system
|
||||||
|
sudo apt install proxmox-backup-client # or yay -S on Arch
|
||||||
|
|
||||||
|
# Configure (temporary)
|
||||||
|
export PBS_REPOSITORY='user@pbs!token@192.168.1.181:8007:backups'
|
||||||
|
export PBS_PASSWORD='your-token-secret'
|
||||||
|
|
||||||
|
# List backups
|
||||||
|
proxmox-backup-client snapshot list
|
||||||
|
|
||||||
|
# Restore to new disk (replace /dev/nvme0n1 with your new disk)
|
||||||
|
proxmox-backup-client restore \
|
||||||
|
host/old-laptop/2025-11-01T03:00:00Z \
|
||||||
|
sda.img \
|
||||||
|
/dev/nvme0n1
|
||||||
|
|
||||||
|
# Reboot
|
||||||
|
sudo reboot
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Remove USB, boot from restored disk
|
||||||
|
7. System should boot normally with all your data
|
||||||
|
|
||||||
|
**If new disk is larger:** The restored partition will be original size. Expand it:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# After first boot from restored disk
|
||||||
|
|
||||||
|
# For ext4 filesystem
|
||||||
|
sudo growpart /dev/nvme0n1 1 # Expand partition
|
||||||
|
sudo resize2fs /dev/nvme0n1p1 # Expand filesystem
|
||||||
|
|
||||||
|
# For btrfs
|
||||||
|
sudo btrfs filesystem resize max /
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Which Should You Choose?
|
||||||
|
|
||||||
|
**Choose File-level only if:**
|
||||||
|
- Storage on PBS is very limited
|
||||||
|
- You only care about recovering files, not full system
|
||||||
|
- You're comfortable reinstalling OS if hardware fails
|
||||||
|
- Backup speed is critical
|
||||||
|
|
||||||
|
**Choose Block device only if:**
|
||||||
|
- You specifically want VM conversion capability
|
||||||
|
- Storage space is not a concern
|
||||||
|
- You rarely backup (weekly/monthly)
|
||||||
|
- System rarely changes
|
||||||
|
|
||||||
|
**Choose Both (Hybrid) if:**
|
||||||
|
- You want maximum protection
|
||||||
|
- PBS has decent storage (500GB+ free)
|
||||||
|
- System is important/production
|
||||||
|
- You want both fast recovery AND disaster recovery options
|
||||||
|
- **This is the recommended default**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Storage Planning
|
||||||
|
|
||||||
|
### For Hybrid Backups
|
||||||
|
|
||||||
|
Calculate required PBS storage:
|
||||||
|
|
||||||
|
```
|
||||||
|
Initial: (Disk Size) + (Used Space)
|
||||||
|
Weekly: + (Disk Size)
|
||||||
|
Monthly: 4 × (Disk Size) + ~(Used Space × 2)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Example:** 512GB laptop with 200GB used
|
||||||
|
|
||||||
|
```
|
||||||
|
Initial: 512GB + 200GB = 712GB
|
||||||
|
After 1 month: 512 + 200 + (4 × 512) + 400 = 2860GB ≈ 3TB
|
||||||
|
With dedup: ~1TB actual storage (typical 3:1 compression)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Recommendation:** PBS datastore with at least **3x your total disk size** for comfortable monthly retention with hybrid backups.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Your Backups
|
||||||
|
|
||||||
|
**CRITICAL:** Always test restores before you need them!
|
||||||
|
|
||||||
|
### Test File-level Restore
|
||||||
|
```bash
|
||||||
|
# Restore single file to verify
|
||||||
|
proxmox-backup-client restore \
|
||||||
|
host/laptop/2025-11-01T03:00:00Z \
|
||||||
|
root.pxar /tmp/test-restore \
|
||||||
|
--pattern 'etc/hostname'
|
||||||
|
|
||||||
|
cat /tmp/test-restore/etc/hostname
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Block Device Restore
|
||||||
|
```bash
|
||||||
|
# On Proxmox VE, create test VM quarterly
|
||||||
|
# Follow VM conversion steps above
|
||||||
|
# Verify VM boots successfully
|
||||||
|
# Delete test VM after verification
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Block device backup fails: "cannot open device"
|
||||||
|
|
||||||
|
**Problem:** Device is busy/mounted
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# Option 1: Backup while system is running (works, but not ideal)
|
||||||
|
# Current script does this - it's safe but may have minor inconsistencies
|
||||||
|
|
||||||
|
# Option 2: Boot from USB and backup unmounted disk (best)
|
||||||
|
# Boot from Live USB
|
||||||
|
# Install PBS client
|
||||||
|
# Backup the unmounted disk
|
||||||
|
```
|
||||||
|
|
||||||
|
### VM won't boot after restore
|
||||||
|
|
||||||
|
**Common causes:**
|
||||||
|
1. Secure Boot enabled in VM (disable in VM settings)
|
||||||
|
2. Wrong boot order (set boot to scsi0)
|
||||||
|
3. EFI partition not restored (ensure you backed up entire disk, not just a partition)
|
||||||
|
|
||||||
|
**Fix:**
|
||||||
|
```bash
|
||||||
|
# In Proxmox VM settings:
|
||||||
|
# Options → Boot Order → Enable scsi0, move to top
|
||||||
|
# Options → BIOS → SeaBIOS (or OVMF if original was UEFI)
|
||||||
|
```
|
||||||
|
|
||||||
|
### "Not enough space" error during block device backup
|
||||||
|
|
||||||
|
**Problem:** Disk is large, PBS datastore is full
|
||||||
|
|
||||||
|
**Solutions:**
|
||||||
|
1. Clean old backups: `proxmox-backup-client prune`
|
||||||
|
2. Run garbage collection on PBS
|
||||||
|
3. Add more storage to PBS
|
||||||
|
4. Switch to file-level only or increase prune frequency
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## FAQ
|
||||||
|
|
||||||
|
**Q: Can I backup just one partition instead of entire disk?**
|
||||||
|
A: Yes! During setup, specify `/dev/sda1` instead of `/dev/sda`. However, you won't be able to directly boot this as a VM without manual partition table recreation.
|
||||||
|
|
||||||
|
**Q: Will hybrid backup run two backups simultaneously?**
|
||||||
|
A: No. On Sundays, it runs file backup first, then block backup. They're sequential.
|
||||||
|
|
||||||
|
**Q: Can I change the weekly block backup day from Sunday?**
|
||||||
|
A: Yes! Edit `/etc/proxmox-backup-client/backup.sh` and change `[ "$(date +%u)" -eq 7 ]` to different day (1=Monday, 7=Sunday).
|
||||||
|
|
||||||
|
**Q: Does block device backup require downtime?**
|
||||||
|
A: No, but it's a "hot backup" of a running system, so minor inconsistencies possible. For critical systems, consider backing up while system is idle or from Live USB.
|
||||||
|
|
||||||
|
**Q: Can I restore a block backup to smaller disk?**
|
||||||
|
A: No, target must be >= original size. You CAN restore file-level backups to any size disk.
|
||||||
|
|
||||||
|
**Q: Do I need encryption for block device backups?**
|
||||||
|
A: YES! Block device backups contain everything including swap (which may have passwords/keys). Always enable encryption.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Command Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List all backups
|
||||||
|
proxmox-backup-client snapshot list
|
||||||
|
|
||||||
|
# Restore file-level backup
|
||||||
|
proxmox-backup-client restore host/laptop/DATE root.pxar /restore/path
|
||||||
|
|
||||||
|
# Restore block device to disk
|
||||||
|
proxmox-backup-client restore host/laptop/DATE sda.img /dev/sdX
|
||||||
|
|
||||||
|
# Restore block device to VM disk
|
||||||
|
proxmox-backup-client restore host/laptop/DATE sda.img /dev/pve/vm-ID-disk-0
|
||||||
|
|
||||||
|
# Mount backup for browsing (file-level only)
|
||||||
|
proxmox-backup-client mount host/laptop/DATE root.pxar /mnt
|
||||||
|
|
||||||
|
# Check backup size
|
||||||
|
proxmox-backup-client snapshot list --output-format json | jq
|
||||||
|
|
||||||
|
# Manual block device backup
|
||||||
|
proxmox-backup-client backup sda.img:/dev/sda
|
||||||
|
```
|
||||||
15
CHANGELOG.md
15
CHANGELOG.md
|
|
@ -8,6 +8,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- **Docker-based cross-platform solution (v1.2.0 - NEW!)**
|
||||||
|
- Full Docker implementation for Windows, macOS, and Linux
|
||||||
|
- Dockerfile with PBS client in Debian container
|
||||||
|
- Platform-specific docker-compose files (linux/windows/macos)
|
||||||
|
- Daemon mode with internal cron scheduler
|
||||||
|
- One-shot backup mode for manual runs
|
||||||
|
- REST API server for remote management (optional)
|
||||||
|
- Health monitoring and status endpoints
|
||||||
|
- Automatic encryption key generation and management
|
||||||
|
- Build and deployment scripts (`build.sh`, `deploy.sh`)
|
||||||
|
- Complete Docker documentation (README-DOCKER.md, QUICKSTART-DOCKER.md)
|
||||||
|
- Organized in `docker/` subdirectory
|
||||||
|
- Cross-platform backup support matrix in README
|
||||||
|
- Platform-specific exclusion patterns
|
||||||
|
- Metadata change detection for fast incrementals
|
||||||
- **Multi-target backup support (v1.1.0 - COMPLETE)**
|
- **Multi-target backup support (v1.1.0 - COMPLETE)**
|
||||||
- Support for multiple backup destinations (different PBS servers for redundancy)
|
- Support for multiple backup destinations (different PBS servers for redundancy)
|
||||||
- Named backup targets (e.g., "offsite", "local", "backup1")
|
- Named backup targets (e.g., "offsite", "local", "backup1")
|
||||||
|
|
|
||||||
31
README.md
31
README.md
|
|
@ -1,10 +1,12 @@
|
||||||
# PBSClientTool
|
# PBSClientTool
|
||||||
|
|
||||||
Interactive tool for installing and managing Proxmox Backup Client on Ubuntu, Debian, and Arch Linux.
|
Interactive tool for installing and managing Proxmox Backup Client on **all platforms**: Linux (native), Windows, and macOS (Docker).
|
||||||
|
|
||||||
<img width="346" height="714" alt="screenshot-2025-11-02_18-48-02" src="https://github.com/user-attachments/assets/6796f247-ef4f-488c-8443-d232dc70b356" />
|
<img width="346" height="714" alt="screenshot-2025-11-02_18-48-02" src="https://github.com/user-attachments/assets/6796f247-ef4f-488c-8443-d232dc70b356" />
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
- **Cross-platform support** - Native Linux + Docker for Windows/Mac
|
||||||
- **Multi-target backups** - Backup to multiple PBS servers for redundancy
|
- **Multi-target backups** - Backup to multiple PBS servers for redundancy
|
||||||
- **Auto-detection** - Automatically detects your Linux distribution
|
- **Auto-detection** - Automatically detects your Linux distribution
|
||||||
- **File & block device backups** - Supports .pxar (files) and .img (full disk) backups
|
- **File & block device backups** - Supports .pxar (files) and .img (full disk) backups
|
||||||
|
|
@ -206,6 +208,33 @@ cd ~/dev/PBSClientTool
|
||||||
sudo ./uninstaller.sh
|
sudo ./uninstaller.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Docker Solution (Windows/Mac)
|
||||||
|
|
||||||
|
Want to backup Windows or macOS systems? Use the Docker-based solution:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd docker
|
||||||
|
./build.sh
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The Docker solution provides:
|
||||||
|
- **Cross-platform** - Works on Windows, macOS, and Linux
|
||||||
|
- **REST API** - Remote management and monitoring
|
||||||
|
- **File-level backups** - Daily automated backups
|
||||||
|
- **Easy deployment** - Single container, simple configuration
|
||||||
|
|
||||||
|
See [docker/README-DOCKER.md](docker/README-DOCKER.md) for complete documentation.
|
||||||
|
|
||||||
|
**Platform Support Matrix:**
|
||||||
|
|
||||||
|
| Feature | Native Linux | Docker (Win/Mac) |
|
||||||
|
|---------|-------------|------------------|
|
||||||
|
| File backups | ✅ Yes | ✅ Yes |
|
||||||
|
| Block device backups | ✅ Yes | ❌ No |
|
||||||
|
| Performance | ✅ Best | ⚠️ Good |
|
||||||
|
| Setup complexity | Medium | Easy |
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
Having issues? See the [Troubleshooting Guide](TROUBLESHOOTING.md) for:
|
Having issues? See the [Troubleshooting Guide](TROUBLESHOOTING.md) for:
|
||||||
|
|
|
||||||
392
docker/DOCKER-SOLUTION-SUMMARY.md
Normal file
392
docker/DOCKER-SOLUTION-SUMMARY.md
Normal file
|
|
@ -0,0 +1,392 @@
|
||||||
|
# PBS Client Docker Solution - Complete Package
|
||||||
|
|
||||||
|
This is a **cross-platform Proxmox Backup Client** running in Docker, enabling backups from **Windows, macOS, and Linux** to your Proxmox Backup Server.
|
||||||
|
|
||||||
|
## What's Included
|
||||||
|
|
||||||
|
### Core Docker Components
|
||||||
|
- **Dockerfile** - Multi-stage build with PBS client
|
||||||
|
- **docker-compose-linux.yml** - Linux deployment config
|
||||||
|
- **docker-compose-windows.yml** - Windows deployment config
|
||||||
|
- **docker-compose-macos.yml** - macOS deployment config
|
||||||
|
|
||||||
|
### Scripts (in `scripts/` directory)
|
||||||
|
- **entrypoint.sh** - Main container entrypoint, handles modes
|
||||||
|
- **backup.sh** - Actual backup logic that runs inside container
|
||||||
|
- **healthcheck.sh** - Container health monitoring
|
||||||
|
- **api-server.sh** - Optional REST API for management
|
||||||
|
|
||||||
|
### Deployment Tools
|
||||||
|
- **build.sh** - Builds the Docker image
|
||||||
|
- **deploy.sh** - Interactive deployment script (auto-detects platform)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- **README-DOCKER.md** - Complete documentation (500+ lines)
|
||||||
|
- **QUICKSTART-DOCKER.md** - Quick start guide
|
||||||
|
|
||||||
|
### Original Native Installers (Bonus)
|
||||||
|
- **pbs-client-installer.sh** - Interactive native installer
|
||||||
|
- **pbs-client-uninstaller.sh** - Clean removal script
|
||||||
|
- **README.md** - Native installer documentation
|
||||||
|
- **BACKUP-TYPES-GUIDE.md** - Guide for file vs block backups
|
||||||
|
|
||||||
|
## How It Works
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Host System │
|
||||||
|
│ (Windows/Mac/Linux) │
|
||||||
|
│ │
|
||||||
|
│ ┌──────────────────────────────────┐ │
|
||||||
|
│ │ Docker Container (Debian) │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ ┌────────────────────────────┐ │ │
|
||||||
|
│ │ │ PBS Client (Linux binary) │ │ │
|
||||||
|
│ │ │ │ │ │
|
||||||
|
│ │ │ - Connects to PBS Server │ │ │
|
||||||
|
│ │ │ - Reads host filesystem │ │ │
|
||||||
|
│ │ │ - Encrypts & uploads │ │ │
|
||||||
|
│ │ └────────────────────────────┘ │ │
|
||||||
|
│ │ │ │
|
||||||
|
│ │ Host FS mounted at /host-data │ │
|
||||||
|
│ │ ↓ │ │
|
||||||
|
│ │ C:\ or / or /Users │ │
|
||||||
|
│ └──────────────────────────────────┘ │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
│ TLS encrypted
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────────┐
|
||||||
|
│ Proxmox Backup Server │
|
||||||
|
│ 192.168.1.181:8007 │
|
||||||
|
│ │
|
||||||
|
│ - Receives encrypted chunks │
|
||||||
|
│ - Deduplicates data │
|
||||||
|
│ - Stores backups │
|
||||||
|
└─────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Two Operating Modes
|
||||||
|
|
||||||
|
### 1. Daemon Mode (Recommended)
|
||||||
|
Container runs continuously with internal cron scheduler:
|
||||||
|
- Automatic scheduled backups
|
||||||
|
- Health monitoring
|
||||||
|
- Optional REST API
|
||||||
|
- Persistent logging
|
||||||
|
|
||||||
|
**Use case:** Laptops and workstations that need regular automated backups
|
||||||
|
|
||||||
|
### 2. One-Shot Mode
|
||||||
|
Container runs backup once and exits:
|
||||||
|
- Triggered manually or by host scheduler
|
||||||
|
- Minimal resource usage when not running
|
||||||
|
- Good for CI/CD or manual backups
|
||||||
|
|
||||||
|
**Use case:** Servers with existing orchestration, testing, manual backups
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
### Cross-Platform
|
||||||
|
- **Linux:** Full support including block devices
|
||||||
|
- **Windows:** File-level backups of C:\ (or other drives)
|
||||||
|
- **macOS:** File-level backups with proper permission handling
|
||||||
|
|
||||||
|
### Docker Benefits
|
||||||
|
1. **Consistent environment** - PBS client runs in same Linux environment everywhere
|
||||||
|
2. **Easy updates** - Pull new image, restart container
|
||||||
|
3. **Isolation** - Container can't affect host system
|
||||||
|
4. **Portability** - Same container on all platforms
|
||||||
|
|
||||||
|
### Smart Defaults
|
||||||
|
- Auto-detects and excludes temp directories
|
||||||
|
- Platform-specific exclusion patterns
|
||||||
|
- Automatic encryption key generation
|
||||||
|
- Metadata change detection for fast incrementals
|
||||||
|
|
||||||
|
### Management
|
||||||
|
- REST API for remote control (optional)
|
||||||
|
- Health checks for monitoring
|
||||||
|
- Structured JSON logs
|
||||||
|
- docker-compose for easy deployment
|
||||||
|
|
||||||
|
## Quick Start Examples
|
||||||
|
|
||||||
|
### Linux Laptop
|
||||||
|
```bash
|
||||||
|
# Build
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
# Deploy (interactive)
|
||||||
|
./deploy.sh
|
||||||
|
|
||||||
|
# Or manually
|
||||||
|
docker-compose -f docker-compose-linux.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows Developer Machine
|
||||||
|
```bash
|
||||||
|
# Ensure Docker Desktop is running
|
||||||
|
# Share C:\ drive in Docker settings
|
||||||
|
|
||||||
|
./deploy.sh
|
||||||
|
# Or
|
||||||
|
docker-compose -f docker-compose-windows.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### macOS Laptop
|
||||||
|
```bash
|
||||||
|
# Grant Full Disk Access to Docker first
|
||||||
|
./deploy.sh
|
||||||
|
# Or
|
||||||
|
docker-compose -f docker-compose-macos.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with PBSClientTool
|
||||||
|
|
||||||
|
This Docker solution is **perfect for PBSClientTool** because:
|
||||||
|
|
||||||
|
1. **Uniform interface** - Same API/commands across all platforms
|
||||||
|
2. **Remote management** - REST API enables central control
|
||||||
|
3. **Easy deployment** - Single image works everywhere
|
||||||
|
4. **Standardized monitoring** - Same health checks on all systems
|
||||||
|
|
||||||
|
### Suggested Integration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PBSClientTool could deploy Docker containers
|
||||||
|
pbsclienttool deploy laptop1 --platform windows --docker
|
||||||
|
|
||||||
|
# Monitor via API
|
||||||
|
pbsclienttool status laptop1
|
||||||
|
# Queries: http://laptop1:8080/status
|
||||||
|
|
||||||
|
# Trigger backup remotely
|
||||||
|
pbsclienttool backup laptop1 --now
|
||||||
|
# POSTs to: http://laptop1:8080/backup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
### What Works
|
||||||
|
✅ File-level backups on all platforms
|
||||||
|
✅ Automatic encryption
|
||||||
|
✅ Incremental backups with deduplication
|
||||||
|
✅ Scheduled backups via cron
|
||||||
|
✅ Retention policies
|
||||||
|
✅ Remote management via API
|
||||||
|
|
||||||
|
### What Doesn't Work
|
||||||
|
❌ Block device backups on Windows/Mac (Docker limitation)
|
||||||
|
❌ Windows Shadow Copy / VSS
|
||||||
|
❌ macOS APFS snapshots
|
||||||
|
❌ Backing up files currently locked/open on Windows
|
||||||
|
❌ Accessing system files requiring SIP disabled on Mac
|
||||||
|
|
||||||
|
### Workarounds
|
||||||
|
- **Block devices:** Boot from Linux USB, run PBS client natively
|
||||||
|
- **Locked files:** Close applications before backup, or schedule during off-hours
|
||||||
|
- **Large files:** Use exclusions for `node_modules`, `.git`, etc.
|
||||||
|
|
||||||
|
## Storage Requirements
|
||||||
|
|
||||||
|
Example: 500GB laptop with 200GB used
|
||||||
|
|
||||||
|
**Docker overhead:**
|
||||||
|
- Image size: ~500MB
|
||||||
|
- Container overhead: ~50MB
|
||||||
|
- Logs: ~100MB/month
|
||||||
|
|
||||||
|
**PBS storage (on server):**
|
||||||
|
- First backup: ~200GB
|
||||||
|
- Daily backups: ~1-5GB each (only changes)
|
||||||
|
- With deduplication: Typically 5-10x reduction
|
||||||
|
- Monthly: ~50-100GB actual storage (with dedup)
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### First Backup
|
||||||
|
- Reads entire filesystem
|
||||||
|
- Can take hours for large disks
|
||||||
|
- Network bandwidth is bottleneck
|
||||||
|
- Consider running on-site for first backup
|
||||||
|
|
||||||
|
### Subsequent Backups
|
||||||
|
- Metadata change detection (fast)
|
||||||
|
- Only changed files transferred
|
||||||
|
- Typically 1-5GB transferred
|
||||||
|
- Usually completes in 10-30 minutes
|
||||||
|
|
||||||
|
### Docker Overhead
|
||||||
|
- **Linux:** Minimal (<5% performance impact)
|
||||||
|
- **Windows/Mac:** Docker Desktop adds overhead (~20-30% slower)
|
||||||
|
- **Network:** No impact, direct connection
|
||||||
|
|
||||||
|
## Security
|
||||||
|
|
||||||
|
### Built-in Security
|
||||||
|
1. **Client-side encryption** (AES-256-GCM)
|
||||||
|
2. **TLS transport** to PBS server
|
||||||
|
3. **Read-only filesystem mounts** (`:ro`)
|
||||||
|
4. **Isolated container** environment
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
1. Use API tokens instead of passwords
|
||||||
|
2. Backup encryption keys to secure location
|
||||||
|
3. Don't expose API port to internet
|
||||||
|
4. Use Docker secrets for credentials
|
||||||
|
5. Regular key rotation
|
||||||
|
|
||||||
|
### Credentials
|
||||||
|
Stored in:
|
||||||
|
- Environment variables (docker-compose)
|
||||||
|
- `.env` file (chmod 600)
|
||||||
|
- Or Docker secrets (production)
|
||||||
|
|
||||||
|
Never committed to git (in `.dockerignore`).
|
||||||
|
|
||||||
|
## Comparison: Docker vs Native Install
|
||||||
|
|
||||||
|
| Feature | Docker | Native Install |
|
||||||
|
|---------|--------|----------------|
|
||||||
|
| Windows support | ✅ Yes | ❌ No |
|
||||||
|
| macOS support | ✅ Yes | ❌ No |
|
||||||
|
| Linux support | ✅ Yes | ✅ Yes |
|
||||||
|
| Block devices (Linux) | ⚠️ Possible | ✅ Yes |
|
||||||
|
| Block devices (Win/Mac) | ❌ No | ❌ No |
|
||||||
|
| Ease of deployment | ✅ Very easy | ⚠️ Moderate |
|
||||||
|
| Updates | ✅ Pull image | ⚠️ Re-run installer |
|
||||||
|
| Resource usage | ⚠️ Higher | ✅ Lower |
|
||||||
|
| Portability | ✅ Excellent | ❌ Platform-specific |
|
||||||
|
| Performance | ⚠️ Good | ✅ Excellent |
|
||||||
|
|
||||||
|
**Recommendation:**
|
||||||
|
- **Docker:** Windows, macOS, mixed environment, ease of management
|
||||||
|
- **Native:** Linux servers, block device backups needed, maximum performance
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
### Perfect For Docker
|
||||||
|
|
||||||
|
1. **Mixed OS Team**
|
||||||
|
- 5 Windows laptops
|
||||||
|
- 3 MacBooks
|
||||||
|
- 2 Linux workstations
|
||||||
|
- → Single deployment method for all
|
||||||
|
|
||||||
|
2. **Developer Workstations**
|
||||||
|
- Already using Docker
|
||||||
|
- Need easy setup
|
||||||
|
- Want central management
|
||||||
|
|
||||||
|
3. **Remote Workers**
|
||||||
|
- Various operating systems
|
||||||
|
- Need automated backups
|
||||||
|
- Central IT management
|
||||||
|
|
||||||
|
4. **Testing/Development**
|
||||||
|
- Quick setup/teardown
|
||||||
|
- Multiple test environments
|
||||||
|
- Consistent results
|
||||||
|
|
||||||
|
### Better Native
|
||||||
|
|
||||||
|
1. **Linux Production Servers**
|
||||||
|
- Need maximum performance
|
||||||
|
- Block device backups required
|
||||||
|
- Direct hardware access needed
|
||||||
|
|
||||||
|
2. **Infrastructure Systems**
|
||||||
|
- Minimal dependencies preferred
|
||||||
|
- Docker not already deployed
|
||||||
|
- Tight resource constraints
|
||||||
|
|
||||||
|
## Monitoring & Alerts
|
||||||
|
|
||||||
|
### Health Checks
|
||||||
|
Container includes healthcheck that monitors:
|
||||||
|
- Cron daemon running (daemon mode)
|
||||||
|
- Last backup success/failure
|
||||||
|
- Backup age (alerts if >48 hours old)
|
||||||
|
- PBS server connectivity
|
||||||
|
|
||||||
|
### Status API
|
||||||
|
```bash
|
||||||
|
# Check status
|
||||||
|
curl http://localhost:8080/status
|
||||||
|
{
|
||||||
|
"last_backup": "2025-11-03T02:00:00Z",
|
||||||
|
"hostname": "laptop1",
|
||||||
|
"success": true,
|
||||||
|
"paths": ["/host-data"]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
{"status":"healthy"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Ideas
|
||||||
|
- Prometheus metrics exporter
|
||||||
|
- Grafana dashboard
|
||||||
|
- Email alerts on failure
|
||||||
|
- Slack/Discord notifications
|
||||||
|
|
||||||
|
## Roadmap / Future Ideas
|
||||||
|
|
||||||
|
### Possible Enhancements
|
||||||
|
1. **GUI Management** - Web interface for configuration
|
||||||
|
2. **Windows VSS Integration** - Shadow copy support
|
||||||
|
3. **Auto-discovery** - Detect and backup databases automatically
|
||||||
|
4. **Pre/post hooks** - Custom scripts before/after backup
|
||||||
|
5. **Bandwidth scheduling** - Different limits by time of day
|
||||||
|
6. **Multi-destination** - Backup to multiple PBS servers
|
||||||
|
7. **Backup verification** - Automated restore testing
|
||||||
|
|
||||||
|
### Community Contributions Welcome
|
||||||
|
- Platform testing (various Windows/Mac versions)
|
||||||
|
- Performance optimization
|
||||||
|
- Additional features
|
||||||
|
- Documentation improvements
|
||||||
|
|
||||||
|
## Support & Resources
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
- **README-DOCKER.md** - Complete reference
|
||||||
|
- **QUICKSTART-DOCKER.md** - Quick start guide
|
||||||
|
- **BACKUP-TYPES-GUIDE.md** - Backup strategy guide
|
||||||
|
|
||||||
|
### Community
|
||||||
|
- PBS Forums: https://forum.proxmox.com
|
||||||
|
- Your repo: [github-link]
|
||||||
|
- Issues/PRs welcome
|
||||||
|
|
||||||
|
### Related Projects
|
||||||
|
- **PBSClientTool** - Your CLI tool for PBS client management
|
||||||
|
- **proxmox-backup-client** - Official Proxmox client
|
||||||
|
- **Proxmox Backup Server** - Server component
|
||||||
|
|
||||||
|
## Getting Started Checklist
|
||||||
|
|
||||||
|
- [ ] Have PBS server running and accessible
|
||||||
|
- [ ] Create PBS user and API token
|
||||||
|
- [ ] Install Docker (Desktop on Win/Mac, Engine on Linux)
|
||||||
|
- [ ] Download/clone this repository
|
||||||
|
- [ ] Run `./build.sh` to build image
|
||||||
|
- [ ] Run `./deploy.sh` for guided setup
|
||||||
|
- [ ] **Backup encryption key immediately**
|
||||||
|
- [ ] Verify first backup completes
|
||||||
|
- [ ] Test restore of a few files
|
||||||
|
- [ ] Set up monitoring (optional)
|
||||||
|
|
||||||
|
## Conclusion
|
||||||
|
|
||||||
|
This Docker-based PBS client solution provides a **universal backup solution** that works across all major operating systems. Combined with Proxmox Backup Server and your PBSClientTool for management, you have a complete **open-source, self-hosted backup infrastructure** comparable to commercial solutions like CrashPlan or Backblaze, but with:
|
||||||
|
|
||||||
|
- Full control over your data
|
||||||
|
- No recurring costs
|
||||||
|
- Better deduplication
|
||||||
|
- Native Proxmox integration
|
||||||
|
- Support for hybrid environments
|
||||||
|
|
||||||
|
Perfect for MSPs, IT teams, homelabs, or anyone managing multiple systems across different platforms.
|
||||||
63
docker/Dockerfile
Normal file
63
docker/Dockerfile
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Proxmox Backup Client - Docker Container
|
||||||
|
# Cross-platform PBS client for Windows, Mac, and Linux
|
||||||
|
|
||||||
|
FROM debian:bookworm-slim
|
||||||
|
|
||||||
|
# Metadata
|
||||||
|
LABEL maintainer="PBSClientTool"
|
||||||
|
LABEL description="Cross-platform Proxmox Backup Client with scheduler"
|
||||||
|
LABEL version="1.0.0"
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y \
|
||||||
|
wget \
|
||||||
|
gnupg \
|
||||||
|
cron \
|
||||||
|
curl \
|
||||||
|
jq \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Add Proxmox repository and install PBS client
|
||||||
|
RUN wget -q https://enterprise.proxmox.com/debian/proxmox-release-bookworm.gpg \
|
||||||
|
-O /etc/apt/trusted.gpg.d/proxmox-release-bookworm.gpg && \
|
||||||
|
echo "deb [arch=amd64] http://download.proxmox.com/debian/pbs-client bookworm main" \
|
||||||
|
> /etc/apt/sources.list.d/pbs-client.list && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -y proxmox-backup-client && \
|
||||||
|
apt-get clean && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Create directories
|
||||||
|
RUN mkdir -p /config /backup-scripts /host-data /logs
|
||||||
|
|
||||||
|
# Copy scripts
|
||||||
|
COPY scripts/entrypoint.sh /usr/local/bin/
|
||||||
|
COPY scripts/backup.sh /usr/local/bin/pbs-backup
|
||||||
|
COPY scripts/healthcheck.sh /usr/local/bin/healthcheck
|
||||||
|
COPY scripts/api-server.sh /usr/local/bin/api-server
|
||||||
|
|
||||||
|
RUN chmod +x /usr/local/bin/entrypoint.sh \
|
||||||
|
/usr/local/bin/pbs-backup \
|
||||||
|
/usr/local/bin/healthcheck \
|
||||||
|
/usr/local/bin/api-server
|
||||||
|
|
||||||
|
# Expose API port (optional)
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
HEALTHCHECK --interval=5m --timeout=10s --start-period=30s --retries=3 \
|
||||||
|
CMD /usr/local/bin/healthcheck
|
||||||
|
|
||||||
|
# Default environment variables
|
||||||
|
ENV MODE=daemon \
|
||||||
|
BACKUP_SCHEDULE="0 2 * * *" \
|
||||||
|
BACKUP_PATHS="/host-data" \
|
||||||
|
EXCLUDE_PATTERNS="/host-data/tmp /host-data/var/tmp /host-data/proc /host-data/sys /host-data/dev" \
|
||||||
|
TIMEZONE=UTC
|
||||||
|
|
||||||
|
VOLUME ["/config", "/logs", "/host-data"]
|
||||||
|
|
||||||
|
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
|
||||||
|
CMD ["daemon"]
|
||||||
233
docker/QUICKSTART-DOCKER.md
Normal file
233
docker/QUICKSTART-DOCKER.md
Normal file
|
|
@ -0,0 +1,233 @@
|
||||||
|
# Docker PBS Client - Quick Start
|
||||||
|
|
||||||
|
## One-Command Deploy (Any Platform)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x deploy.sh
|
||||||
|
./deploy.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Answer the prompts and you're done!
|
||||||
|
|
||||||
|
## Manual Deploy
|
||||||
|
|
||||||
|
### 1. Build Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Create `.env` File
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat > .env << 'EOF'
|
||||||
|
PBS_REPOSITORY=backup@pbs!token@192.168.1.181:8007:backups
|
||||||
|
PBS_PASSWORD=your-token-secret-here
|
||||||
|
BACKUP_SCHEDULE=0 2 * * *
|
||||||
|
HOSTNAME=my-laptop
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Start Container
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux
|
||||||
|
docker-compose -f docker-compose-linux.yml up -d
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
docker-compose -f docker-compose-windows.yml up -d
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
docker-compose -f docker-compose-macos.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verify It's Working
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check container is running
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker logs pbs-backup-client
|
||||||
|
|
||||||
|
# Check last backup status
|
||||||
|
docker exec pbs-backup-client cat /logs/status.json | jq
|
||||||
|
|
||||||
|
# Trigger manual backup
|
||||||
|
docker exec pbs-backup-client /usr/local/bin/pbs-backup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Common Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Restart
|
||||||
|
docker-compose restart
|
||||||
|
|
||||||
|
# Update image
|
||||||
|
docker-compose pull
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# Shell access
|
||||||
|
docker exec -it pbs-backup-client /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backup Your Encryption Key!
|
||||||
|
|
||||||
|
**CRITICAL - Do this immediately:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy encryption key
|
||||||
|
docker cp pbs-backup-client:/config/encryption-key.json ./
|
||||||
|
|
||||||
|
# View paper backup
|
||||||
|
docker exec pbs-backup-client cat /config/encryption-key-paper.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Store these files securely. Without them, you cannot restore your backups!
|
||||||
|
|
||||||
|
## Platform-Specific Setup
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
1. Install Docker Desktop
|
||||||
|
2. Share C:\ drive with Docker (Settings → Resources → File Sharing)
|
||||||
|
3. Run: `docker-compose -f docker-compose-windows.yml up -d`
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
1. Install Docker Desktop
|
||||||
|
2. Grant Full Disk Access:
|
||||||
|
- System Preferences → Privacy & Security → Full Disk Access
|
||||||
|
- Add Docker.app
|
||||||
|
3. Run: `docker-compose -f docker-compose-macos.yml up -d`
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
1. Install Docker Engine
|
||||||
|
2. Run: `docker-compose -f docker-compose-linux.yml up -d`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
**Container won't start:**
|
||||||
|
```bash
|
||||||
|
docker-compose logs
|
||||||
|
docker-compose config # Validate config
|
||||||
|
```
|
||||||
|
|
||||||
|
**Can't connect to PBS:**
|
||||||
|
```bash
|
||||||
|
docker exec pbs-backup-client ping 192.168.1.181
|
||||||
|
docker exec pbs-backup-client proxmox-backup-client snapshot list
|
||||||
|
```
|
||||||
|
|
||||||
|
**Permission denied (Windows/Mac):**
|
||||||
|
- Windows: Share drive with Docker in settings
|
||||||
|
- Mac: Grant Full Disk Access to Docker
|
||||||
|
|
||||||
|
**Backup fails:**
|
||||||
|
```bash
|
||||||
|
# View detailed logs
|
||||||
|
docker exec pbs-backup-client cat /logs/last-backup.log
|
||||||
|
```
|
||||||
|
|
||||||
|
## What Gets Backed Up?
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
- Default: Entire root filesystem (`/`)
|
||||||
|
- Excludes: `/tmp`, `/proc`, `/sys`, `/dev`, `/run`
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
- Default: `C:\` drive
|
||||||
|
- Excludes: Temp folders, system files, cache
|
||||||
|
- Can add D:\, E:\ by editing docker-compose.yml
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
- Default: `/Users` and `/Applications`
|
||||||
|
- Excludes: Caches, logs, trash
|
||||||
|
- Can add other paths by editing docker-compose.yml
|
||||||
|
|
||||||
|
## API Access (Optional)
|
||||||
|
|
||||||
|
Enable API in docker-compose.yml:
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
ENABLE_API: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
Then access:
|
||||||
|
```bash
|
||||||
|
# Status
|
||||||
|
curl http://localhost:8080/status | jq
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
|
||||||
|
# Trigger backup
|
||||||
|
curl -X POST http://localhost:8080/backup
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
curl http://localhost:8080/logs | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customization
|
||||||
|
|
||||||
|
Edit `docker-compose-*.yml` to customize:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
# Change schedule
|
||||||
|
BACKUP_SCHEDULE: "0 3 * * *" # 3 AM daily
|
||||||
|
|
||||||
|
# Add more paths (Linux example)
|
||||||
|
BACKUP_PATHS: "/host-data /host-data/home"
|
||||||
|
|
||||||
|
# Add more exclusions
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/tmp /host-data/var/cache /host-data/Downloads"
|
||||||
|
|
||||||
|
# Adjust retention
|
||||||
|
KEEP_LAST: 5
|
||||||
|
KEEP_DAILY: 14
|
||||||
|
KEEP_WEEKLY: 8
|
||||||
|
KEEP_MONTHLY: 12
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart after changes:
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with PBSClientTool
|
||||||
|
|
||||||
|
The Docker approach complements PBSClientTool perfectly:
|
||||||
|
|
||||||
|
**Scenario:** Manage 10 developer laptops (mix of Windows/Mac/Linux)
|
||||||
|
|
||||||
|
1. Deploy Docker container on each laptop
|
||||||
|
2. Use PBSClientTool to monitor all backups centrally
|
||||||
|
3. API endpoints enable remote management
|
||||||
|
|
||||||
|
## Full Documentation
|
||||||
|
|
||||||
|
See `README-DOCKER.md` for complete documentation including:
|
||||||
|
- All configuration options
|
||||||
|
- Platform-specific details
|
||||||
|
- Security best practices
|
||||||
|
- Performance tuning
|
||||||
|
- Advanced usage
|
||||||
|
|
||||||
|
## Need Help?
|
||||||
|
|
||||||
|
- Full docs: README-DOCKER.md
|
||||||
|
- PBS Forums: https://forum.proxmox.com
|
||||||
|
- Issues: [your-github-repo]/issues
|
||||||
490
docker/README-DOCKER.md
Normal file
490
docker/README-DOCKER.md
Normal file
|
|
@ -0,0 +1,490 @@
|
||||||
|
# PBS Client Docker - Cross-Platform Backup Solution
|
||||||
|
|
||||||
|
Run Proxmox Backup Client on **Windows, macOS, and Linux** using Docker.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This Docker container provides a cross-platform way to backup any machine to Proxmox Backup Server, regardless of operating system. The container runs PBS client in a Linux environment while backing up your host filesystem.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Cross-platform:** Works on Windows, macOS, and Linux
|
||||||
|
- **Two modes:** Daemon (continuous with scheduler) or one-shot backup
|
||||||
|
- **Automatic encryption:** Client-side encryption with key management
|
||||||
|
- **Health monitoring:** Built-in healthcheck and status API
|
||||||
|
- **Flexible scheduling:** Cron-based scheduling for automated backups
|
||||||
|
- **Easy management:** Docker Compose for simple deployment
|
||||||
|
- **Retention policies:** Configurable backup retention
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### 1. Prerequisites
|
||||||
|
|
||||||
|
- Docker and Docker Compose installed
|
||||||
|
- Proxmox Backup Server accessible on network
|
||||||
|
- PBS user credentials or API token
|
||||||
|
|
||||||
|
### 2. Choose Your Platform
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux
|
||||||
|
docker-compose -f docker-compose-linux.yml up -d
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
docker-compose -f docker-compose-windows.yml up -d
|
||||||
|
|
||||||
|
# macOS
|
||||||
|
docker-compose -f docker-compose-macos.yml up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Configure
|
||||||
|
|
||||||
|
Edit the appropriate `docker-compose-*.yml` file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
PBS_REPOSITORY: "user@pbs!token@192.168.1.181:8007:backups"
|
||||||
|
PBS_PASSWORD: "your-token-secret"
|
||||||
|
BACKUP_SCHEDULE: "0 2 * * *" # Daily at 2 AM
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Done! Backups will run automatically on schedule.
|
||||||
|
|
||||||
|
## Building the Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Build
|
||||||
|
docker build -t pbsclient:latest .
|
||||||
|
|
||||||
|
# Or use build script
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage Modes
|
||||||
|
|
||||||
|
### Daemon Mode (Recommended)
|
||||||
|
|
||||||
|
Container runs continuously with cron scheduler:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
--name pbs-client \
|
||||||
|
-v /:/host-data:ro \
|
||||||
|
-v pbs-config:/config \
|
||||||
|
-v pbs-logs:/logs \
|
||||||
|
-e PBS_REPOSITORY="user@pbs!token@192.168.1.181:8007:backups" \
|
||||||
|
-e PBS_PASSWORD="secret" \
|
||||||
|
-e MODE=daemon \
|
||||||
|
-e BACKUP_SCHEDULE="0 2 * * *" \
|
||||||
|
pbsclient:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### One-Shot Mode
|
||||||
|
|
||||||
|
Run backup once and exit:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm \
|
||||||
|
-v /:/host-data:ro \
|
||||||
|
-v pbs-config:/config \
|
||||||
|
-e PBS_REPOSITORY="user@pbs!token@192.168.1.181:8007:backups" \
|
||||||
|
-e PBS_PASSWORD="secret" \
|
||||||
|
pbsclient:latest backup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
| Variable | Required | Default | Description |
|
||||||
|
|----------|----------|---------|-------------|
|
||||||
|
| `PBS_REPOSITORY` | Yes | - | PBS repository URL |
|
||||||
|
| `PBS_PASSWORD` | Yes | - | PBS password or API token |
|
||||||
|
| `MODE` | No | `daemon` | Container mode: `daemon`, `backup`, `test` |
|
||||||
|
| `BACKUP_SCHEDULE` | No | `0 2 * * *` | Cron schedule for backups |
|
||||||
|
| `BACKUP_PATHS` | No | `/host-data` | Paths to backup (space-separated) |
|
||||||
|
| `EXCLUDE_PATTERNS` | No | See compose files | Exclusion patterns |
|
||||||
|
| `CONTAINER_HOSTNAME` | No | container hostname | Hostname for backups |
|
||||||
|
| `KEEP_LAST` | No | `3` | Keep last N backups |
|
||||||
|
| `KEEP_DAILY` | No | `7` | Keep daily backups for N days |
|
||||||
|
| `KEEP_WEEKLY` | No | `4` | Keep weekly backups for N weeks |
|
||||||
|
| `KEEP_MONTHLY` | No | `6` | Keep monthly backups for N months |
|
||||||
|
| `ENABLE_API` | No | `false` | Enable REST API server |
|
||||||
|
| `API_PORT` | No | `8080` | API server port |
|
||||||
|
| `TIMEZONE` | No | `UTC` | Container timezone |
|
||||||
|
|
||||||
|
### Volume Mounts
|
||||||
|
|
||||||
|
| Volume | Purpose | Required |
|
||||||
|
|--------|---------|----------|
|
||||||
|
| `/host-data` | Host filesystem to backup | Yes |
|
||||||
|
| `/config` | Persistent config and encryption keys | Yes |
|
||||||
|
| `/logs` | Backup logs | Recommended |
|
||||||
|
|
||||||
|
## Management Commands
|
||||||
|
|
||||||
|
### Check Status
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Via logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Via API (if enabled)
|
||||||
|
curl http://localhost:8080/status
|
||||||
|
|
||||||
|
# Check last backup
|
||||||
|
docker exec pbs-client cat /logs/status.json | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Backup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Trigger backup manually
|
||||||
|
docker exec pbs-client /usr/local/bin/pbs-backup
|
||||||
|
|
||||||
|
# Or via API
|
||||||
|
curl -X POST http://localhost:8080/backup
|
||||||
|
```
|
||||||
|
|
||||||
|
### View Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Follow live logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Last backup log
|
||||||
|
docker exec pbs-client cat /logs/last-backup.log
|
||||||
|
|
||||||
|
# Via API
|
||||||
|
curl http://localhost:8080/logs
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test Connection
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec pbs-client proxmox-backup-client snapshot list
|
||||||
|
```
|
||||||
|
|
||||||
|
### Interactive Shell
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker exec -it pbs-client /bin/bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Platform-Specific Notes
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
**File System Access:**
|
||||||
|
- Mounts `C:\` drive by default
|
||||||
|
- To backup additional drives, add volume mounts:
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- C:\:/host-data:ro
|
||||||
|
- D:\:/host-data-d:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
**Exclusions:**
|
||||||
|
- System files (pagefile.sys, hiberfil.sys)
|
||||||
|
- Temp directories
|
||||||
|
- Windows Update cache
|
||||||
|
- User temp files
|
||||||
|
|
||||||
|
**Scheduling:**
|
||||||
|
- Container must run continuously
|
||||||
|
- Docker Desktop must start on boot
|
||||||
|
|
||||||
|
**Limitations:**
|
||||||
|
- No block device backups (file-level only)
|
||||||
|
- Cannot backup files locked by Windows
|
||||||
|
- Shadow Copy not available
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
|
||||||
|
**File System Access:**
|
||||||
|
- Requires Full Disk Access for Docker
|
||||||
|
- Grant in: System Preferences → Privacy & Security → Full Disk Access
|
||||||
|
- May need to restart Docker Desktop after granting access
|
||||||
|
|
||||||
|
**Recommended Paths:**
|
||||||
|
- `/Users` - Home directories
|
||||||
|
- `/Applications` - Installed apps
|
||||||
|
- `/etc` - System configs
|
||||||
|
- `/Library/Application Support` - App data
|
||||||
|
|
||||||
|
**Exclusions:**
|
||||||
|
- Caches and logs in `~/Library`
|
||||||
|
- Xcode (very large)
|
||||||
|
- Time Machine backups
|
||||||
|
- Downloads folder
|
||||||
|
|
||||||
|
**Limitations:**
|
||||||
|
- No block device backups
|
||||||
|
- Some system files require SIP disabled (not recommended)
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
**Full Access:**
|
||||||
|
- Can backup everything including block devices
|
||||||
|
- Mount with `:ro` for safety
|
||||||
|
- Use `--privileged` for block device access (if needed)
|
||||||
|
|
||||||
|
**Block Device Backups:**
|
||||||
|
To enable block device backups on Linux:
|
||||||
|
```yaml
|
||||||
|
devices:
|
||||||
|
- /dev/sda:/dev/sda:ro
|
||||||
|
privileged: true
|
||||||
|
```
|
||||||
|
|
||||||
|
Then set:
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
BACKUP_TYPE: block
|
||||||
|
BLOCK_DEVICE: /dev/sda
|
||||||
|
```
|
||||||
|
|
||||||
|
## API Endpoints
|
||||||
|
|
||||||
|
When `ENABLE_API=true`:
|
||||||
|
|
||||||
|
| Endpoint | Method | Description |
|
||||||
|
|----------|--------|-------------|
|
||||||
|
| `/status` | GET | Current backup status |
|
||||||
|
| `/health` | GET | Health check |
|
||||||
|
| `/backup` | POST | Trigger manual backup |
|
||||||
|
| `/logs` | GET | Recent backup logs |
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```bash
|
||||||
|
# Check status
|
||||||
|
curl http://localhost:8080/status | jq
|
||||||
|
|
||||||
|
# Trigger backup
|
||||||
|
curl -X POST http://localhost:8080/backup
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
```
|
||||||
|
|
||||||
|
## Encryption Keys
|
||||||
|
|
||||||
|
**CRITICAL:** Your encryption key is stored in `/config/encryption-key.json`
|
||||||
|
|
||||||
|
### Backup Your Key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy from volume
|
||||||
|
docker cp pbs-client:/config/encryption-key.json ./backup/
|
||||||
|
|
||||||
|
# View paper backup (QR code)
|
||||||
|
docker exec pbs-client cat /config/encryption-key-paper.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restore Key
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy key to volume
|
||||||
|
docker cp ./backup/encryption-key.json pbs-client:/config/
|
||||||
|
|
||||||
|
# Restart container
|
||||||
|
docker-compose restart
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Connection Fails
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Test PBS connectivity
|
||||||
|
docker exec pbs-client bash -c "export PBS_REPOSITORY='...' PBS_PASSWORD='...' && proxmox-backup-client snapshot list"
|
||||||
|
|
||||||
|
# Check network
|
||||||
|
docker exec pbs-client ping 192.168.1.181
|
||||||
|
|
||||||
|
# Check firewall rules
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Denied
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux: Ensure volume mounts are readable
|
||||||
|
# Windows: Grant Docker access to drives
|
||||||
|
# macOS: Grant Full Disk Access
|
||||||
|
```
|
||||||
|
|
||||||
|
### Container Won't Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check logs
|
||||||
|
docker-compose logs
|
||||||
|
|
||||||
|
# Validate environment variables
|
||||||
|
docker-compose config
|
||||||
|
|
||||||
|
# Check disk space
|
||||||
|
docker system df
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup Fails
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check last backup log
|
||||||
|
docker exec pbs-client cat /logs/last-backup.log
|
||||||
|
|
||||||
|
# Verify paths exist
|
||||||
|
docker exec pbs-client ls -la /host-data
|
||||||
|
|
||||||
|
# Check exclusion patterns
|
||||||
|
```
|
||||||
|
|
||||||
|
### High Memory Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Limit container memory
|
||||||
|
docker run --memory=4g ...
|
||||||
|
|
||||||
|
# Or in docker-compose:
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 4G
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance Considerations
|
||||||
|
|
||||||
|
### Network Bandwidth
|
||||||
|
|
||||||
|
For remote backups over WAN:
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
RATE_LIMIT: 10485760 # 10 MB/s
|
||||||
|
```
|
||||||
|
|
||||||
|
### Storage Requirements
|
||||||
|
|
||||||
|
First backup reads all data. Subsequent backups only transfer changed files.
|
||||||
|
|
||||||
|
Example: 500GB system with 200GB used
|
||||||
|
- First backup: ~200GB transferred
|
||||||
|
- Daily backups: ~1-5GB transferred (only changes)
|
||||||
|
- Monthly storage: ~10-30GB (with deduplication)
|
||||||
|
|
||||||
|
### Docker Desktop Limitations
|
||||||
|
|
||||||
|
Docker Desktop (Windows/Mac) has performance overhead:
|
||||||
|
- File I/O slower than native
|
||||||
|
- First backup will be slower
|
||||||
|
- Consider increasing Docker resources
|
||||||
|
|
||||||
|
## Integration with PBSClientTool
|
||||||
|
|
||||||
|
This Docker solution complements PBSClientTool:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Use PBSClientTool to manage Docker containers
|
||||||
|
pbsclienttool add-target \
|
||||||
|
--name laptop1 \
|
||||||
|
--type docker \
|
||||||
|
--host laptop1.local \
|
||||||
|
--repository "..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
1. **Use API Tokens** instead of passwords
|
||||||
|
2. **Enable encryption** (automatic by default)
|
||||||
|
3. **Backup encryption keys** to secure location
|
||||||
|
4. **Mount filesystems read-only** (`:ro`)
|
||||||
|
5. **Don't expose API port** to internet
|
||||||
|
6. **Use secrets management** for credentials:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
secrets:
|
||||||
|
pbs_password:
|
||||||
|
external: true
|
||||||
|
|
||||||
|
environment:
|
||||||
|
PBS_PASSWORD_FILE: /run/secrets/pbs_password
|
||||||
|
```
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
### What This CANNOT Do
|
||||||
|
|
||||||
|
- **Windows/Mac block device backups** - File-level only
|
||||||
|
- **Shadow Copy/VSS on Windows** - Not available
|
||||||
|
- **Live database backups** - Stop database first or use dumps
|
||||||
|
- **Backup locked files** - Some Windows files may be skipped
|
||||||
|
- **APFS snapshots on Mac** - Not accessible from Docker
|
||||||
|
|
||||||
|
### Workarounds
|
||||||
|
|
||||||
|
For databases:
|
||||||
|
```bash
|
||||||
|
# Pre-backup hook
|
||||||
|
docker exec pbs-client bash -c '
|
||||||
|
mysqldump -u root -p password db > /host-data/backup/db.sql
|
||||||
|
'
|
||||||
|
```
|
||||||
|
|
||||||
|
For block device backups on Windows/Mac:
|
||||||
|
- Boot from Linux USB
|
||||||
|
- Run PBS client natively
|
||||||
|
- Backup unmounted disk
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Backup Windows User Profile Only
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- C:\Users\YourName:/host-data:ro
|
||||||
|
|
||||||
|
environment:
|
||||||
|
BACKUP_PATHS: "/host-data"
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/AppData/Local/Temp"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup Multiple Mac Users
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- /Users:/host-data:ro
|
||||||
|
|
||||||
|
environment:
|
||||||
|
BACKUP_PATHS: "/host-data"
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/*/Library/Caches /host-data/*/.Trash"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup Linux Server with Multiple Mounts
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- /:/host-data:ro
|
||||||
|
- /home:/host-home:ro
|
||||||
|
- /var/www:/host-www:ro
|
||||||
|
|
||||||
|
environment:
|
||||||
|
BACKUP_PATHS: "/host-data /host-home /host-www"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
|
||||||
|
Issues and pull requests welcome at [your-repo-url]
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
## Credits
|
||||||
|
|
||||||
|
- Proxmox team for PBS
|
||||||
|
- Docker PBS client by [your-name]
|
||||||
59
docker/build.sh
Executable file
59
docker/build.sh
Executable file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Build script for PBS Client Docker image
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
VERSION=${1:-latest}
|
||||||
|
IMAGE_NAME="pbsclient"
|
||||||
|
|
||||||
|
echo "=================================="
|
||||||
|
echo "Building PBS Client Docker Image"
|
||||||
|
echo "=================================="
|
||||||
|
echo "Version: $VERSION"
|
||||||
|
echo "Image: $IMAGE_NAME:$VERSION"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check if scripts directory exists
|
||||||
|
if [ ! -d "scripts" ]; then
|
||||||
|
echo "ERROR: scripts/ directory not found"
|
||||||
|
echo "Make sure you're in the correct directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build the image
|
||||||
|
echo "Building image..."
|
||||||
|
docker build -t "$IMAGE_NAME:$VERSION" .
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo
|
||||||
|
echo "=================================="
|
||||||
|
echo "Build successful!"
|
||||||
|
echo "=================================="
|
||||||
|
echo
|
||||||
|
echo "Image: $IMAGE_NAME:$VERSION"
|
||||||
|
echo
|
||||||
|
echo "Quick test:"
|
||||||
|
echo " docker run --rm $IMAGE_NAME:$VERSION test"
|
||||||
|
echo
|
||||||
|
echo "Deploy with:"
|
||||||
|
echo " docker-compose -f docker-compose-linux.yml up -d"
|
||||||
|
echo " docker-compose -f docker-compose-windows.yml up -d"
|
||||||
|
echo " docker-compose -f docker-compose-macos.yml up -d"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "=================================="
|
||||||
|
echo "Build failed!"
|
||||||
|
echo "=================================="
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Optionally tag as latest
|
||||||
|
if [ "$VERSION" != "latest" ]; then
|
||||||
|
echo "Tagging as latest..."
|
||||||
|
docker tag "$IMAGE_NAME:$VERSION" "$IMAGE_NAME:latest"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show image size
|
||||||
|
echo "Image size:"
|
||||||
|
docker images "$IMAGE_NAME:$VERSION" --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
|
||||||
181
docker/deploy.sh
Executable file
181
docker/deploy.sh
Executable file
|
|
@ -0,0 +1,181 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Smart deployment script - detects platform and deploys appropriate config
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Colors
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo -e "${GREEN}[$(date +'%H:%M:%S')]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
info() {
|
||||||
|
echo -e "${BLUE}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Detect platform
|
||||||
|
detect_platform() {
|
||||||
|
case "$(uname -s)" in
|
||||||
|
Linux*)
|
||||||
|
echo "linux"
|
||||||
|
;;
|
||||||
|
Darwin*)
|
||||||
|
echo "macos"
|
||||||
|
;;
|
||||||
|
CYGWIN*|MINGW*|MSYS*)
|
||||||
|
echo "windows"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "unknown"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check Docker is installed
|
||||||
|
check_docker() {
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo "ERROR: Docker is not installed"
|
||||||
|
echo
|
||||||
|
echo "Install Docker:"
|
||||||
|
echo " Linux: https://docs.docker.com/engine/install/"
|
||||||
|
echo " Windows: https://docs.docker.com/desktop/install/windows-install/"
|
||||||
|
echo " Mac: https://docs.docker.com/desktop/install/mac-install/"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! docker ps &> /dev/null; then
|
||||||
|
echo "ERROR: Docker is not running"
|
||||||
|
echo "Start Docker and try again"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prompt for configuration
|
||||||
|
prompt_config() {
|
||||||
|
echo
|
||||||
|
echo "======================================"
|
||||||
|
echo " PBS Client Docker Setup"
|
||||||
|
echo "======================================"
|
||||||
|
echo
|
||||||
|
|
||||||
|
read -p "PBS Server IP/hostname: " PBS_SERVER
|
||||||
|
read -p "PBS Server port [8007]: " PBS_PORT
|
||||||
|
PBS_PORT=${PBS_PORT:-8007}
|
||||||
|
|
||||||
|
read -p "PBS Datastore name: " PBS_DATASTORE
|
||||||
|
read -p "PBS Username: " PBS_USERNAME
|
||||||
|
read -p "PBS Realm [pbs]: " PBS_REALM
|
||||||
|
PBS_REALM=${PBS_REALM:-pbs}
|
||||||
|
read -p "PBS Token name: " PBS_TOKEN
|
||||||
|
read -sp "PBS Token secret: " PBS_PASSWORD
|
||||||
|
echo
|
||||||
|
|
||||||
|
PBS_REPOSITORY="${PBS_USERNAME}@${PBS_REALM}!${PBS_TOKEN}@${PBS_SERVER}:${PBS_PORT}:${PBS_DATASTORE}"
|
||||||
|
|
||||||
|
read -p "Backup schedule (cron format) [0 2 * * *]: " SCHEDULE
|
||||||
|
SCHEDULE=${SCHEDULE:-"0 2 * * *"}
|
||||||
|
|
||||||
|
read -p "Container hostname [$(hostname)]: " CONTAINER_HOST
|
||||||
|
CONTAINER_HOST=${CONTAINER_HOST:-$(hostname)}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create env file
|
||||||
|
create_env_file() {
|
||||||
|
cat > .env << EOF
|
||||||
|
# PBS Configuration
|
||||||
|
PBS_REPOSITORY=${PBS_REPOSITORY}
|
||||||
|
PBS_PASSWORD=${PBS_PASSWORD}
|
||||||
|
|
||||||
|
# Backup Configuration
|
||||||
|
BACKUP_SCHEDULE=${SCHEDULE}
|
||||||
|
CONTAINER_HOSTNAME=${CONTAINER_HOST}
|
||||||
|
|
||||||
|
# Hostname
|
||||||
|
HOSTNAME=${CONTAINER_HOST}
|
||||||
|
COMPUTERNAME=${CONTAINER_HOST}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 600 .env
|
||||||
|
log "Configuration saved to .env"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
deploy() {
|
||||||
|
local platform=$1
|
||||||
|
local compose_file="docker-compose-${platform}.yml"
|
||||||
|
|
||||||
|
if [ ! -f "$compose_file" ]; then
|
||||||
|
echo "ERROR: $compose_file not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Deploying PBS Client for $platform..."
|
||||||
|
|
||||||
|
# Build if image doesn't exist
|
||||||
|
if ! docker images pbsclient:latest | grep -q pbsclient; then
|
||||||
|
warn "Image not found, building..."
|
||||||
|
./build.sh
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
docker-compose -f "$compose_file" up -d
|
||||||
|
|
||||||
|
echo
|
||||||
|
log "Deployment complete!"
|
||||||
|
echo
|
||||||
|
info "Container status:"
|
||||||
|
docker-compose -f "$compose_file" ps
|
||||||
|
echo
|
||||||
|
info "View logs:"
|
||||||
|
echo " docker-compose -f $compose_file logs -f"
|
||||||
|
echo
|
||||||
|
info "Check backup status:"
|
||||||
|
echo " docker exec pbs-backup-client cat /logs/status.json"
|
||||||
|
echo
|
||||||
|
info "Manual backup:"
|
||||||
|
echo " docker exec pbs-backup-client /usr/local/bin/pbs-backup"
|
||||||
|
echo
|
||||||
|
warn "IMPORTANT: Backup your encryption key!"
|
||||||
|
echo " docker cp pbs-backup-client:/config/encryption-key.json ./encryption-key.json"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main
|
||||||
|
main() {
|
||||||
|
echo
|
||||||
|
echo "╔════════════════════════════════════════╗"
|
||||||
|
echo "║ PBS Client Docker Deployment ║"
|
||||||
|
echo "╚════════════════════════════════════════╝"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Check prerequisites
|
||||||
|
check_docker
|
||||||
|
|
||||||
|
# Detect platform
|
||||||
|
PLATFORM=$(detect_platform)
|
||||||
|
info "Detected platform: $PLATFORM"
|
||||||
|
|
||||||
|
if [ "$PLATFORM" = "unknown" ]; then
|
||||||
|
echo "ERROR: Cannot detect platform"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prompt for configuration
|
||||||
|
prompt_config
|
||||||
|
|
||||||
|
# Create env file
|
||||||
|
create_env_file
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
deploy "$PLATFORM"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
61
docker/docker-compose-linux.yml
Normal file
61
docker/docker-compose-linux.yml
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
pbs-client:
|
||||||
|
image: pbsclient:latest
|
||||||
|
container_name: pbs-backup-client
|
||||||
|
hostname: ${HOSTNAME:-linux-host}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Required: PBS Server Configuration
|
||||||
|
PBS_REPOSITORY: "backup@pbs!token@192.168.1.181:8007:backups"
|
||||||
|
PBS_PASSWORD: "your-api-token-secret-here"
|
||||||
|
|
||||||
|
# Container Mode
|
||||||
|
MODE: daemon
|
||||||
|
|
||||||
|
# Backup Configuration
|
||||||
|
BACKUP_SCHEDULE: "0 2 * * *" # Daily at 2 AM
|
||||||
|
BACKUP_PATHS: "/host-data"
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/tmp /host-data/var/tmp /host-data/var/cache /host-data/proc /host-data/sys /host-data/dev /host-data/run"
|
||||||
|
CONTAINER_HOSTNAME: "${HOSTNAME:-linux-host}"
|
||||||
|
|
||||||
|
# Retention Policy
|
||||||
|
KEEP_LAST: 3
|
||||||
|
KEEP_DAILY: 7
|
||||||
|
KEEP_WEEKLY: 4
|
||||||
|
KEEP_MONTHLY: 6
|
||||||
|
|
||||||
|
# Optional: API Server
|
||||||
|
ENABLE_API: "true"
|
||||||
|
API_PORT: 8080
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
TIMEZONE: "America/New_York"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Mount host filesystem (read-only for safety)
|
||||||
|
- /:/host-data:ro
|
||||||
|
|
||||||
|
# Persistent config and logs
|
||||||
|
- pbs-config:/config
|
||||||
|
- pbs-logs:/logs
|
||||||
|
|
||||||
|
ports:
|
||||||
|
# API port (optional)
|
||||||
|
- "8080:8080"
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
healthcheck:
|
||||||
|
test: ["/usr/local/bin/healthcheck"]
|
||||||
|
interval: 5m
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pbs-config:
|
||||||
|
name: pbs-client-config
|
||||||
|
pbs-logs:
|
||||||
|
name: pbs-client-logs
|
||||||
80
docker/docker-compose-macos.yml
Normal file
80
docker/docker-compose-macos.yml
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
# PBS Client for macOS
|
||||||
|
# Backs up user home directories and important system files
|
||||||
|
|
||||||
|
services:
|
||||||
|
pbs-client:
|
||||||
|
image: pbsclient:latest
|
||||||
|
container_name: pbs-backup-client
|
||||||
|
hostname: ${HOSTNAME:-mac-host}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Required: PBS Server Configuration
|
||||||
|
PBS_REPOSITORY: "backup@pbs!token@192.168.1.181:8007:backups"
|
||||||
|
PBS_PASSWORD: "your-api-token-secret-here"
|
||||||
|
|
||||||
|
# Container Mode
|
||||||
|
MODE: daemon
|
||||||
|
|
||||||
|
# Backup Configuration
|
||||||
|
BACKUP_SCHEDULE: "0 2 * * *" # Daily at 2 AM
|
||||||
|
BACKUP_PATHS: "/host-data/Users /host-data/Applications"
|
||||||
|
# macOS-specific exclusions
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/Users/*/Library/Caches /host-data/Users/*/Library/Logs /host-data/Users/*/.Trash /host-data/Users/*/Downloads /host-data/Applications/Xcode.app"
|
||||||
|
CONTAINER_HOSTNAME: "${HOSTNAME:-mac-host}"
|
||||||
|
|
||||||
|
# Retention Policy
|
||||||
|
KEEP_LAST: 3
|
||||||
|
KEEP_DAILY: 7
|
||||||
|
KEEP_WEEKLY: 4
|
||||||
|
KEEP_MONTHLY: 6
|
||||||
|
|
||||||
|
# Optional: API Server
|
||||||
|
ENABLE_API: "true"
|
||||||
|
API_PORT: 8080
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
TIMEZONE: "America/New_York"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Mount macOS filesystem
|
||||||
|
# Note: Docker Desktop for Mac has permission restrictions
|
||||||
|
# You may need to grant access in System Preferences → Privacy & Security
|
||||||
|
- /:/host-data:ro
|
||||||
|
|
||||||
|
# Persistent config and logs
|
||||||
|
- pbs-config:/config
|
||||||
|
- pbs-logs:/logs
|
||||||
|
|
||||||
|
ports:
|
||||||
|
# API port (optional)
|
||||||
|
- "8080:8080"
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
healthcheck:
|
||||||
|
test: ["/usr/local/bin/healthcheck"]
|
||||||
|
interval: 5m
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pbs-config:
|
||||||
|
name: pbs-client-config
|
||||||
|
pbs-logs:
|
||||||
|
name: pbs-client-logs
|
||||||
|
|
||||||
|
# To run on macOS:
|
||||||
|
# 1. Install Docker Desktop for Mac
|
||||||
|
# 2. Grant Docker file system access:
|
||||||
|
# System Preferences → Privacy & Security → Full Disk Access → Add Docker
|
||||||
|
# 3. Edit PBS_REPOSITORY and PBS_PASSWORD above
|
||||||
|
# 4. Run: docker-compose -f docker-compose-macos.yml up -d
|
||||||
|
#
|
||||||
|
# For Time Machine-style backups, consider backing up only:
|
||||||
|
# - /Users (home directories)
|
||||||
|
# - /Applications (installed apps)
|
||||||
|
# - /etc (system configs)
|
||||||
|
# - /Library/Application Support (app data)
|
||||||
75
docker/docker-compose-windows.yml
Normal file
75
docker/docker-compose-windows.yml
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
# PBS Client for Windows
|
||||||
|
# Backs up C:\ drive (or other drives as needed)
|
||||||
|
|
||||||
|
services:
|
||||||
|
pbs-client:
|
||||||
|
image: pbsclient:latest
|
||||||
|
container_name: pbs-backup-client
|
||||||
|
hostname: ${COMPUTERNAME:-windows-host}
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
environment:
|
||||||
|
# Required: PBS Server Configuration
|
||||||
|
PBS_REPOSITORY: "backup@pbs!token@192.168.1.181:8007:backups"
|
||||||
|
PBS_PASSWORD: "your-api-token-secret-here"
|
||||||
|
|
||||||
|
# Container Mode
|
||||||
|
MODE: daemon
|
||||||
|
|
||||||
|
# Backup Configuration
|
||||||
|
BACKUP_SCHEDULE: "0 2 * * *" # Daily at 2 AM
|
||||||
|
BACKUP_PATHS: "/host-data"
|
||||||
|
# Windows-specific exclusions
|
||||||
|
EXCLUDE_PATTERNS: "/host-data/Windows/Temp /host-data/Windows/Logs /host-data/ProgramData/Microsoft/Windows/WER /host-data/ProgramData/Package Cache /host-data/Users/*/AppData/Local/Temp /host-data/Users/*/AppData/Local/Microsoft/Windows/INetCache /host-data/pagefile.sys /host-data/hiberfil.sys /host-data/swapfile.sys"
|
||||||
|
CONTAINER_HOSTNAME: "${COMPUTERNAME:-windows-host}"
|
||||||
|
|
||||||
|
# Retention Policy
|
||||||
|
KEEP_LAST: 3
|
||||||
|
KEEP_DAILY: 7
|
||||||
|
KEEP_WEEKLY: 4
|
||||||
|
KEEP_MONTHLY: 6
|
||||||
|
|
||||||
|
# Optional: API Server
|
||||||
|
ENABLE_API: "true"
|
||||||
|
API_PORT: 8080
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
TIMEZONE: "America/New_York"
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Mount Windows C:\ drive
|
||||||
|
# Note: You can add additional drives like D:\, E:\, etc.
|
||||||
|
- C:\:/host-data:ro
|
||||||
|
|
||||||
|
# Persistent config and logs
|
||||||
|
- pbs-config:/config
|
||||||
|
- pbs-logs:/logs
|
||||||
|
|
||||||
|
ports:
|
||||||
|
# API port (optional)
|
||||||
|
- "8080:8080"
|
||||||
|
|
||||||
|
# Health check
|
||||||
|
healthcheck:
|
||||||
|
test: ["/usr/local/bin/healthcheck"]
|
||||||
|
interval: 5m
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 30s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pbs-config:
|
||||||
|
name: pbs-client-config
|
||||||
|
pbs-logs:
|
||||||
|
name: pbs-client-logs
|
||||||
|
|
||||||
|
# To run on Windows:
|
||||||
|
# 1. Install Docker Desktop for Windows
|
||||||
|
# 2. Edit PBS_REPOSITORY and PBS_PASSWORD above
|
||||||
|
# 3. Run: docker-compose -f docker-compose-windows.yml up -d
|
||||||
|
#
|
||||||
|
# To add additional drives (e.g., D:\):
|
||||||
|
# - Add another volume mount: - D:\:/host-data-d:ro
|
||||||
|
# - Update BACKUP_PATHS: "/host-data /host-data-d"
|
||||||
79
docker/scripts/api-server.sh
Executable file
79
docker/scripts/api-server.sh
Executable file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Simple API server for PBS Client container management
|
||||||
|
# Provides REST endpoints for status, manual backup, etc.
|
||||||
|
|
||||||
|
PORT=${API_PORT:-8080}
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[API] [$(date +'%Y-%m-%d %H:%M:%S')] $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to handle HTTP requests
|
||||||
|
handle_request() {
|
||||||
|
local method="$1"
|
||||||
|
local path="$2"
|
||||||
|
|
||||||
|
case "$path" in
|
||||||
|
/status)
|
||||||
|
if [ -f /logs/status.json ]; then
|
||||||
|
cat /logs/status.json
|
||||||
|
else
|
||||||
|
echo '{"error":"No backup status available"}'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
/health)
|
||||||
|
if /usr/local/bin/healthcheck >/dev/null 2>&1; then
|
||||||
|
echo '{"status":"healthy"}'
|
||||||
|
else
|
||||||
|
echo '{"status":"unhealthy"}'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
/backup)
|
||||||
|
if [ "$method" = "POST" ]; then
|
||||||
|
echo '{"status":"starting","message":"Backup triggered"}'
|
||||||
|
/usr/local/bin/pbs-backup &
|
||||||
|
else
|
||||||
|
echo '{"error":"Use POST method to trigger backup"}'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
/logs)
|
||||||
|
if [ -f /logs/last-backup.log ]; then
|
||||||
|
tail -n 50 /logs/last-backup.log | jq -R -s -c 'split("\n")'
|
||||||
|
else
|
||||||
|
echo '{"logs":[]}'
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo '{"error":"Not found","available_endpoints":["/status","/health","/backup","/logs"]}'
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Simple HTTP server using nc
|
||||||
|
log "Starting API server on port $PORT"
|
||||||
|
|
||||||
|
while true; do
|
||||||
|
{
|
||||||
|
read -r method path protocol
|
||||||
|
|
||||||
|
# Read headers (discard)
|
||||||
|
while read -r line; do
|
||||||
|
[ -z "$line" ] || [ "$line" = $'\r' ] && break
|
||||||
|
done
|
||||||
|
|
||||||
|
# Generate response
|
||||||
|
RESPONSE=$(handle_request "$method" "$path")
|
||||||
|
CONTENT_LENGTH=${#RESPONSE}
|
||||||
|
|
||||||
|
# Send HTTP response
|
||||||
|
cat << EOF
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Content-Type: application/json
|
||||||
|
Content-Length: $CONTENT_LENGTH
|
||||||
|
Access-Control-Allow-Origin: *
|
||||||
|
Connection: close
|
||||||
|
|
||||||
|
$RESPONSE
|
||||||
|
EOF
|
||||||
|
} | nc -l -p $PORT -q 1
|
||||||
|
done
|
||||||
117
docker/scripts/backup.sh
Executable file
117
docker/scripts/backup.sh
Executable file
|
|
@ -0,0 +1,117 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# PBS Backup Script - Runs inside Docker container
|
||||||
|
# Backs up mounted host filesystem
|
||||||
|
|
||||||
|
HOSTNAME=${CONTAINER_HOSTNAME:-$(hostname)}
|
||||||
|
LOG_FILE="/logs/last-backup.log"
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1" | tee -a "$LOG_FILE" >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Parse backup paths into array
|
||||||
|
IFS=' ' read -ra PATHS <<< "$BACKUP_PATHS"
|
||||||
|
IFS=' ' read -ra EXCLUDES <<< "$EXCLUDE_PATTERNS"
|
||||||
|
|
||||||
|
# Validate backup paths exist
|
||||||
|
for path in "${PATHS[@]}"; do
|
||||||
|
if [ ! -e "$path" ]; then
|
||||||
|
error "Backup path does not exist: $path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
log "========================================="
|
||||||
|
log "Starting backup for $HOSTNAME"
|
||||||
|
log "========================================="
|
||||||
|
log "Paths: ${PATHS[*]}"
|
||||||
|
log "Excludes: ${EXCLUDES[*]}"
|
||||||
|
|
||||||
|
# Build backup command
|
||||||
|
BACKUP_CMD="proxmox-backup-client backup"
|
||||||
|
|
||||||
|
# Add each path as separate archive
|
||||||
|
for path in "${PATHS[@]}"; do
|
||||||
|
# Sanitize path for archive name
|
||||||
|
# /host-data/home -> home.pxar
|
||||||
|
# /host-data -> root.pxar
|
||||||
|
archive_name=$(echo "$path" | sed 's/^\/host-data\///' | sed 's/\//-/g')
|
||||||
|
[ -z "$archive_name" ] && archive_name="root"
|
||||||
|
[ "$archive_name" = "host-data" ] && archive_name="root"
|
||||||
|
|
||||||
|
BACKUP_CMD="$BACKUP_CMD ${archive_name}.pxar:${path}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add exclusions
|
||||||
|
for pattern in "${EXCLUDES[@]}"; do
|
||||||
|
BACKUP_CMD="$BACKUP_CMD --exclude=${pattern}"
|
||||||
|
done
|
||||||
|
|
||||||
|
# Add options
|
||||||
|
BACKUP_CMD="$BACKUP_CMD --skip-lost-and-found"
|
||||||
|
|
||||||
|
# Use metadata change detection if not first backup
|
||||||
|
if proxmox-backup-client snapshot list 2>/dev/null | grep -q "$HOSTNAME"; then
|
||||||
|
BACKUP_CMD="$BACKUP_CMD --change-detection-mode=metadata"
|
||||||
|
log "Using metadata change detection (incremental)"
|
||||||
|
else
|
||||||
|
log "First backup - reading all files"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Execute backup
|
||||||
|
log "Executing backup command..."
|
||||||
|
if eval $BACKUP_CMD 2>&1 | tee -a "$LOG_FILE"; then
|
||||||
|
log "Backup completed successfully"
|
||||||
|
BACKUP_SUCCESS=true
|
||||||
|
else
|
||||||
|
error "Backup FAILED"
|
||||||
|
BACKUP_SUCCESS=false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Prune old backups
|
||||||
|
if [ "$BACKUP_SUCCESS" = true ] && [ "${ENABLE_PRUNE:-true}" = "true" ]; then
|
||||||
|
log "Pruning old backups..."
|
||||||
|
|
||||||
|
# Use environment variables or defaults
|
||||||
|
KEEP_LAST=${KEEP_LAST:-3}
|
||||||
|
KEEP_DAILY=${KEEP_DAILY:-7}
|
||||||
|
KEEP_WEEKLY=${KEEP_WEEKLY:-4}
|
||||||
|
KEEP_MONTHLY=${KEEP_MONTHLY:-6}
|
||||||
|
|
||||||
|
if proxmox-backup-client prune "host/${HOSTNAME}" \
|
||||||
|
--keep-last "$KEEP_LAST" \
|
||||||
|
--keep-daily "$KEEP_DAILY" \
|
||||||
|
--keep-weekly "$KEEP_WEEKLY" \
|
||||||
|
--keep-monthly "$KEEP_MONTHLY" 2>&1 | tee -a "$LOG_FILE"; then
|
||||||
|
log "Prune completed successfully"
|
||||||
|
else
|
||||||
|
error "Prune failed"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Save stats
|
||||||
|
log "========================================="
|
||||||
|
log "Backup session completed"
|
||||||
|
log "========================================="
|
||||||
|
|
||||||
|
# Update status file
|
||||||
|
cat > /logs/status.json << EOF
|
||||||
|
{
|
||||||
|
"last_backup": "$(date -Iseconds)",
|
||||||
|
"hostname": "$HOSTNAME",
|
||||||
|
"success": $BACKUP_SUCCESS,
|
||||||
|
"paths": ${PATHS[@]@json}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ "$BACKUP_SUCCESS" = true ]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
180
docker/scripts/entrypoint.sh
Executable file
180
docker/scripts/entrypoint.sh
Executable file
|
|
@ -0,0 +1,180 @@
|
||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Entrypoint for PBS Client Docker Container
|
||||||
|
# Handles both daemon mode (continuous with cron) and one-shot backup mode
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" | tee -a /logs/container.log
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo "[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1" | tee -a /logs/container.log >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set timezone
|
||||||
|
if [ -n "$TIMEZONE" ]; then
|
||||||
|
ln -snf /usr/share/zoneinfo/$TIMEZONE /etc/localtime
|
||||||
|
echo $TIMEZONE > /etc/timezone
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Validate required environment variables
|
||||||
|
validate_config() {
|
||||||
|
if [ -z "$PBS_REPOSITORY" ]; then
|
||||||
|
error "PBS_REPOSITORY environment variable is required"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$PBS_PASSWORD" ]; then
|
||||||
|
error "PBS_PASSWORD environment variable is required"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Initialize encryption key if not exists
|
||||||
|
init_encryption() {
|
||||||
|
if [ ! -f /config/encryption-key.json ]; then
|
||||||
|
log "Generating encryption key..."
|
||||||
|
mkdir -p /config
|
||||||
|
proxmox-backup-client key create --kdf none 2>/dev/null || true
|
||||||
|
|
||||||
|
# Copy to persistent config volume
|
||||||
|
if [ -f /root/.config/proxmox-backup/encryption-key.json ]; then
|
||||||
|
cp /root/.config/proxmox-backup/encryption-key.json /config/
|
||||||
|
log "Encryption key created and saved to /config/"
|
||||||
|
|
||||||
|
# Create paper backup
|
||||||
|
proxmox-backup-client key paperkey --output-format text > /config/encryption-key-paper.txt
|
||||||
|
log "Paper backup created: /config/encryption-key-paper.txt"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
log "Using existing encryption key from /config/"
|
||||||
|
mkdir -p /root/.config/proxmox-backup
|
||||||
|
cp /config/encryption-key.json /root/.config/proxmox-backup/
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Setup cron for daemon mode
|
||||||
|
setup_cron() {
|
||||||
|
log "Setting up cron schedule: $BACKUP_SCHEDULE"
|
||||||
|
|
||||||
|
# Create cron job
|
||||||
|
cat > /etc/cron.d/pbs-backup << EOF
|
||||||
|
# PBS Backup Schedule
|
||||||
|
SHELL=/bin/bash
|
||||||
|
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||||
|
PBS_REPOSITORY=$PBS_REPOSITORY
|
||||||
|
PBS_PASSWORD=$PBS_PASSWORD
|
||||||
|
|
||||||
|
$BACKUP_SCHEDULE root /usr/local/bin/pbs-backup >> /logs/cron.log 2>&1
|
||||||
|
EOF
|
||||||
|
|
||||||
|
chmod 0644 /etc/cron.d/pbs-backup
|
||||||
|
|
||||||
|
# Apply cron environment
|
||||||
|
printenv | grep -v "no_proxy" >> /etc/environment
|
||||||
|
|
||||||
|
log "Cron configured successfully"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start daemon mode
|
||||||
|
start_daemon() {
|
||||||
|
log "Starting PBS Client in daemon mode"
|
||||||
|
log "Backup schedule: $BACKUP_SCHEDULE"
|
||||||
|
log "Monitoring logs at /logs/"
|
||||||
|
|
||||||
|
validate_config || exit 1
|
||||||
|
init_encryption
|
||||||
|
setup_cron
|
||||||
|
|
||||||
|
# Start API server if enabled
|
||||||
|
if [ "$ENABLE_API" = "true" ]; then
|
||||||
|
log "Starting API server on port 8080"
|
||||||
|
/usr/local/bin/api-server &
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Start cron in foreground
|
||||||
|
log "Starting cron daemon..."
|
||||||
|
cron -f
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run one-shot backup
|
||||||
|
run_backup() {
|
||||||
|
log "Running one-shot backup"
|
||||||
|
|
||||||
|
validate_config || exit 1
|
||||||
|
init_encryption
|
||||||
|
|
||||||
|
# Export for PBS client
|
||||||
|
export PBS_REPOSITORY
|
||||||
|
export PBS_PASSWORD
|
||||||
|
|
||||||
|
# Run backup
|
||||||
|
/usr/local/bin/pbs-backup
|
||||||
|
}
|
||||||
|
|
||||||
|
# Test connection
|
||||||
|
test_connection() {
|
||||||
|
log "Testing connection to PBS server..."
|
||||||
|
|
||||||
|
validate_config || exit 1
|
||||||
|
|
||||||
|
export PBS_REPOSITORY
|
||||||
|
export PBS_PASSWORD
|
||||||
|
|
||||||
|
if proxmox-backup-client snapshot list >/dev/null 2>&1; then
|
||||||
|
log "Connection test successful!"
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
error "Connection test failed"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show status
|
||||||
|
show_status() {
|
||||||
|
log "PBS Client Container Status"
|
||||||
|
echo "=========================="
|
||||||
|
echo "Mode: $MODE"
|
||||||
|
echo "PBS Repository: $PBS_REPOSITORY"
|
||||||
|
echo "Backup Paths: $BACKUP_PATHS"
|
||||||
|
echo "Schedule: $BACKUP_SCHEDULE"
|
||||||
|
echo "Timezone: $TIMEZONE"
|
||||||
|
echo "=========================="
|
||||||
|
|
||||||
|
if [ "$MODE" = "daemon" ]; then
|
||||||
|
echo "Last backup:"
|
||||||
|
if [ -f /logs/last-backup.log ]; then
|
||||||
|
tail -5 /logs/last-backup.log
|
||||||
|
else
|
||||||
|
echo " No backups run yet"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main logic
|
||||||
|
case "${1:-$MODE}" in
|
||||||
|
daemon)
|
||||||
|
start_daemon
|
||||||
|
;;
|
||||||
|
backup)
|
||||||
|
run_backup
|
||||||
|
;;
|
||||||
|
test)
|
||||||
|
test_connection
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
show_status
|
||||||
|
;;
|
||||||
|
shell)
|
||||||
|
log "Starting interactive shell"
|
||||||
|
exec /bin/bash
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
error "Unknown command: $1"
|
||||||
|
echo "Usage: $0 {daemon|backup|test|status|shell}"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
44
docker/scripts/healthcheck.sh
Executable file
44
docker/scripts/healthcheck.sh
Executable file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Healthcheck script for Docker container
|
||||||
|
|
||||||
|
# Check if cron is running (daemon mode)
|
||||||
|
if [ "$MODE" = "daemon" ]; then
|
||||||
|
if ! pgrep -x "cron" > /dev/null; then
|
||||||
|
echo "Cron is not running"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if last backup was successful (if any backups have run)
|
||||||
|
if [ -f /logs/status.json ]; then
|
||||||
|
SUCCESS=$(jq -r '.success' /logs/status.json 2>/dev/null || echo "null")
|
||||||
|
if [ "$SUCCESS" = "false" ]; then
|
||||||
|
echo "Last backup failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if backup is too old (more than 48 hours)
|
||||||
|
LAST_BACKUP=$(jq -r '.last_backup' /logs/status.json 2>/dev/null || echo "")
|
||||||
|
if [ -n "$LAST_BACKUP" ]; then
|
||||||
|
LAST_TIMESTAMP=$(date -d "$LAST_BACKUP" +%s 2>/dev/null || echo "0")
|
||||||
|
CURRENT_TIMESTAMP=$(date +%s)
|
||||||
|
AGE=$((CURRENT_TIMESTAMP - LAST_TIMESTAMP))
|
||||||
|
|
||||||
|
# 48 hours = 172800 seconds
|
||||||
|
if [ $AGE -gt 172800 ]; then
|
||||||
|
echo "Last backup is too old (>48 hours)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if PBS connection is working (quick test)
|
||||||
|
export PBS_REPOSITORY
|
||||||
|
export PBS_PASSWORD
|
||||||
|
if ! timeout 5 proxmox-backup-client snapshot list >/dev/null 2>&1; then
|
||||||
|
echo "Cannot connect to PBS server"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Healthy"
|
||||||
|
exit 0
|
||||||
Loading…
Reference in a new issue