adf6aa7658
Verify an od-db-backup cold backup by restoring it into a throwaway, network-isolated Hyper-V VM (revert to checkpoint after), never over live prod. Covers matching versions from MANIFEST, whole-datadir restore for InnoDB, re-pointing the image path, and a pass/fail health checklist (connects, Help>About version, Database Maintenance Check, recent data, images open, no missing tables, optional mysqlcheck). Cites Open Dental Backups / Manual Backups / Database Maintenance. Cross-linked with od-db-backup.md; README updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
117 lines
9.6 KiB
Markdown
117 lines
9.6 KiB
Markdown
# Runbook: Open Dental — Verify a backup by test-restoring into an isolated Hyper-V VM
|
||
|
||
**Applies to:** Any Open Dental cold backup produced by [`od-db-backup.md`](od-db-backup.md) (an `od-backup-<timestamp>` folder holding `data\`, `OpenDentImages\`, `FreeDentalConfig.xml`, `MANIFEST.txt`).
|
||
**Goal:** Prove a backup is actually restorable and complete by restoring it into a **throwaway, network-isolated Hyper-V virtual machine** and running a short health checklist. A backup you have never restored is a guess.
|
||
|
||
> [!IMPORTANT]
|
||
> **Never restore over a live production database** — Open Dental warns this can cause irreversible data loss. The whole point of this runbook is to restore somewhere that *cannot* touch production: an isolated VM, off the office network. ([Open Dental — Backups](https://opendental.com/manual/backups.html))
|
||
|
||
**Cadence:** Test-restore **at least monthly**, and any time you change backup jobs, versions, or hardware. Open Dental recommends restoring to a machine **not connected to the office network** to verify quality. ([Open Dental — Manual Backups](https://www.opendental.com/manual/backupsmanual.html))
|
||
|
||
**Why Hyper-V:** it gives you that isolated machine on demand, with a **checkpoint** you revert after every test — so each verification starts from a known-clean baseline and the PHI-laden copy is destroyed when you're done. Any spare offline PC or a doctor's disconnected laptop works too; the steps are identical inside.
|
||
|
||
**Placeholders:**
|
||
|
||
| Placeholder | Meaning |
|
||
|---|---|
|
||
| `<BACKUP_FOLDER>` | The `od-backup-<timestamp>` folder being verified |
|
||
| `<OD_VERSION>` | Open Dental version from `MANIFEST.txt` — must match on the VM |
|
||
| `<DB_VERSION>` | MySQL/MariaDB version from `MANIFEST.txt` — must match on the VM |
|
||
| `<DB_SERVICE>` | The MySQL/MariaDB service name **inside the VM** |
|
||
| `<VM_DATA_DIR>` | The VM's MySQL data directory (e.g. `C:\mysql\data`) |
|
||
| `<VM_IMAGES_DIR>` | The VM's A-to-Z images folder (e.g. `C:\OpenDentImages`) |
|
||
|
||
---
|
||
|
||
## Phase 0 — Read the manifest first
|
||
|
||
Open `<BACKUP_FOLDER>\MANIFEST.txt`. Note **`Open Dental ver`** (`<OD_VERSION>`) and **`DB engine ver`** (`<DB_VERSION>`). You must install **matching** versions in the VM — a version mismatch either refuses to open or silently converts the database. ([Open Dental — Manual Backups](https://www.opendental.com/manual/backupsmanual.html))
|
||
|
||
## Phase 1 — Build the isolated verification VM (once, then reuse)
|
||
|
||
Do this one time; you'll revert to a checkpoint for every future test.
|
||
|
||
1. **Enable Hyper-V** on a Windows Pro/Enterprise/Server host (elevated PowerShell; reboots):
|
||
```
|
||
Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All
|
||
```
|
||
2. **Create an isolated network** so the VM can never reach the office network or the live database. In Hyper-V Manager → *Virtual Switch Manager*, create a **Private** (or **Internal**) switch — **not** External. Or leave the VM with **no network adapter** at all.
|
||
> This isolation is the safety guarantee. An "External" switch would put the test VM on the practice LAN, where a mistake could reach production shares or the live DB. Don't.
|
||
3. **Create the VM** (Gen 2, enough RAM/disk for the database + images), install a supported **Windows** guest.
|
||
4. Inside the VM, install **MySQL/MariaDB `<DB_VERSION>`** and **Open Dental `<OD_VERSION>`** (matching the manifest). Do a normal Open Dental install so `<DB_SERVICE>`, `<VM_DATA_DIR>`, and a local `opendental` database exist.
|
||
5. Shut the VM down cleanly and take a **checkpoint** named `clean-baseline`. This is your reset point.
|
||
|
||
## Phase 2 — Get the backup into the VM (keep it offline)
|
||
|
||
Copy `<BACKUP_FOLDER>` into the VM **without** using the office network — e.g. Hyper-V Enhanced Session copy/paste, or attach the backup as a VHD/passthrough disk, or a scratch VHDX. The VM stays isolated the entire time.
|
||
|
||
## Phase 3 — Restore into the VM
|
||
|
||
Run these **inside the VM**, elevated. This mirrors Open Dental's documented restore, adapted for our **whole-datadir** cold copy.
|
||
|
||
1. **Stop the database:**
|
||
```
|
||
net stop <DB_SERVICE>
|
||
Get-Service <DB_SERVICE> # confirm Status = Stopped before touching files
|
||
```
|
||
2. **Move the VM's existing data aside** (don't delete — lets you retry):
|
||
```
|
||
Rename-Item "<VM_DATA_DIR>" "<VM_DATA_DIR>-old"
|
||
New-Item -ItemType Directory "<VM_DATA_DIR>" | Out-Null
|
||
```
|
||
3. **Restore the whole data directory** from the backup — copy the **entire contents of the backup's `data\` folder**, not just `data\opendental\`:
|
||
```
|
||
robocopy "<BACKUP_FOLDER>\data" "<VM_DATA_DIR>" /E /COPY:DAT /R:2 /W:5
|
||
```
|
||
> For **InnoDB** you must restore the shared tablespace and logs (`ibdata1`, `ib_logfile*`) that live at the datadir root alongside the `opendental` folder — that's why we restore the whole `data\`, matching how [`od-db-backup.md`](od-db-backup.md) captured it. Restoring only the `opendental` subfolder yields a database that won't start.
|
||
4. **Restore the images:**
|
||
```
|
||
robocopy "<BACKUP_FOLDER>\OpenDentImages" "<VM_IMAGES_DIR>" /E /COPY:DAT /R:2 /W:5
|
||
```
|
||
5. **Start the database:**
|
||
```
|
||
net start <DB_SERVICE>
|
||
Get-Service <DB_SERVICE> # confirm Running
|
||
```
|
||
6. **Launch Open Dental in the VM**, connecting to the **local** `opendental` database (localhost). Configure a fresh local connection — do **not** reuse the production `FreeDentalConfig.xml` connection string (it points at the real server). The captured `FreeDentalConfig.xml` is only a **reference** of production settings (e.g. the A-to-Z path).
|
||
7. If Open Dental reports it **can't find the images**, point the image path at `<VM_IMAGES_DIR>`: *Setup → Imaging / Image path* (the A-to-Z path stored in the database is production's; update it to the VM's local folder so restored images resolve).
|
||
|
||
## Phase 4 — Health checklist: is this backup good?
|
||
|
||
Work top to bottom. **All must pass** for the backup to count as verified.
|
||
|
||
- [ ] **Connects & opens** — Open Dental launches against the restored DB with **no connection or startup errors**.
|
||
- [ ] **Version matches** — *Help → About* shows `<OD_VERSION>` (no unexpected DB-conversion prompt).
|
||
- [ ] **Database Maintenance is clean** — *Main Menu → Tools → Database Maintenance*, run **Check** (not Fix). It "checks the database for improper settings, inconsistencies, or corruption." Review the results for **unexpected** corruption/integrity errors. ([Open Dental — Database Maintenance](https://www.opendental.com/manual/databasemaintenance.html))
|
||
- [ ] **Recent data is present and current** — open the **Appointments** module on a recent production date; open 2–3 known patients; check a recent **payment/ledger** entry. Confirm the newest data lines up with production **as of the backup time** (proves the backup is current, not stale).
|
||
- [ ] **Images actually open** — pick a patient known to have scanned docs/X-rays in the Imaging module and **open the files**. This proves the A-to-Z folder restored *and* the image path resolves — a DB-only restore silently loses every document.
|
||
- [ ] **No missing modules/tables** — click through Chart, Family, Account, Imaging; watch for "table doesn't exist" / read-only errors.
|
||
- [ ] *(Optional, deeper)* **Engine-level integrity** — from the VM's MySQL shell, `mysqlcheck -u root -p --check opendental` (or `CHECK TABLE`) to confirm no table-level corruption.
|
||
|
||
## Phase 5 — Record the result (keep as evidence)
|
||
|
||
Log, outside the VM: **date verified**, `<BACKUP_FOLDER>` timestamp, `<OD_VERSION>`/`<DB_VERSION>`, each checklist item **pass/fail**, who ran it, and any Database Maintenance findings. This is your DR evidence for E&O / cyber insurance and HIPAA contingency-plan testing.
|
||
|
||
> A **fail** on any item means the backup is not trustworthy — fix the backup job (not just this restore) and re-verify. Common causes: images folder never included; only `data\opendental\` copied (InnoDB won't start); backup taken hot without stopping the service; version drift.
|
||
|
||
## Phase 6 — Tear down / reset
|
||
|
||
1. In Open Dental, close out; **stop the MySQL service** in the VM before shutting down.
|
||
> Open Dental warns: if a machine used to verify backups **sleeps while MySQL is running, it can corrupt the database.** Stop the service first. ([Open Dental — Manual Backups](https://www.opendental.com/manual/backupsmanual.html))
|
||
2. **Revert the VM to the `clean-baseline` checkpoint.** This resets to a known-clean state for next time **and destroys the restored PHI copy**.
|
||
3. Never reconnect this VM to the office network with a restored database attached.
|
||
|
||
---
|
||
|
||
## Security note
|
||
|
||
The moment you restore, the VM's virtual disk holds the **entire practice's PHI** — treat it exactly like production. Keep the VM **isolated** (Private/Internal switch or no NIC), keep the host and VHDX **encrypted** (BitLocker / encrypted VHDX), and **revert/destroy** the restored state when done so PHI doesn't linger on a test box. HIPAA applies to the copy just as much as to production. See the security note in [`od-db-backup.md`](od-db-backup.md) — on direct-connection setups the captured `FreeDentalConfig.xml` also holds the (reversibly obfuscated) DB password.
|
||
|
||
## References
|
||
|
||
- Open Dental manual — Backups (overview; test-restore off-network): <https://opendental.com/manual/backups.html>
|
||
- Open Dental manual — Manual Backups (restore steps; verify on disconnected machine; sleep/corruption warning): <https://www.opendental.com/manual/backupsmanual.html>
|
||
- Open Dental manual — Database Maintenance (Check/Fix health tool): <https://www.opendental.com/manual/databasemaintenance.html>
|
||
- Open Dental manual — Backup Tool: <https://www.opendental.com/manual/backuptool.html>
|
||
- Companion runbook — producing the backup: [`od-db-backup.md`](od-db-backup.md)
|