Skip to content

Cross-Server Restore

Cross-server restore is the path you take when the old server is dead, you’re migrating between VPS providers, or you’re cloning production into a staging panel. ProxPanel makes this nearly one-click on V2 backups (v1.0.208+) by embedding the source license key in the backup header so the destination can fetch the right decryption password from the license server.

This page is the operational walk-through. For backup creation and encryption format, see Backups & Recovery.

The .proisp.bak file is encrypted with a key derived from the originating server’s DB password, which is itself derived from the originating server’s license. A naive restore on a different server uses the new server’s DB password — and fails with decryption failed because the two passwords are different.

The fix is to identify which license originally encrypted the file, fetch that license’s DB password from the central license server, and decrypt with it.

┌──────────────────┐ ┌──────────────────────┐ ┌──────────────────┐
│ Old server │ │ license.proxrad.com │ │ New server │
│ license: PROXP-A│ │ │ │ license: PROXP-B│
│ │ │ PROXP-A → pwd_A │ │ │
│ Backup created │ │ PROXP-B → pwd_B │ │ Restore started │
│ encrypted_with │ ─────▶ │ │ ◀───── │ reads V2 header:│
│ pwd_A │ upload│ │ fetch │ LICENSE_KEY=A │
│ │ │ │ pwd_A │ │
│ │ │ │ ─────▶ │ decrypts with A │
└──────────────────┘ └──────────────────────┘ └──────────────────┘

Backups created since v1.0.208 prepend the source license key right after the magic header:

PROXPANEL_ENCRYPTED_BACKUP_V2\n
LICENSE_KEY=PROXP-XXXXX-XXXXX-XXXXX-XXXXX\n
<binary ciphertext>

When you restore, the destination server:

  1. Reads the first ~200 bytes.
  2. Sees the V2 magic.
  3. Extracts LICENSE_KEY=… (line 2).
  4. Calls GET https://license.proxrad.com/api/v1/license/backup-password with header X-License-Key: PROXP-A….
  5. License server returns {db_password: "…"} for that license.
  6. Derives the AES key, decrypts, restores into Postgres.

No user input required.

  1. On the old server, create a fresh full backup (Backups → Create Backup) and download the .proisp.bak file to your workstation.

  2. Install ProxPanel on the new server using curl -sL https://license.proxrad.com/install | bash -s -- NEW_LICENSE_KEY (a new, different license key is fine — V2 doesn’t require matching keys).

  3. Activate the new panel at least once so it’s recognised by the license server. Verify with curl -s https://NEW_SERVER/health.

  4. Upload the backup file via Backups → Upload Backup. The file lands in /var/backups/proisp/ on the new server.

  5. Click Restore on the uploaded file. Leave the Source License Key field empty — the system auto-detects.

  6. Wait for completion. A 30 K-subscriber dump takes 30–90 seconds. The page returns Restored successfully.

  7. Update MikroTik RADIUS targets to point to the new server’s IP: /radius set [find] address=NEW_IP.

  8. Update DNS for panel.example.com to the new IP. Customer portals continue to work the moment DNS propagates.

That’s it. The new server now serves the old data and continues to validate against the old license. If you want it to use the new license going forward, see “Re-binding licenses” below.

If your backup was created before v1.0.208, the header is just:

PROXPANEL_ENCRYPTED_BACKUP_V1\n
<binary ciphertext>

No license key embedded. On restore you must fill in the Source License Key field manually:

  1. Upload the V1 backup to the new server.

  2. Click Restore. In the modal, paste the source license key in the “Source License Key” field. (It’s PROXP-XXXXX-XXXXX-XXXXX-XXXXX, the one used to install the old panel.)

  3. Click Restore Backup. The destination fetches pwd for that license key from the license server and decrypts.

If you don’t have the source license key, contact info@proxrad.com with the file’s timestamp and source server IP — we can look it up in the license database.

Terminal window
# Upload the backup
curl -X POST -H "Authorization: Bearer $TOKEN" \
-F "file=@proisp_full_20260512_140530.proisp.bak" \
https://NEW_PANEL/api/backups/upload
# Restore (V2 — source key auto-detected)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"source_license_key":""}' \
https://NEW_PANEL/api/backups/proisp_full_20260512_140530.proisp.bak/restore
# Restore (V1 — source key required)
curl -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"source_license_key":"PROXP-OLD-LICENSE-KEY-HERE"}' \
https://NEW_PANEL/api/backups/proisp_full_20260512_140530.proisp.bak/restore

