Files
tor-guard-relay/docs/BACKUP.md
rE-Bo0t.bx1 90b65ee469 🔖 release(v1.1.6): bind mount fix, full repo audit, workflow fixes
🔧 Entrypoint:
- Detect wrong ownership on /var/lib/tor and /var/lib/tor/keys at startup
  with actionable chown commands before Tor fails cryptically in Phase 4
- Accept DEBUG=TRUE, DEBUG=1, DEBUG=yes (case-insensitive)
- Fix signal trap bug: inner cleanup_verify_tmp no longer overwrites
  the global TERM/INT handler (could skip graceful shutdown)

🛡️ Security:
- Deprecate all versions < v1.1.5 (CVE-2025-15467, OpenSSL CVSS 9.8)
- Add deprecation notice to README and SECURITY.md
- Update lifecycle tables in CHANGELOG and SECURITY

🐛 Bug Fixes:
- Fix bootstrap detection in migrate-from-official.sh
  (parsed non-existent "bootstrap_percent" field — now "bootstrap")
- Fix health JSON docs across 4 files: uptime_seconds → uptime,
  add missing pid/errors fields, correct reachable type to string
- Fix validate.yml: bash -n → sh -n (POSIX script, not bash)

📚 Documentation:
- Add "Bind Mount Ownership" troubleshooting section to README
- Fix chown 1000:1000 typo → 100:101 in TROUBLESHOOTING-BRIDGE-MIGRATION.md
- Add [1.1.6] changelog entry
- Update version references across 20+ files to v1.1.6
- Update 47x alpine:3.22.2 → 3.23.3 across migration docs/scripts
- Fix tool count 4 → 5 in DEPLOYMENT, ARCHITECTURE, TROUBLESHOOTING
- Remove 5 broken links (CLAUDE.md, CONTRIBUTORS.md, SECURITY-AUDIT-REPORT.md)
- Fix stale image tags (:1.1.1/:1.1.2 → :latest) in 4 files
- Rewrite PR template as clean reusable form

