Files
itpp-docs/docs-source/itpp-infrastructure/backup-restore/ARCHITECTURE.md
T
Germaine Brown 98073dc636
Publish Docs Site / build (push) Failing after 5s
feat: initial itpp-docs setup with MkDocs Material
- mkdocs.yml with dark slate theme, nav for 12 ITPP projects
- build-docs.sh aggregates docs from all project repos
- .gitea/workflows/docs-publish.yml for nightly rebuild+deploy
- README and CHANGELOG for the itpp-docs repo itself
- docs-source/ populated from all 12 repos
- site/ ready for deployment to docs.itpropartner.com
2026-08-09 23:49:45 -04:00

6.0 KiB

Backup-Restore — Architecture

Topology

                         INTERNET
                            |
                    [Caddy on Core]
                   my.itpropartner.com
                            |
            +---------------+---------------+
            |               |               |
     /backups/*      /api/restore    /api/backup
     /api/log        /api/download   /api/delete
            |               |               |
            +-------+-------+-------+-------+
                            |
                    app3 (152.53.241.111)
                     netcup RS 4000
                            |
                    [Flask :8090]
                   /opt/backup-restore/
                            |
        +-------------------+-------------------+
        |                   |                   |
  snapshot.sh         app.py (UI+API)     snapshots/
  (cron 1AM,1PM)      Jinja templates     /opt/backup-restore/
        |                   |              snapshots/<domain>/
        v                   v                   |
  [tar files]          [render HTML]     +------+------+
  [mysqldump]          [REST API]        |      |      |
        |                   |          .tar.gz  .sql  note.txt
        v                   v
  /opt/backup-restore/  [Browser]
  snapshots/<domain>/
  <timestamp>/

Data Flow — Manual Backup

Browser (user clicks "Backup Now")
  |
  |-- POST /api/backup {"domain":"x.com","note":"pre-deploy"}
  |       |
  |       v
  |   Caddy → app3:8090
  |       |
  |       v
  |   Flask api_backup()
  |       |
  |       |-- Parse nginx config → find htdocs path
  |       |-- tar -czf files.tar.gz (timeout 300s)
  |       |-- Parse wp-config.php → find DB_NAME
  |       |-- mysqldump → database.sql (timeout 300s)
  |       |-- Save note.txt, size.txt
  |       |-- Return {"ok":true, "snapshot":"<timestamp>"}
  |       |
  |       v
  |   snapshots/x.com/2026-07-20_163208/
  |       files.tar.gz (16MB)
  |       database.sql (74KB)
  |       note.txt ("pre-deploy")
  |       size.txt
  |
  v
Browser reloads → new snapshot in list

Data Flow — Restore

Browser (user clicks Restore on a snapshot)
  |
  |-- POST /api/restore {"domain":"x.com","snapshot":"2026-07-20_130001"}
  |       |
  |       v
  |   Caddy → app3:8090 (flush_interval -1, 300s timeouts)
  |       |
  |       v
  |   Flask api_restore()
  |       |
  |       |-- Find snapshot path
  |       |-- tar -xzf files.tar.gz → htdocs (timeout 300s)
  |       |-- mysql < database.sql → WordPress DB (timeout 300s)
  |       |-- chown -R site-user:site-user
  |       |-- Log to restore.log: "TS|x.com|snap_id|OK"
  |       |-- Return {"ok":true, "msg":"x.com restored to <snap>"}
  |       |
  |       v
  |   Site is restored
  |
  v
Browser shows success toast → Restore History updates

Components

1. Flask App (/opt/backup-restore/app/app.py)

  • Single-file Flask application, port 8090
  • Jinja2 templating for backup dashboard (render_template_string)
  • 6 API endpoints (backup, restore, delete, download, log, index)
  • All HTML/CSS/JS inline in a single Python triple-quoted string
  • No auth — accessible via Caddy-only routing
  • Systemd: backup-restore.service

2. Snapshot Engine (/opt/backup-restore/snapshot.sh)

  • Bash script, runs at 1 AM and 1 PM via cron
  • Iterates all WordPress sites in /etc/nginx/sites-enabled/
  • Creates: files.tar.gz (document root), database.sql (MySQL dump)
  • Auto-cleanup: deletes snapshots older than 30 days
  • Log: /opt/backup-restore/logs/snapshots.log

3. Snapshot Storage (/opt/backup-restore/snapshots/)

  • Structure: /<domain>/<YYYY-MM-DD_HHMMSS>/
  • 9 WordPress domains, 10 snapshots each (10 days retention shown)
  • Average snapshot size: 16MB files + 74KB database
  • Total: ~1.4GB for full snapshot set

4. Restore Log (/opt/backup-restore/logs/restore.log)

  • Pipe-delimited format: timestamp|domain|snapshot_id|status
  • Written by api_restore() on every restore attempt
  • Read by /api/log → displayed in Restore History table
  • Last 50 entries retained

5. Caddy Proxy (on Core)

  • handle /api/backup → app3:8090
  • handle /api/restore → app3:8090 (flush_interval -1, 300s read/write timeouts)
  • handle /api/download/* → app3:8090
  • handle /api/log → app3:8090
  • handle_path /backups/* → app3:8090 (300s timeouts for long restores)
  • Domain: my.itpropartner.com

9 Hosted WordPress Sites

All served by CloudPanel on app3, backed up by this system:

Domain htdocs Path DB Pattern
apextrackexperience.com /home/apx/htdocs/apextrackexperience.com wp-config DB_NAME
boxpilotlogistics.com /home/boxpilotlogistics/htdocs/boxpilotlogistics.com wp-config DB_NAME
debtrecoveryexperts.com /home/debtrecoveryexperts/... wp-config DB_NAME
iamgmb.com /home/iamgmb/... wp-config DB_NAME
katiewattdesign.com /home/katiewattdesign/htdocs/katiewattdesign.com wp-config DB_NAME
katiewattsdesign.com /home/katiewattsdesign/... wp-config DB_NAME
mainwp.itpropartner.com /home/mainwp/... wp-config DB_NAME
vigilanttac.com /home/vigilanttac/... wp-config DB_NAME
voipsimplicity.com /home/voipsimplicity/... wp-config DB_NAME

Key Design Decisions

  1. Single-file Flask app: No package structure needed — the app has 6 endpoints and one HTML template. Keeping it in one file makes deployment trivial (scp + systemctl restart).

  2. Caddy on Core as single entry point: app3 isn't exposed to the internet directly. All access goes through Core's Caddy with proper timeouts. The restore operation takes 30-45s and Caddy's default proxy timeout was killing connections mid-operation.

  3. Tar + mysqldump over rsync: Snapshots are point-in-time archives, not incremental backups. Each snapshot is self-contained (files.tar.gz + database.sql). Restore is a single operation with no dependency chain.

  4. No auth on backup API: The endpoints have no authentication. Access is controlled by Caddy routing — only requests through my.itpropartner.com reach the app. Internal network only.