186 lines
4.8 KiB
Markdown
186 lines
4.8 KiB
Markdown
# PVE Cloud Backup
|
|
|
|
Self-hosted Proxmox VE backup manager for uploads to an existing rclone remote such as OneDrive.
|
|
|
|
The application is intentionally small:
|
|
|
|
- FastAPI backend and worker
|
|
- Vue 3 + TypeScript + Tailwind frontend, compiled once into `static/`
|
|
- SQLite for all runtime configuration and state
|
|
- `pvesh` for Proxmox API access
|
|
- `rclone copyto`, `rclone lsjson`, `rclone deletefile`, and `rclone rmdir` for exact remote objects and empty per-backup folders
|
|
- systemd services, no Docker
|
|
|
|
## Layout
|
|
|
|
All application files live under:
|
|
|
|
```text
|
|
/opt/pve-cloud-backup/
|
|
backend/
|
|
frontend/
|
|
static/
|
|
data/
|
|
app.db
|
|
logs/
|
|
scripts/
|
|
```
|
|
|
|
The install script copies the two systemd service files to `/etc/systemd/system/`.
|
|
|
|
## Prerequisites
|
|
|
|
Install these on the Proxmox host:
|
|
|
|
- Python 3 with `venv`
|
|
- Node.js and npm for the one-time frontend build
|
|
- `rclone`
|
|
- a preconfigured rclone remote, for example OneDrive or a crypt remote backed by OneDrive
|
|
- working `pvesh` access as the service user
|
|
|
|
The app does not configure rclone. If no remote exists, setup fails until you configure rclone yourself.
|
|
|
|
## Install
|
|
|
|
From the installation directory:
|
|
|
|
```bash
|
|
cd /opt/pve-cloud-backup
|
|
./scripts/install.sh
|
|
```
|
|
|
|
The installer:
|
|
|
|
1. creates required subdirectories,
|
|
2. creates a Python virtual environment,
|
|
3. installs Python dependencies,
|
|
4. builds the Vue frontend into `/opt/pve-cloud-backup/static`,
|
|
5. initializes SQLite migrations,
|
|
6. installs and starts systemd services.
|
|
|
|
Open:
|
|
|
|
```text
|
|
http://<proxmox-host>:8080
|
|
```
|
|
|
|
## Setup
|
|
|
|
On first launch, complete the setup wizard:
|
|
|
|
- Proxmox node
|
|
- Proxmox backup storage
|
|
- local backup directory
|
|
- rclone executable path
|
|
- rclone remote name
|
|
- remote backup path/folder within that remote
|
|
- Discord webhook URL
|
|
- allowed CORS origins
|
|
- default compression
|
|
- default backup mode
|
|
- default retention policy
|
|
- max concurrent backups
|
|
|
|
All settings are stored in SQLite at `/opt/pve-cloud-backup/data/app.db`.
|
|
|
|
## Recovery behavior
|
|
|
|
On worker startup, unfinished records in these states are reconciled:
|
|
|
|
- `pve_running`
|
|
- `local_ready`
|
|
- `uploading`
|
|
- `remote_ready`
|
|
- `local_deleting`
|
|
- `deleting`
|
|
|
|
The worker does not delete unknown local files or remote objects. Local archives are deleted only after upload finishes and the remote object is verified.
|
|
|
|
## Retention cleanup
|
|
|
|
Retention cleanup runs in two places:
|
|
|
|
- immediately after a backup completes for that job;
|
|
- periodically from the worker service, once per hour, so changed rules and day-based expiry are enforced even if no new backup runs.
|
|
|
|
Remote deletion uses exact-object `rclone deletefile` calls for backup records already known in SQLite, then best-effort `rclone rmdir` cleanup for the empty per-backup folder.
|
|
|
|
## Testing
|
|
|
|
Run backend tests:
|
|
|
|
```bash
|
|
cd /opt/pve-cloud-backup/backend
|
|
./.venv/bin/pytest
|
|
```
|
|
|
|
Run frontend type check and build:
|
|
|
|
```bash
|
|
cd /opt/pve-cloud-backup/frontend
|
|
npm run build
|
|
```
|
|
|
|
Manual integration test against a real Proxmox guest:
|
|
|
|
```bash
|
|
INTEGRATION_VMID=<vmid> API_URL=http://127.0.0.1:8080 /opt/pve-cloud-backup/scripts/integration-test.sh
|
|
```
|
|
|
|
Optional environment variables:
|
|
|
|
- `INTEGRATION_GUEST_NAME` to assert the discovered guest name before queueing.
|
|
- `INTEGRATION_STORAGE` to override the configured Proxmox backup storage.
|
|
- `INTEGRATION_LOCAL_BACKUP_DIR` to assert the configured local dump directory.
|
|
- `INTEGRATION_CRON` to choose the created job schedule. Default: `0 3 * * *`.
|
|
- `INTEGRATION_RUN_NOW=0` to create the job without immediately queueing it.
|
|
|
|
The script creates a disabled backup job and, by default, queues it once. Only run it when you intentionally want a real Proxmox backup and rclone upload.
|
|
|
|
## CI
|
|
|
|
Gitea Actions workflow:
|
|
|
|
```text
|
|
.gitea/workflows/ci.yml
|
|
```
|
|
|
|
It runs on pushes and pull requests to `main` and can also be started manually. The workflow checks:
|
|
|
|
- backend dependency install and pytest;
|
|
- frontend dependency install and production build;
|
|
- shell script syntax.
|
|
|
|
Package caches are enabled through the Gitea Actions cache-compatible setup actions:
|
|
|
|
- Python/pip cache keyed by `backend/requirements.txt`;
|
|
- npm cache keyed by `frontend/package-lock.json`.
|
|
|
|
The Gitea runner must have action cache support configured for cache restore/save to work.
|
|
|
|
## Updates
|
|
|
|
After pulling new code, apply it with:
|
|
|
|
```bash
|
|
cd /opt/pve-cloud-backup
|
|
git pull --ff-only
|
|
./scripts/apply-update.sh
|
|
```
|
|
|
|
For a stricter update that runs backend tests before restarting services:
|
|
|
|
```bash
|
|
RUN_TESTS=1 ./scripts/apply-update.sh
|
|
```
|
|
|
|
The update script backs up `data/app.db`, rebuilds dependencies/assets, runs migrations, installs service units, restarts services, and checks API health.
|
|
|
|
## Uninstall
|
|
|
|
```bash
|
|
/opt/pve-cloud-backup/scripts/uninstall.sh
|
|
```
|
|
|
|
The uninstall script removes and disables systemd services. It leaves `/opt/pve-cloud-backup` intact so `app.db`, logs, and any remaining data are not destroyed accidentally.
|