⚙️ Workflow (release.yml):
- Fix duplicate title in release body (name + body both had ## 🧅 header)
- Fix trailing --- not being stripped from changelog extract
- Fix Full Changelog link comparing current tag to itself
- Extract Alpine version from Dockerfile instead of hardcoding
- Add fetch-depth: 0 for git history in release-notes job
- Fix fallback commit range when no conventional commits found

🐳 Dockerfiles:
- Fix stale base.name label (alpine:3.23.0 → alpine:3.23.3)
- Fix trailing whitespace after backslash in Dockerfile.edge

📋 Templates:
- Update cosmos-compose and docker-compose versions to 1.1.6
2026-02-08 16:04:22 +05:30

653 lines
15 KiB
Markdown

# 🔐 Backup & Recovery Guide - Tor Guard Relay
Complete instructions for backing up and restoring your Tor relay's identity, keys, and configuration data.
---
## Table of Contents
- [Why Backups Matter](#why-backups-matter)
- [What to Backup](#what-to-backup)
- [Backup Methods](#backup-methods)
- [Recovery Procedures](#recovery-procedures)
- [Migration Guide](#migration-guide)
- [Best Practices](#best-practices)
---
## Why Backups Matter
Your Tor relay's **identity is permanent**. Once established, it becomes part of the Tor network's fabric. Losing these keys means:
- 🚫 Loss of your relay's fingerprint
- 📉 Loss of reputation built over time
- 🔄 New relay starting from zero
- ⏰ 8+ days to regain guard flag
**Backup your keys immediately after first successful bootstrap.**
---
## What to Backup
### 🔑 Critical Files (Preserve Forever)
Located in `/var/lib/tor/`:
| File | Purpose | Restore Impact |
|------|---------|-----------------|
| `keys/ed25519_master_id_secret_key` | Master identity key | **CRITICAL** - Defines relay identity |
| `keys/ed25519_signing_secret_key` | Signing key | **CRITICAL** - Signs all operations |
| `keys/secret_onion_key` | Onion key | **CRITICAL** - Onion address generation |
| `fingerprint` | Your relay fingerprint | Reference only (can regenerate) |
### 📋 Important Files (Backup Regularly)
| File | Purpose | Restore Impact |
|------|---------|-----------------|
| `cached-consensus` | Current Tor consensus | Nice to have (rebuilds automatically) |
| `cached-descriptors` | Relay descriptors | Nice to have (rebuilds automatically) |
| `state` | Relay state file | Optional (recreated on startup) |
### ⚙️ Configuration (Backup Before Changes)
| File | Location | Purpose |
|------|----------|---------|
| `relay.conf` | Host machine | Your relay configuration |
| `torrc` | `/etc/tor/torrc` (in container) | Mounted copy of relay.conf |
---
## Backup Methods
### Quick Backup (Simplest)
Copy the keys directory straight out of a running container:
```bash
docker cp <container-name>:/var/lib/tor/keys ./RelayKeyBackup
```
That's it. The `RelayKeyBackup/` folder now contains your relay's identity keys. Store it somewhere safe.
---
### Method 1: Docker Volume Backup (Recommended)
**Pros:** Complete, easy to restore, version-controlled
**Cons:** Requires disk space for full volume copy
#### Step 1: Stop the Relay Gracefully
```bash
# Stop relay (allows clean shutdown)
docker stop guard-relay
# Wait for graceful shutdown
sleep 5
# Verify stopped
docker ps | grep guard-relay
```
#### Step 2: Backup the Volume
```bash
# Create backup directory
mkdir -p ~/tor-relay-backups/$(date +%Y-%m-%d)
# Backup the tor-guard-data volume
docker run --rm \
-v tor-guard-data:/data \
-v ~/tor-relay-backups/$(date +%Y-%m-%d):/backup \
alpine tar czf /backup/tor-data-$(date +%s).tar.gz -C /data .
# Verify backup created
ls -lh ~/tor-relay-backups/$(date +%Y-%m-%d)/
```
**Output:**
```
-rw-r--r-- 1 user user 2.5M Jan 1 12:00 tor-data-1704110400.tar.gz
```
#### Step 3: Backup the Logs Volume
```bash
# Backup logs for audit trail
docker run --rm \
-v tor-guard-logs:/data \
-v ~/tor-relay-backups/$(date +%Y-%m-%d):/backup \
alpine tar czf /backup/tor-logs-$(date +%s).tar.gz -C /data .
# Verify
ls -lh ~/tor-relay-backups/$(date +%Y-%m-%d)/
```
#### Step 4: Restart the Relay
```bash
# Restart relay
docker start guard-relay
# Monitor startup
docker logs -f guard-relay
```
---
### Method 2: Direct Key Extraction
**Pros:** Minimal, extracts only critical keys
**Cons:** Manual process, easier to miss files
#### Extract Keys While Running
```bash
# Create secure backup directory
mkdir -p ~/tor-relay-backups/keys-only
chmod 700 ~/tor-relay-backups/keys-only
# Extract keys directly from container
docker exec guard-relay tar czf - -C /var/lib/tor/keys . | \
tar xzf - -C ~/tor-relay-backups/keys-only/
# Verify contents
ls -la ~/tor-relay-backups/keys-only/
```
**Expected output:**
```
ed25519_master_id_secret_key
ed25519_signing_secret_key
secret_onion_key
```
#### Secure the Backup
```bash
# Set restrictive permissions
chmod 600 ~/tor-relay-backups/keys-only/*
# Verify ownership
ls -la ~/tor-relay-backups/keys-only/
```
---
### Method 3: Automated Daily Backup
**Pros:** Hands-off, versioned history
**Cons:** Requires cron setup, disk space
#### Create Backup Script
```bash
#!/bin/bash
# Save as: /usr/local/bin/backup-tor-relay.sh
set -euo pipefail
BACKUP_DIR="/backups/tor-relay"
RETENTION_DAYS=30
CONTAINER="guard-relay"
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
# Create backup directory
mkdir -p "$BACKUP_DIR/$TIMESTAMP"
# Stop relay gracefully
echo "🛑 Stopping relay..."
docker stop "$CONTAINER" || true
sleep 5
# Backup data volume
echo "💾 Backing up data volume..."
docker run --rm \
-v tor-guard-data:/data \
-v "$BACKUP_DIR/$TIMESTAMP":/backup \
alpine tar czf /backup/tor-data.tar.gz -C /data .
# Backup logs volume
echo "📝 Backing up logs..."
docker run --rm \
-v tor-guard-logs:/data \
-v "$BACKUP_DIR/$TIMESTAMP":/backup \
alpine tar czf /backup/tor-logs.tar.gz -C /data .
# Extract fingerprint for reference
docker start "$CONTAINER"
sleep 10
docker exec "$CONTAINER" cat /var/lib/tor/fingerprint > "$BACKUP_DIR/$TIMESTAMP/fingerprint.txt" || true
# Create manifest
cat > "$BACKUP_DIR/$TIMESTAMP/MANIFEST.txt" << EOF
Tor Guard Relay Backup
Timestamp: $TIMESTAMP
Container: $CONTAINER
Relay: $(grep Nickname /opt/tor-relay/relay.conf | cut -d' ' -f2)
Files:
- tor-data.tar.gz (Relay identity and state)
- tor-logs.tar.gz (Tor logs for audit)
- fingerprint.txt (Relay fingerprint reference)
EOF
# Cleanup old backups (keep last 30 days)
echo "🧹 Cleaning up old backups..."
find "$BACKUP_DIR" -maxdepth 1 -type d -mtime +$RETENTION_DAYS -exec rm -rf {} \;
# Summary
echo "✅ Backup complete: $BACKUP_DIR/$TIMESTAMP"
du -sh "$BACKUP_DIR/$TIMESTAMP"
```
#### Make Executable
```bash
chmod +x /usr/local/bin/backup-tor-relay.sh
```
#### Add to Cron (Daily at 2 AM)
```bash
# Edit crontab
crontab -e
# Add line:
0 2 * * * /usr/local/bin/backup-tor-relay.sh >> /var/log/tor-backup.log 2>&1
```
#### Monitor Backup Logs
```bash
# View backup logs
tail -f /var/log/tor-backup.log
# Check backup history
ls -lah /backups/tor-relay/
```
---
### Method 4: Off-Site Backup (Cloud/External)
**Pros:** Disaster recovery, geographic redundancy
**Cons:** Security risk if not encrypted, potential costs
#### Encrypt Backup Before Upload
```bash
# Generate encryption key (save this somewhere secure!)
openssl rand -base64 32 > ~/tor-relay-backup.key
# Encrypt backup before upload
gpg --symmetric --cipher-algo AES256 \
--output tor-data-encrypted.tar.gz.gpg \
tor-data-$(date +%s).tar.gz
# Upload to cloud (e.g., AWS S3)
aws s3 cp tor-data-encrypted.tar.gz.gpg s3://my-backups/tor-relay/
```
#### Decrypt When Needed
```bash
# Decrypt backup
gpg --decrypt tor-data-encrypted.tar.gz.gpg > tor-data-restored.tar.gz
# Verify integrity
tar tzf tor-data-restored.tar.gz | head -10
```
---
## Recovery Procedures
### Scenario 1: Container Corruption
**Problem:** Container is running but data is corrupted
**Recovery time:** 15 minutes
#### Steps
```bash
# 1. Stop the relay
docker stop guard-relay
# 2. Remove corrupted volume
docker volume rm tor-guard-data
# 3. Create new volume
docker volume create tor-guard-data
# 4. Restore from backup
docker run --rm \
-v tor-guard-data:/data \
-v ~/tor-relay-backups/2024-01-01:/backup \
alpine tar xzf /backup/tor-data-1704110400.tar.gz -C /data
# 5. Verify permissions
docker exec guard-relay chown -R tor:tor /var/lib/tor
# 6. Restart relay
docker start guard-relay
# 7. Monitor startup
docker logs -f guard-relay
```
---
### Scenario 2: Server Failure - Full Restore
**Problem:** Entire server lost, migrating to new hardware
**Recovery time:** 30 minutes
#### Steps
```bash
# 1. Prepare new server with Docker
# 2. Copy backup to new server
scp -r ~/tor-relay-backups/2024-01-01 user@new-server:/tmp/
# 3. On new server, create volume and restore
docker volume create tor-guard-data
docker run --rm \
-v tor-guard-data:/data \
-v /tmp/2024-01-01:/backup \
alpine tar xzf /backup/tor-data-1704110400.tar.gz -C /data
# 4. Copy relay configuration
scp /opt/tor-relay/relay.conf user@new-server:/opt/tor-relay/
# 5. On new server, start relay
docker run -d \
--name guard-relay \
--network host \
-v /opt/tor-relay/relay.conf:/etc/tor/torrc:ro \
-v tor-guard-data:/var/lib/tor \
-v tor-guard-logs:/var/log/tor \
--restart unless-stopped \
r3bo0tbx1/onion-relay:latest
# 6. Verify relay is using old identity
docker exec guard-relay fingerprint
# Should match original fingerprint!
```
---
### Scenario 3: Key Loss - Emergency Recovery
**Problem:** All keys lost, only backup exists
**Recovery time:** 5 minutes
#### Restore Keys Only
```bash
# Stop relay
docker stop guard-relay
# Clear tor data
docker run --rm \
-v tor-guard-data:/data \
alpine rm -rf /data/*
# Restore from backup
docker run --rm \
-v tor-guard-data:/data \
-v ~/tor-relay-backups/keys-only:/backup \
alpine bash -c "cp -r /backup/* /data/"
# Fix permissions
docker exec guard-relay chown -R tor:tor /var/lib/tor
docker exec guard-relay chmod 700 /var/lib/tor/keys
# Restart
docker start guard-relay
# Verify identity recovered
docker exec guard-relay fingerprint
```
---
## Migration Guide
### Move Relay to New Server (Same Identity)
**Goal:** Keep relay fingerprint, move to new hardware
#### Pre-Migration Checklist
- ✅ Recent full backup created
- ✅ New server prepared with Docker
- ✅ Network firewall rules ready
- ✅ DNS/IP planning done
- ✅ Maintenance window scheduled
#### Step-by-Step Migration
```bash
# === ON OLD SERVER ===
# 1. Create final backup
docker stop guard-relay
sleep 5
docker run --rm \
-v tor-guard-data:/data \
-v ~/tor-relay-backups/migration:/backup \
alpine tar czf /backup/tor-data-final.tar.gz -C /data .
# 2. Verify backup
ls -lh ~/tor-relay-backups/migration/
# === TRANSFER TO NEW SERVER ===
# 3. Copy backup securely
scp -r ~/tor-relay-backups/migration user@new-server:/tmp/
# 4. Copy relay configuration
scp /opt/tor-relay/relay.conf user@new-server:/opt/tor-relay/
# === ON NEW SERVER ===
# 5. Create volume and restore
docker volume create tor-guard-data
docker run --rm \
-v tor-guard-data:/data \
-v /tmp/migration:/backup \
alpine tar xzf /backup/tor-data-final.tar.gz -C /data
# 6. Start relay on new server
docker run -d \
--name guard-relay \
--network host \
-v /opt/tor-relay/relay.conf:/etc/tor/torrc:ro \
-v tor-guard-data:/var/lib/tor \
-v tor-guard-logs:/var/log/tor \
--restart unless-stopped \
r3bo0tbx1/onion-relay:latest
# 7. Verify startup and identity
docker logs -f guard-relay
docker exec guard-relay fingerprint
# === FINAL VERIFICATION ===
# 8. Check on Tor Metrics (should recognize old fingerprint within hours)
# https://metrics.torproject.org/rs.html
# 9. After verification, on old server:
docker stop guard-relay
docker rm guard-relay
```
#### Verification After Migration
```bash
# Check logs for successful bootstrap
docker logs guard-relay 2>&1 | grep "Bootstrapped 100"
# Verify fingerprint matches backup
docker exec guard-relay fingerprint
# Compare with: cat ~/tor-relay-backups/migration/fingerprint.txt
# Monitor for 24 hours for any issues
docker stats guard-relay --no-stream
```
---
### Zero-Downtime Migration (Advanced)
**Goal:** Migrate relay without downtime by running dual servers
#### Setup
```bash
# 1. OLD SERVER: Create backup
docker stop guard-relay
docker run --rm \
-v tor-guard-data:/data \
-v ~/tor-relay-backups/dual:/backup \
alpine tar czf /backup/tor-data.tar.gz -C /data .
# 2. NEW SERVER: Restore backup and start
docker volume create tor-guard-data
docker run --rm \
-v tor-guard-data:/data \
-v /tmp/dual:/backup \
alpine tar xzf /backup/tor-data.tar.gz -C /data
docker run -d \
--name guard-relay \
--network host \
-v /opt/tor-relay/relay.conf:/etc/tor/torrc:ro \
-v tor-guard-data:/var/lib/tor \
-v tor-guard-logs:/var/log/tor \
--restart unless-stopped \
r3bo0tbx1/onion-relay:latest
# 3. Verify NEW server is running
docker logs guard-relay | grep "Bootstrapped"
# 4. Wait 30 minutes for NEW server to stabilize
sleep 1800
# 5. OLD SERVER: Restart old relay
docker start guard-relay
# 6. Both servers now running same relay identity
# Tor network handles this gracefully
# 7. OLD SERVER: After 24 hours, shut down
docker stop guard-relay
```
---
## Best Practices
### ✅ DO
-**Backup immediately after bootstrap** - Preserve identity
-**Use strong encryption** for off-site backups
-**Test restores regularly** - Backups are worthless if unverifiable
-**Document fingerprints** - Keep reference copy of fingerprint
-**Automate backups** - Set and forget with cron
-**Store backups securely** - Encrypt sensitive data
-**Keep multiple copies** - Local + off-site minimum
-**Version your backups** - Date-stamped directories
### ❌ DON'T
-**Don't backup `/etc/tor/torrc`** - Mount as read-only from host
-**Don't share backup media unencrypted** - Keys are sensitive
-**Don't rely on single backup** - 3-2-1 rule applies
-**Don't ignore backup failures** - Monitor logs
-**Don't delete old backups immediately** - Keep 30+ days
### 📊 3-2-1 Backup Rule
Maintain at minimum:
- **3 copies** of your data
- Original (running relay)
- Backup 1 (local storage)
- Backup 2 (off-site)
- **2 different media types**
- NVMe/SSD
- USB external drive
- **1 off-site copy**
- Cloud storage (encrypted)
- Or remote server
---
## Troubleshooting
### Backup Failed: "Volume is in use"
```bash
# Problem: Cannot backup running volume
# Solution: Stop relay first
docker stop guard-relay
sleep 5
# Retry backup command
```
### Restore Failed: "File permissions denied"
```bash
# Problem: Restored files have wrong ownership
# Solution: Fix permissions
docker exec guard-relay chown -R tor:tor /var/lib/tor
docker exec guard-relay chmod 700 /var/lib/tor/keys
```
### Fingerprint Changed After Restore
```bash
# Problem: Restored relay has different fingerprint
# Cause: Keys weren't backed up, only state
# Solution: Use Method 2 (Direct Key Extraction) for future backups
# For now, accept new identity:
docker exec guard-relay fingerprint
# This is your new permanent fingerprint
```
---
## Reference
**Backup Command Cheat Sheet:**
```bash
# Quick backup (stop relay)
docker stop guard-relay && \
docker run --rm -v tor-guard-data:/data -v ~/backups:/backup alpine tar czf /backup/tor-$(date +%s).tar.gz -C /data . && \
docker start guard-relay
# Quick restore
docker run --rm -v tor-guard-data:/data -v ~/backups:/backup alpine tar xzf /backup/tor-1704110400.tar.gz -C /data
# Verify backup integrity
tar tzf ~/backups/tor-1704110400.tar.gz | head -20
# Calculate backup size
du -sh ~/backups/tor-1704110400.tar.gz
```
---
## Support
- 📖 [Main README](../README.md)
- 🚀 [Deployment Guide](./DEPLOYMENT.md)
- 🐛 [Report Issues](https://github.com/r3bo0tbx1/tor-guard-relay/issues)
- 💬 [Tor Relay Forum](https://forum.torproject.org/)