-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Feat: backup and restore #5183
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Feat: backup and restore #5183
Conversation
d4b06c5 to
79ac534
Compare
|
@jc21 the jenkins job has been stuck running for 6+ hours but failed to install cypress, are you able to stop it running? there does not appear to be a configured global timeout. |
ee0dd42 to
39442bc
Compare
|
every time I trigger the CI it fails in a different area. i have squashed and force pushed without any actual changes. Run 6 is now failing on a random apt install because of unexpected file sizes. I'm running out of ideas here. as far as I'm concerned the CI tests are all passing and this is definitely ready for review/integration. |
39442bc to
4aaff28
Compare
|
CI Error: |
4aaff28 to
9e92551
Compare
|
no changes, just a new force push. CI run 7 fails again in a different area. 🤞 for run 8 |
9e92551 to
e69d09f
Compare
Backup and Restore Feature for Nginx Proxy Manager
Overview
This contribution adds a complete backup and restore system to Nginx Proxy Manager, enabling administrators to export their entire configuration to a portable ZIP archive and restore it on the same or different instance.
The backup format is database-agnostic, allowing migration between any supported database backend (SQLite, MySQL, PostgreSQL).
The feature preserves all database records, SSL certificates (Let's Encrypt and custom), access list credentials, and automatically regenerates nginx configurations upon restore.
PR Notes
I created this because I run NPM in various places and have been bitten by things suddenly breaking, usually on upgrade. I know there are manual ways to completely backup the data and lets-encrypt folders but I wanted something native that was quick and easy while still doing it "right".
I have tested this for about a week locally, more testers are always good, but I believe it is ready for PR.
I understand this is a large one, and hopefully that wont put you off considering it.
I have not contributed to this repository before, so please forgive me if I have done something incorrectly (coding standards, etc).
I welcome your feedback!
Features
Export Functionality
Import Functionality
Audit Logging
Screenshots
Architecture
Backend Components
backend/internal/backup.js - Core backup logic
Key constants:
BACKUP_VERSION- Format version for compatibility checkingTABLE_CONFIG- Defines export/import order respecting foreign key dependenciesDELETE_TABLE_ORDER- Reverse order for safe deletionJSON_FIELDS- Fields requiring serialization for raw knex insertsKey functions:
exportAll()- Creates backup ZIP with database JSON and certificate filesimportAll()- Entry point for restore operationperformImport()- Clears database, restores files, imports tablescreateBackupZip()- Assembles ZIP archive with all componentsextractZipDirectory()- Extracts ZIP with optional password supportrestoreCertificateFiles()- Restores Let's Encrypt and custom SSL filescreateLiveSymlinks()- Recreates certbot-style symlinks from archive to liverestoreAccessListFiles()- Restores htpasswd filespurgeNginxConfigs()/purgeCertificateFiles()/purgeAccessListFiles()- Pre-import cleanupregenerateNginxConfigs()- Rebuilds all nginx configs post-importbackend/routes/backup.js - REST API endpoints
GET /api/backup/export- Download backup (5 minute timeout)POST /api/backup/import- Upload and restore backup (10 minute timeout)Frontend Components
frontend/src/pages/Settings/Backup.tsx - React UI component
frontend/src/api/backend/backup.ts - API client functions
exportBackup()- Downloads backup via blob responseimportBackup()- Uploads backup via FormDatafrontend/src/hooks/useBackup.ts - React Query mutations
useExportBackup()- Handles export with loading stateuseImportBackup()- Handles import with automatic logout on successDatabase Tables Handled
In dependency order:
Audit log is cleared but not exported (fresh start on restore).
Dependencies Added
{ "archiver": "^5.3.0", "archiver-zip-encrypted": "^2.0.0", "unzipper": "^0.12.3" }Note: The implementation uses ZipCrypto (zip20) encryption rather than AES-256 because the unzipper library only supports legacy ZIP encryption for extraction.
File Structure in Backup ZIP
Implementation Details
Raw Knex Inserts
The import uses raw knex inserts instead of Objection.js model methods to:
$beforeInserthooks that would re-hash)JSON fields are manually stringified before insert since raw knex does not handle object serialization.
Symlink Recreation
Let's Encrypt certificates use a live/archive directory structure where live contains symlinks to the latest versioned files in archive. The restore process:
fullchain1.pem,fullchain2.pem)fullchain.pem -> ../../archive/npm-X/fullchain2.pem)Session Handling
After successful import:
Files Modified/Added
Localization Strings Added
The following i18n keys were added to
frontend/src/locale/src/en.json:object.event.exportedobject.event.importedsettings.backupsettings.backup.export.buttonsettings.backup.export.descriptionsettings.backup.export.password.confirmsettings.backup.export.password.enablesettings.backup.export.password.labelsettings.backup.export.password.mismatchsettings.backup.export.secrets-warningsettings.backup.export.successsettings.backup.export.titlesettings.backup.import.confirm.buttonsettings.backup.import.confirm.filesettings.backup.import.confirm.logoutsettings.backup.import.confirm.messagesettings.backup.import.confirm.titlesettings.backup.import.confirm.warningsettings.backup.import.descriptionsettings.backup.import.password.hintsettings.backup.import.password.labelsettings.backup.import.progresssettings.backup.import.successsettings.backup.import.titlesettings.backup.import.warningSecurity Considerations
settings:update(admin) permissionTesting
Cypress E2E Test
test/cypress/e2e/api/Backup.cy.js - Full backup/restore cycle test
The test performs a complete integration test of the backup feature:
Setup Phase: Creates one resource of every type:
Export Phase: Downloads backup ZIP and stores it in memory
Deletion Phase: Deletes all created resources to simulate data loss
Import Phase: Uploads the backup ZIP to restore all data
Verification Phase: Re-authenticates and verifies all resources were restored with correct data
Cleanup Phase: Deletes all restored resources in the
after()hook to ensure subsequent test suites start with a clean database stateTest Infrastructure Modifications
test/cypress/plugins/backendApi/client.js - Added buffer handling methods:
getBuffer(path)postBuffer(path, buffer, fieldName, fileName)test/cypress/plugins/backendApi/task.js - Added Cypress tasks:
backendApiGetBuffer{data: number[], length: number}for Cypress serializationbackendApiPostBufferNote: Cypress tasks cannot pass Buffer objects directly between the Node.js plugin process and the browser, so the buffer is converted to/from a number array for serialization.
Linked issues
#2109 #4373 #4752