Backups & Recovery
ProxPanel backs up your entire Postgres database — subscribers, services, RADIUS check/reply, accounting records, transactions, invoices, settings — into a single encrypted file. There is no “config only” vs “full” split that matters for recovery; the encrypted .proisp.bak is what restores a server to working state.
Backups can be created manually from the UI, scheduled hourly/daily/weekly/monthly, and pushed to FTP or the ProxRad cloud-backup service. The file itself is AES-256-GCM encrypted with a key derived from your license, so it survives leaving your server without leaking subscriber data.
How to get here
Section titled “How to get here”Backups in the sidebar (admin only). The page has two tabs:
- Backups — list of files in
/var/backups/proisp/, with Download, Restore, Delete actions. - Schedules — cron-style rules for automated backups.
File format
Section titled “File format”proisp_full_20260512_140530.proisp.bak ← Postgres dump, AES-256-GCMproisp_data_20260512_140530.proisp.bak ← (legacy) subscriber tables onlyproisp_config_20260512_140530.proisp.bak ← (legacy) settings/users onlymikrotik_RouterName_20260512_140530.tar.gz ← RouterOS /export from MikroTikEvery .proisp.bak file starts with one of two magic headers:
| Header | Version | Cross-server restore |
|---|---|---|
PROXPANEL_ENCRYPTED_BACKUP_V1\n | Legacy (≤ v1.0.207) | Requires manually entering source license key on restore |
PROXPANEL_ENCRYPTED_BACKUP_V2\nLICENSE_KEY=PROXP-XXXXX-…\n | Current (v1.0.208+) | Fully automatic — license key embedded in header |
After the header, the rest of the file is AES-256-GCM ciphertext of a pg_dump -Fc (Postgres custom format, compressed binary). For the encryption-key derivation and cross-server flow, see Cross-Server Restore.
Encryption key derivation
Section titled “Encryption key derivation”key = SHA-256("ProxPanel-Backup-Encryption-2024" || DB_PASSWORD)The DB password is fetched from the license server on startup (see Secrets storage on the license server). This means:
- The same panel always re-derives the same key — restoring on the same server “just works”.
- A cloned
/var/backupsdirectory is useless without the license key. An attacker who steals the file but not the license cannot decrypt it. - Cross-server restore works because the V2 header includes the source license key; the destination panel can ask the license server for the source’s DB password.
Creating a manual backup
Section titled “Creating a manual backup”-
Click Backups in the sidebar.
-
Click Create Backup (top right). Confirm “Full backup” in the modal.
-
Wait 5–60 seconds depending on database size. The page refreshes when done.
-
The new file appears at the top of the list with size, timestamp, and an
[encrypted]badge.
Internally, this runs:
pg_dump -h db -U proxpanel -d proxpanel -Fc \ --exclude-table-data=radius_logs \ --exclude-table-data=radpostauth \ --exclude-table-data=cpe_tasks \ -f /var/backups/proisp/.temp_full_TIMESTAMP.dumpThen encrypts that temp file into the final .proisp.bak. The three excluded tables auto-prune to 30 days anyway — they’re noisy and re-populate from live RADIUS traffic, so they’d bloat the backup for zero recovery value.
Scheduled backups
Section titled “Scheduled backups”Backups → Schedules → New Schedule.
| Field | Notes |
|---|---|
| Name | Free-form, shown in logs. |
| Frequency | hourly / daily / weekly / monthly. |
| Day of week / Day of month | For weekly / monthly. |
| Time of day | HH:MM in your configured system timezone (Settings → System → Timezone). |
| Retention | Days to keep. Files older than this are deleted on each scheduler tick. |
| Storage | local only / local + ftp / local + cloud. |
The scheduler runs every 60 seconds (services/backup_scheduler.go) and picks up due schedules with a ±2 minute window so a brief API restart at 02:00 doesn’t miss the 02:00 schedule. A same-day deduplication check prevents two runs of the same schedule on the same day.
FTP destination
Section titled “FTP destination”Host: backup.example.com Port: 21Username: backupuser Password: ********Path: /proxpanel-backups/Passive: yes TLS (FTPS): optionalOn every run, the encrypted backup is created locally, then uploaded to the FTP server. Local copy is retained per the retention setting.
Cloud destination
Section titled “Cloud destination”Cloud is the ProxRad-managed backup service:
- Endpoint:
https://license.proxrad.com/api/v1/cloud-backup/upload - Authenticated with the panel’s license key.
- Encrypted file uploaded as-is; the license server stores it in object storage without ever holding the decryption key.
- Retention on the cloud side: 30 days (configurable by support).
This is the recommended off-server option for customers without their own FTP infrastructure.
Retention and disk usage
Section titled “Retention and disk usage”Local backups live in /var/backups/proisp/ on the host (bind-mounted into the API container). A 30 K-subscriber panel produces ~80–120 MB compressed per full backup; a daily backup with 30-day retention costs roughly 3 GB on disk.
The scheduler deletes files older than retention days at the end of each successful run. Manual backups are also subject to retention if they match the schedule’s filename prefix.
Restoring a backup
Section titled “Restoring a backup”Same-server restore (most common)
-
Backups page → find the file → click Restore.
-
Confirm “This will overwrite the current database” in the modal. The destination license key field can be left empty — the system auto-detects from the V2 header.
-
The API container stops accepting writes during restore (~30 s – 5 min depending on size).
-
When the page returns “Restored successfully”, refresh — your data is now whatever it was at the time of the backup.
V1 backup (legacy)
Backups created before v1.0.208 don’t embed the license key in the header. On restore:
- Open the Restore modal.
- Manually enter the Source License Key of the panel that created the backup.
- The system fetches that license’s DB password from the license server and uses it to decrypt.
If you don’t know the source license key, contact info@proxrad.com with the file timestamp — support can look it up from the upload logs if it was a cloud backup.
Different server (cross-server restore)
This is the migration / disaster-recovery path. The destination server’s license key is automatically replaced with the source’s during restore. See the dedicated Cross-Server Restore page.
SaaS mode — tenant isolation
Section titled “SaaS mode — tenant isolation”When SAAS_MODE=true, backups are per-tenant:
- Scheduler iterates
admin.tenantsand runs each tenant’s schedules in its own schema (tenant_xxx.backup_schedules). - Each backup file is named
tenant_xxx_full_TIMESTAMP.proisp.bakand contains only that tenant’s schema, dumped withpg_dump --schema=tenant_xxx. - Cloud uploads include the tenant ID in the metadata so the SaaS admin UI can list per-tenant backups.
- A tenant restoring “their” backup overwrites only their schema, never the global
admin.*tables.
Tenants cannot see other tenants’ backups in their UI. The platform admin (super-admin) can see all of them via the admin panel.
MikroTik backups
Section titled “MikroTik backups”The MikroTik Backup button (top of the Backups page) connects to a NAS over the RouterOS API and runs:
/export file=proxpanel-backup-TIMESTAMP/file fetchThe exported config is pulled to /var/backups/proisp/mikrotik_RouterName_TIMESTAMP.tar.gz. This is a plain MikroTik config dump, not encrypted (RouterOS exports already redact API passwords and user passwords with 0x...).
Use it to capture interface configs, queue trees, firewall rules, and IP pools so you can rebuild a router from scratch after hardware failure.
CLI inspection
Section titled “CLI inspection”# List backups on the hostls -lah /var/backups/proisp/
# Inspect the magic header of a backuphead -c 60 /var/backups/proisp/proisp_full_20260512_140530.proisp.bak# → PROXPANEL_ENCRYPTED_BACKUP_V2# → LICENSE_KEY=PROXP-XXXXX-XXXXX-XXXXX-XXXXX# → <binary ciphertext>
# Tail the scheduler logdocker logs proxpanel-api 2>&1 | grep BackupScheduler
# Trigger a manual backup via APIcurl -s -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"type":"full"}' \ http://localhost/api/backups | jqCommon pitfalls
Section titled “Common pitfalls”- “Failed to decrypt backup” on same server. DB password changed between backup creation and restore — usually because the panel was reinstalled. Restore using the source license key (cross-server flow).
pg_dump: error: server version: 16.X; pg_dump version: 14.X. The API container uses the wrong Postgres client. The install script pinspostgresql-client-16— if you skipped that step, rundocker exec proxpanel-api apt-get install -y postgresql-client-16and restart the container.- Backups appear in the UI but not in
/var/backups/proisp/. The bind-mount is broken. Checkdocker inspect proxpanel-api | grep -A 3 Mountsshows/var/backups/proispmapped to a host directory. - Scheduler skips runs. Check the configured timezone —
system_preferences.system_timezonemust be a valid Go timezone likeEurope/Berlin, not justCET. Withouttzdatain the API container the scheduler falls back to UTC and runs everything 0–12 hours off. - Cloud upload fails with 401. License key changed (re-activation, hardware migration). Re-validate the license from Settings → License, then trigger a manual scheduled-backup run.
Permissions
Section titled “Permissions”backups.view— see the Backups page.backups.create— create manual backups.backups.restore— restore a backup (destructive).backups.delete— remove backup files.backups.edit— manage schedules.
Resellers can be granted these permissions individually. Most operators give resellers backups.view only and keep restore/delete admin-only.
Related pages
Section titled “Related pages”- Cross-Server Restore — the V2 auto-detect flow in detail.
- Updates — pre-update backup is taken automatically and used for rollback on failure.
- HA Cluster — clustered deployments still need application backups; streaming replication doesn’t protect you from
DROP TABLE.