After a successful cross-server restore, the database (and so subscribers, services, NAS, FUP counters, transactions, invoices, audit log, settings) is whatever the old server had. But these things on the new server are unchanged:

ItemSource
Subscribers, services, RADIUS dataRestored from backup
Settings (timezone, branding, notification creds)Restored from backup
LICENSE_KEY in .envNew server’s own
HARDWARE_IDNew server’s own
Frontend logo / uploadsNot restored — needs separate tar -xzvf of /opt/proxpanel/frontend/dist/uploads/
TLS certificates (Let’s Encrypt)New server’s own
nginx.conf SSL configNew server’s own (preserved by install)

Uploads (logos, login background, favicon, customer-portal assets) are stored on the filesystem rather than in Postgres. You need to copy them across separately:

Terminal window
# On old server
tar -czvf /tmp/uploads.tar.gz /opt/proxpanel/frontend/dist/uploads/
scp /tmp/uploads.tar.gz root@NEW_SERVER:/tmp/
# On new server
tar -xzvf /tmp/uploads.tar.gz -C /
docker exec proxpanel-frontend nginx -s reload

For brand-new ProxPanel installs, the Settings → Cluster → Recover from Existing Server wizard automates the whole flow:

  1. Install fresh ProxPanel on the new hardware.

  2. Settings → Cluster → Recover from Existing Server.

  3. Enter the old server’s IP and root password (or SSH key).

  4. Click Test Connection. Should return API/DB/SSH reachable.

  5. Click Recover Data. Behind the scenes:

    • SSHes to the old server.
    • Runs pg_dump directly on the source.
    • Streams it to the new server.
    • Restores into the new Postgres.
    • Rsyncs /opt/proxpanel/frontend/dist/uploads/.
    • Configures the new server as the new main.
  6. Update MikroTik RADIUS IP. Done.

This is the recommended path for DR when the source is still online but going away — it skips the manual download/upload step entirely.

After a cross-server restore, the new panel still uses its own license key for validation but holds the old panel’s data. You have two choices:

Keep both licenses (recommended)

The old license stays bound to the old server’s hardware ID. The new license stays bound to the new server’s hardware ID. Each pays per its own activation. Data is on the new server; the old server is decommissioned.

If the old server is truly dead, ask info@proxrad.com to suspend that license so you’re not billed twice.

Migrate the old license to the new server

If you want the same license key to keep working (e.g. a customer-facing license number on contracts), an admin on the license server can re-bind:

Terminal window
# On the license server
docker exec proxpanel-license-db psql -U proxpanel -d proxpanel_license -c "
UPDATE licenses
SET hardware_id = NULL
WHERE license_key = 'PROXP-OLD-KEY';
"

Then on the new server, set LICENSE_KEY=PROXP-OLD-KEY in .env, restart the API container, and it’ll re-activate against the new hardware.

The new license you used for the install can then be cancelled or returned to support.

  • “License key required in X-License-Key header” (HTTP 400). V1 backup, empty Source License Key field. Fill in the source license key.
  • “Invalid license key” (HTTP 404) from /license/backup-password. Wrong source license key, or that license has been deleted from the license server.
  • “Database password not found for this license” (HTTP 404). Old license has no stored DB password — happens for installs older than v1.0.166 that never fetched secrets. Contact support.
  • “decryption failed - this backup may be from a different installation”. Salt mismatch (pre-v1.0.74 backup), or you entered the wrong source license key. Try the correct key, or rebuild the panel from a more recent backup.
  • Schema version mismatch. Restoring a v1.0.300 backup onto a v1.0.510 panel works because GORM auto-migrates new columns on startup. Restoring an OLD panel onto a NEW backup does not — install the same or newer version first.

backups.restore is required to perform a restore. It is destructive — the entire current database is overwritten. Most operators keep this admin-only and never grant it to resellers.

  • Backups & Recovery — file format, scheduling, encryption.
  • HA Cluster — for ongoing replication rather than ad-hoc restore, use streaming replication.
  • Failover — planned migration of a live cluster.
  • Updates — version compatibility for restore.