TIDE/RECOVERY.md

140 lines
3.3 KiB
Markdown

# TIDE Forum State and Database Recovery
This restores the Discourse state and database from the BorgBase backup
configured by the TIDE NixOS module. It replaces the current state directory
and PostgreSQL database with the selected Borg archive.
The backup contains:
- `/var/lib/discourse`
- `/var/backup/discourse/discourse.dump`
## Requirements
- BorgBase repo URL:
`ssh://oas17j8p@oas17j8p.repo.borgbase.com/./repo`
- Decrypted Borg SSH private key from the flash drive
- Borg repository passphrase from the flash drive
- A target server that has already been switched to the TIDE NixOS module
- A shell with `borg`, `openssh`, `postgresql`, and `rsync`
On NixOS or another machine with Nix:
```sh
nix-shell -p borgbackup openssh postgresql rsync
```
## Prepare Borg Access
Copy the Borg SSH key into a local recovery directory:
```sh
mkdir -p ~/borg-recovery/discourse
cp /path/to/flash/borg-private-key ~/borg-recovery/discourse/borg-private-key
chmod 600 ~/borg-recovery/discourse/borg-private-key
```
Set the Borg connection environment:
```sh
export BORG_REPO='ssh://oas17j8p@oas17j8p.repo.borgbase.com/./repo'
export BORG_RSH='ssh -i ~/borg-recovery/discourse/borg-private-key -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new'
```
Read the Borg passphrase without showing it on screen:
```sh
read -rsp 'Borg passphrase: ' BORG_PASSPHRASE
export BORG_PASSPHRASE
echo
```
## Extract a Backup
List available archives:
```sh
borg list
```
Choose an archive name, then extract only the Discourse state and database
dump into a temporary directory. Do not extract directly into `/`.
```sh
export ARCHIVE='ARCHIVE_NAME_FROM_BORG_LIST'
mkdir -p ~/borg-recovery/discourse/extract
cd ~/borg-recovery/discourse/extract
borg extract ::$ARCHIVE var/lib/discourse \
var/backup/discourse/discourse.dump
```
## Restore on the Server
Run these commands from `~/borg-recovery/discourse/extract` on the target
server. They assume the TIDE module has created the `discourse` user,
`postgresql.service`, and `discourse-postgresql.service`.
Capture absolute tool paths so they still work through `sudo`:
```sh
RSYNC="$(command -v rsync)"
PSQL="$(command -v psql)"
DROPDB="$(command -v dropdb)"
PG_RESTORE="$(command -v pg_restore)"
```
Stop Discourse and make sure PostgreSQL is running:
```sh
sudo systemctl stop discourse.service
sudo systemctl start postgresql.service
```
Restore `/var/lib/discourse`:
```sh
sudo "$RSYNC" -a --delete ./var/lib/discourse/ /var/lib/discourse/
sudo chown -R discourse:discourse /var/lib/discourse
```
Replace the `discourse` PostgreSQL database:
```sh
sudo -u postgres "$PSQL" -d postgres -v ON_ERROR_STOP=1 \
-c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'discourse';"
sudo -u postgres "$DROPDB" --if-exists discourse
sudo systemctl restart discourse-postgresql.service
sudo -u postgres "$PG_RESTORE" \
--exit-on-error \
--no-owner \
--role=discourse \
--dbname=discourse \
./var/backup/discourse/discourse.dump
sudo systemctl restart discourse-postgresql.service
```
Start Discourse:
```sh
sudo systemctl start discourse.service
```
## Verify
Check the service and recent logs:
```sh
sudo systemctl status discourse.service --no-pager
sudo journalctl -u discourse.service -b --no-pager -n 100
```
If networking and DNS are restored, open:
```text
https://discourse.torahimderecheretz.com
```