Files
tor-guard-relay/docs/MIGRATION-V1.1.X.md
rE-Bo0t.bx1 be4f2bc125 feat(v1.1.7): Happy Family support (Tor 0.4.9+ FamilyId)
🔧 New tool: gen-family - generate/view Happy Family keys
  - Supports --force flag to overwrite existing keys without backup prompt

🐳 Dockerfiles: gen-family in both Dockerfile and Dockerfile.edge

🔧 Entrypoint:
- Phase 2: detect *.secret_family_key, log found keys (informational only)
- Guard/exit config gen: append FamilyId + MyFamily from ENV vars
- Bridge intentionally excluded

📊 Status tool: show family key count + Happy Family config state

📚 Docs:
- README: Happy Family section (generate / import), persistence table, flowchart
- ARCHITECTURE: all mermaid diagrams updated (Phase 2, config gen, tools, dirs)
- TOOLS: full gen-family reference with examples and exit codes
- DEPLOYMENT, MIGRATION, MIGRATION-V1.1.X, TROUBLESHOOTING: 5 -> 6 tools
- FAQ, example configs: version bump + FamilyId/MyFamily placeholders
- Directory authority voting: how 9 dirauths vote on relay flags (5/9 consensus)
- CIISS v2 ContactInfo: field reference, generator link, proof:uri-rsa verification
- All TOR_CONTACT_INFO examples updated to CIISS v2 format across templates and docs

📋 Templates:
- Guard/exit/multi-relay compose: TOR_FAMILY_ID + TOR_MY_FAMILY env vars
- All cosmos-compose + docker-compose versions -> 1.1.7

👷 CI: validate.yml gen-family in 8 spots (threshold 6), security tests, quick-test

🛡️ SECURITY.md: 1.1.7 active, 1.1.6 maintenance, gen-family in tools list

🔖 Version bump 1.1.6 -> 1.1.7 across 30+ files, tool count 5 -> 6, CHANGELOG entry

No breaking changes. TOR_FAMILY_ID and TOR_MY_FAMILY are optional.
2026-03-02 16:23:10 +08:00

12 KiB

Migration Guide: v1.1.0 → >=v1.1.1

This guide documents two successful real-world migration paths validated in production:

  1. Guard/Middle Relay (mounted torrc) - Zero issues
  2. Bridge from Official Image (thetorproject/obfs4-bridge) - Requires ownership fix

📋 What's New in v1.1.1

Security Fixes

  • Fixed: Command injection via OBFS4V_* environment variables (CWE-78, CWE-94)
  • Fixed: Health check failure on ENV-based deployments (CWE-703)
  • Fixed: Privilege escalation attempt with silent failure (CWE-250)
  • Fixed: Inadequate input validation (CWE-20)
  • Fixed: Workflow permission over-granting (CWE-269)
  • Fixed: Temporary file race condition (CWE-377)
  • Fixed: TOR_CONTACT_INFO validation false positives

Improvements

  • Smart healthcheck script works with both mounted and ENV configs
  • Comprehensive input validation with whitespace trimming
  • Better error messages and debugging
  • Removed non-functional chown attempt
  • Cleaned up bridge configuration (removed redundant ExitPolicy)

Breaking Changes

None - All changes are backward compatible!


Migration Path 1: Guard/Middle Relay (Mounted Config)

Difficulty: Easy Downtime: < 2 minutes Fingerprint Preserved: Yes Volume Changes Required: None

Prerequisites

# Verify you're using a mounted torrc file
docker inspect <container> --format='{{range .Mounts}}{{if eq .Destination "/etc/tor/torrc"}}MOUNTED{{end}}{{end}}'
# Should output: MOUNTED

Step 1: Backup

# Stop container
docker stop <container>

# Backup volumes
docker run --rm \
  -v tor-guard-data:/data \
  -v /tmp:/backup \
  alpine:3.23.3 tar czf /backup/tor-guard-data-backup-$(date +%Y%m%d).tar.gz /data

docker run --rm \
  -v tor-guard-logs:/data \
  -v /tmp:/backup \
  alpine:3.23.3 tar czf /backup/tor-guard-logs-backup-$(date +%Y%m%d).tar.gz /data

# Save fingerprint
docker run --rm -v tor-guard-data:/data alpine:3.23.3 cat /data/fingerprint > /tmp/fingerprint-backup.txt

Step 2: Update Configuration

Cosmos JSON changes:

{
  "image": "r3bo0tbx1/onion-relay:latest",  // ← Update from :latest or :1.1.0
  "cap_add": [
    "NET_BIND_SERVICE"  // ← Removed unnecessary CHOWN, SETUID, SETGID, DAC_OVERRIDE
  ],
  "labels": {
    "cosmos-version": "1.1.1"  // ← Update version
  }
}

Step 3: Remove Old Container

docker rm <container>

Step 4: Deploy Updated Container

  • Import updated JSON in Cosmos UI
  • Or redeploy with docker-compose up -d

Step 5: Verify

# Check logs
docker logs -f <container>
# Expected: ✅ Using mounted configuration: /etc/tor/torrc

# Verify fingerprint matches
docker exec <container> fingerprint
cat /tmp/fingerprint-backup.txt
# Must match!

# Run diagnostics
docker exec <container> status
docker exec <container> health | jq .

Success Criteria

  • Container starts successfully
  • Logs show "Using mounted configuration"
  • Fingerprint matches backup
  • Bootstrap reaches 100%
  • Relay is reachable

⚠️ Migration Path 2: Bridge from Official Image

Difficulty: Moderate Downtime: 5-10 minutes Fingerprint Preserved: Yes (after fix) Volume Changes Required: Yes - UID ownership fix

The Challenge

UID Mismatch:

  • Official thetorproject/obfs4-bridge (Debian): UID 101
  • r3bo0tbx1/onion-relay (Alpine): UID 100

Symptom: Permission denied errors if not fixed.

Prerequisites

# Verify current image
docker inspect <container> --format='{{.Config.Image}}'
# Should show: thetorproject/obfs4-bridge or similar

# Check ENV variables
docker inspect <container> --format='{{range .Config.Env}}{{println .}}{{end}}' | grep -E "OR_PORT|PT_PORT|EMAIL|NICKNAME"

Why?

  • More reliable than ENV variables
  • Bypasses validation complexity
  • Same as guard relay (consistent approach)
  • Easier to troubleshoot

Step 1: Backup Everything

# Stop container
docker stop obfs4-bridge

# Backup volume (CRITICAL!)
docker run --rm \
  -v obfs4-data:/data \
  -v /tmp:/backup \
  alpine:3.23.3 tar czf /backup/obfs4-data-backup-$(date +%Y%m%d).tar.gz /data

# Verify backup
ls -lh /tmp/obfs4-data-backup-*.tar.gz

# Save fingerprint
docker run --rm -v obfs4-data:/data alpine:3.23.3 cat /data/fingerprint > /tmp/bridge-fingerprint-backup.txt
cat /tmp/bridge-fingerprint-backup.txt

Step 2: Fix Volume Ownership (CRITICAL!)

# Check current ownership (should be 101:101)
docker run --rm -v obfs4-data:/data alpine:3.23.3 ls -ldn /data
# Output: drwx------ ... 101 101 ...

# Fix ownership: 101 → 100
docker run --rm -v obfs4-data:/data alpine:3.23.3 chown -R 100:101 /data

# Verify fix
docker run --rm -v obfs4-data:/data alpine:3.23.3 ls -ldn /data
# Output: drwx------ ... 100 101 ...  ← MUST show 100!

# Verify key files are readable
docker run --rm -v obfs4-data:/data alpine:3.23.3 ls -la /data/keys/
# Should show files owned by 100:101

Step 3: Create Bridge Config File

# Create config directory
sudo mkdir -p /home/$(whoami)/onion

# Create bridge.conf
sudo tee /home/$(whoami)/onion/bridge.conf > /dev/null << 'EOF'
# Tor obfs4 Bridge Configuration
Nickname MyObfs4Bridge
ContactInfo admin@email.org

# Network configuration
ORPort 9001
SocksPort 0

# Data directories
DataDirectory /var/lib/tor
Log notice file /var/log/tor/notices.log

# Bridge relay configuration
BridgeRelay 1
PublishServerDescriptor bridge

# obfs4 pluggable transport
ServerTransportPlugin obfs4 exec /usr/bin/lyrebird
ServerTransportListenAddr obfs4 0.0.0.0:9005
ExtORPort auto

# Additional options
MaxMemInQueues 1024 MB
AddressDisableIPv6 0
EOF

# Customize with your values
sudo nano /home/$(whoami)/onion/bridge.conf

Step 4: Remove Old Container

docker rm obfs4-bridge

Step 5: Deploy with Mounted Config

Cosmos JSON:

{
  "minVersion": "0.8.0",
  "services": {
    "obfs4-bridge": {
      "image": "r3bo0tbx1/onion-relay:latest",
      "container_name": "obfs4-bridge",
      "restart": "unless-stopped",
      "network_mode": "host",
      "environment": [
        "TZ=UTC"
      ],
      "volumes": [
        {
          "type": "volume",
          "source": "obfs4-data",
          "target": "/var/lib/tor"
        },
        {
          "type": "bind",
          "source": "/home/youruser/onion/bridge.conf",
          "target": "/etc/tor/torrc",
          "read_only": true
        }
      ],
      "security_opt": [
        "no-new-privileges:true"
      ],
      "labels": {
        "cosmos-stack": "TorBridge",
        "cosmos-stack-main": "obfs4-bridge",
        "cosmos-description": "🌉 Hardened obfs4 Bridge v1.1.1",
        "cosmos-icon": "https://iili.io/KsXP2Y7.png",
        "cosmos-auto-update": "true",
        "cosmos-auto-update-type": "registry",
        "cosmos-force-network-secured": "false",
        "cosmos-version": "1.1.1"
      }
    }
  },
  "volumes": {
    "obfs4-data": {}
  }
}

Key changes:

  • Removed ALL ENV variables
  • Added mounted bridge.conf
  • Updated image to 1.1.1

Step 6: Deploy and Verify

# Import JSON in Cosmos UI and start

# Check logs
docker logs -f obfs4-bridge
# Expected:
# ✅ Using mounted configuration: /etc/tor/torrc
# ✅ Configuration is valid
# 🚀 Tor relay started

# Wait 30 seconds, then verify fingerprint
docker exec obfs4-bridge fingerprint
cat /tmp/bridge-fingerprint-backup.txt
# MUST MATCH!

# Check configuration
docker exec obfs4-bridge cat /etc/tor/torrc
# Should show BridgeRelay 1, obfs4 config, etc.

# Run health check
docker exec obfs4-bridge health | jq .

# Run full status
docker exec obfs4-bridge status

Step 7: Get Bridge Line (After 24-48 Hours)

# Bridge line appears after Tor publishes to BridgeDB
docker exec obfs4-bridge bridge-line

Success Criteria

  • Container starts successfully
  • Logs show "Using mounted configuration"
  • Fingerprint matches backup (CRITICAL!)
  • Bootstrap reaches 100%
  • Bridge line available after 24-48 hours

🚨 Troubleshooting

Issue 1: "Permission denied" on startup

Symptom:

Directory /var/lib/tor cannot be read: Permission denied

Cause: Volume ownership not fixed (still UID 101)

Fix:

docker stop obfs4-bridge
docker run --rm -v obfs4-data:/data alpine:3.23.3 chown -R 100:101 /data
docker start obfs4-bridge

Issue 2: Different fingerprint after migration

Symptom: Fingerprint changed, new bridge identity

Cause: Bridge keys not preserved

Fix: Restore from backup:

docker stop obfs4-bridge
docker run --rm -v obfs4-data:/data -v /tmp:/backup alpine:3.23.3 \
  sh -c 'rm -rf /data/* && tar xzf /backup/obfs4-data-backup-*.tar.gz -C / && chown -R 100:101 /data'
docker start obfs4-bridge

Issue 3: "TOR_CONTACT_INFO contains invalid characters"

Symptom: Container in restart loop with validation error

Cause: Fixed in v1.1.1 - validation was too strict

Solution: Use mounted config instead of ENV variables (see Step 3-5 above)

Issue 4: Container restart loop (general)

Debug:

# Check logs
docker logs obfs4-bridge --tail 50

# Check if it's actually using new image
docker inspect obfs4-bridge --format='{{.Image}}'
docker images r3bo0tbx1/onion-relay:latest --format='{{.ID}}'
# IDs must match!

# If IDs don't match: remove and recreate container
docker stop obfs4-bridge
docker rm obfs4-bridge
# Then redeploy

Issue 5: Health check failing

Symptom: Container marked unhealthy

Cause: Old health check used hardcoded path

Fix: v1.1.1 includes smart healthcheck.sh that works with both mounted and ENV configs. Just update to 1.1.1 image.


📊 Comparison: ENV vs Mounted Config

Aspect ENV Variables Mounted Config
Complexity Medium Simple
Validation Strict (can cause issues) Minimal (tor validates)
Debugging Harder Easier (just cat file)
Updates Restart container Edit file + restart
Recommended No ⚠️ Yes
Use Case Quick testing Production

Recommendation: Always use mounted config for production deployments.


🎯 Pre-Migration Checklist

For All Migrations

  • Current fingerprint saved to file
  • Volumes backed up with timestamps
  • Old container can be removed (stopped first)
  • Firewall rules documented
  • Testing plan prepared

For Bridge from Official Image

  • Volume ownership fix command prepared
  • bridge.conf file created and customized
  • Backup includes pt_state/obfs4_state.json
  • Expected fingerprint documented

Post-Migration

  • Fingerprint matches backup
  • Container starts without errors
  • Bootstrap reaches 100%
  • Diagnostic tools work (status, health, fingerprint, gen-family)
  • Monitoring updated (if applicable)

📚 Additional Resources

  • Security Policy: ../SECURITY.md
  • General Migration Guide: MIGRATION.md
  • Troubleshooting: docs/TROUBLESHOOTING-BRIDGE-MIGRATION.md
  • Tools Documentation: docs/TOOLS.md
  • Deployment Guide: docs/DEPLOYMENT.md

🔒 Security Notes

What's Fixed in v1.1.1

  1. Command Injection (CRITICAL): OBFS4V_* variables now validated with whitelist
  2. Health Check (CRITICAL): Works with both mounted and ENV configs
  3. Input Validation (CRITICAL): Comprehensive validation with whitespace trimming
  4. Permissions (HIGH): Removed non-functional chown attempt
  5. Contact Info Validation (HIGH): Fixed false positives

Risk Assessment

Before Migration: MEDIUM (using v1.1.0 with known vulnerabilities) After Migration: LOW (all critical vulnerabilities patched)

Recommendation: Migrate as soon as possible to address security fixes.


Last Updated: 2025-12-05 Validated with production deployments