mirror of
https://github.com/r3bo0tbx1/tor-guard-relay.git
synced 2026-04-06 00:32:04 +02:00
v1.1.1 Security Hardening & Config Enhancement 🛡️✨
🚀 Major architectural release with a near full rewrite of the entrypoint, validation system, diagnostics, and templates. The image is now ~20MB, fully busybox based, more secure, and more flexible for relay and bridge operators. 🔧 Critical Fixes - Busybox compatible rewrite of OBFS4V_* parsing for values with spaces. - Rewritten TOR_CONTACT_INFO validation to prevent crash loops. - Restored bootstrap logs with Log notice stdout. - Fixed ENV healthchecks and validation order. - Resolved busybox regex and quoting issues across the script. ✨ Features and Enhancements - Added PT_PORT with complete obfs4 bridge compatibility. - Support for OR_PORT, PT_PORT, EMAIL, and NICKNAME. - Rewritten bandwidth logic with correct Rate and Burst translation. - Unified guard, exit, and bridge via TOR_RELAY_MODE. - Integrated obfs4 with rewritten diagnostics for status, health, fingerprint, and bridge-line. - Reliable ENV only mode without torrc files. 📦 Build Improvements - Image reduced ~45MB to ~20MB with busybox only tools. - Rewritten healthcheck for ENV and mounted configs. - Four diagnostic tools rewritten to pure busybox sh. - Weekly rebuilds with latest Alpine and Tor. 📚 Templates and Documentation - All templates rewritten and updated with bandwidth options and naming alternatives. - Updated Cosmos and Docker Compose templates for bridge, guard, exit. - New templates README with full deployment, migration, and config comparisons. - Revised Claude file with clearer differences and bandwidth notes. 🔒 Security Hardening - 32 vulnerabilities fixed across critical, high, medium, low categories. - Non root runtime with UID 100. - Strict OBFS4V_* whitelist and rewritten validation. - No exposed diagnostics ports, docker exec only. - Smaller attack surface with removed binaries. 🚀 Migration Notes - From v1.1.0: direct upgrade, no config changes, fingerprint preserved. - From official obfs4 bridge: one time UID fix required, full ENV compatibility afterward. - Templates include both TOR_ and official naming for smooth migration. 🧩 Compatibility - Alpine 3.22.2 base, latest Tor from edge. - AMD64 and ARM64 supported. - Works with Docker, Compose, Cosmos Cloud, Portainer.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# 🚀 Deployment Guide - Tor Guard Relay v1.1
|
||||
# 🚀 Deployment Guide - Tor Guard Relay v1.1.1
|
||||
|
||||
Complete deployment instructions for various hosting environments.
|
||||
Complete deployment instructions for guard, exit, and bridge relays across various hosting environments.
|
||||
|
||||
---
|
||||
|
||||
@@ -11,6 +11,8 @@ Complete deployment instructions for various hosting environments.
|
||||
- [Method 2: Docker Compose](#method-2-docker-compose)
|
||||
- [Method 3: Cosmos Cloud](#method-3-cosmos-cloud)
|
||||
- [Method 4: Portainer](#method-4-portainer)
|
||||
- [Multi-Mode Deployment](#multi-mode-deployment)
|
||||
- [ENV-Based Deployment](#env-based-deployment)
|
||||
- [Post-Deployment Verification](#post-deployment-verification)
|
||||
- [Firewall Configuration](#firewall-configuration)
|
||||
- [Hosting Provider Recommendations](#hosting-provider-recommendations)
|
||||
@@ -25,8 +27,8 @@ Before deploying, ensure you have:
|
||||
- ✅ **Root or sudo access** on your server
|
||||
- ✅ **Static public IP address**
|
||||
- ✅ **Sufficient bandwidth** (10+ Mbps recommended)
|
||||
- ✅ **Open firewall ports** (9001/tcp at minimum)
|
||||
- ✅ **Prepared configuration file** (`relay.conf`)
|
||||
- ✅ **Open firewall ports** (9001/tcp minimum, 9030/tcp recommended for guard/exit, 9002/tcp for bridges)
|
||||
- ✅ **Prepared configuration** (config file OR environment variables)
|
||||
|
||||
---
|
||||
|
||||
@@ -43,34 +45,38 @@ Create `relay.conf` file:
|
||||
mkdir -p ~/tor-relay
|
||||
cd ~/tor-relay
|
||||
|
||||
# Download example config
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/examples/relay.conf
|
||||
# Download example config (guard relay)
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/examples/relay-guard.conf
|
||||
|
||||
# edit
|
||||
nano relay.conf
|
||||
# Edit configuration
|
||||
nano relay-guard.conf
|
||||
```
|
||||
|
||||
**Minimum required edits:**
|
||||
- `Nickname` - Your relay name
|
||||
- `ContactInfo` - Your email
|
||||
- `ORPort` - Usually 9001
|
||||
- `ORPort` - Usually 9001 or 443
|
||||
- `RelayBandwidthRate` - Your bandwidth limit
|
||||
|
||||
### Step 2: Pull the Image
|
||||
|
||||
```bash
|
||||
# From GitHub Container Registry (recommended)
|
||||
docker pull ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# Or from Docker Hub
|
||||
docker pull r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Step 3: Run the Container
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name guard-relay \
|
||||
--name tor-relay \
|
||||
--network host \
|
||||
-v ~/tor-relay/relay.conf:/etc/tor/torrc:ro \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v tor-guard-logs:/var/log/tor \
|
||||
-v ~/tor-relay/relay-guard.conf:/etc/tor/torrc:ro \
|
||||
-v tor-data:/var/lib/tor \
|
||||
-v tor-logs:/var/log/tor \
|
||||
--restart unless-stopped \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
@@ -79,13 +85,15 @@ docker run -d \
|
||||
|
||||
```bash
|
||||
# Check container is running
|
||||
docker ps | grep guard-relay
|
||||
docker ps | grep tor-relay
|
||||
|
||||
# Check logs
|
||||
docker logs -f guard-relay
|
||||
# Check logs and bootstrap progress
|
||||
docker logs -f tor-relay
|
||||
|
||||
# Run diagnostics
|
||||
docker exec guard-relay relay-status
|
||||
# Run diagnostics (4 tools available)
|
||||
docker exec tor-relay status # Full health report with emojis
|
||||
docker exec tor-relay health # JSON health data
|
||||
docker exec tor-relay fingerprint # Show fingerprint + Tor Metrics URL
|
||||
```
|
||||
|
||||
---
|
||||
@@ -104,11 +112,11 @@ cd ~/tor-relay
|
||||
### Step 2: Download Files
|
||||
|
||||
```bash
|
||||
# Download docker-compose.yml
|
||||
# Download docker-compose.yml (guard relay with mounted config)
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/docker-compose.yml
|
||||
|
||||
# Download example config
|
||||
curl -o relay.conf https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/examples/relay.conf
|
||||
curl -o relay.conf https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/examples/relay-guard.conf
|
||||
```
|
||||
|
||||
### Step 3: Edit Configuration
|
||||
@@ -132,7 +140,7 @@ docker-compose up -d
|
||||
docker-compose logs -f
|
||||
|
||||
# Check status
|
||||
docker-compose exec tor-guard-relay relay-status
|
||||
docker-compose exec tor-relay status
|
||||
```
|
||||
|
||||
### Step 5: Manage Deployment
|
||||
@@ -158,8 +166,8 @@ docker-compose stats
|
||||
|
||||
Perfect for users with [Cosmos Cloud](https://cosmos-cloud.io/) - a modern Docker management interface.
|
||||
|
||||
> **About Cosmos Cloud**: Created by [azukaar](https://github.com/azukaar), Cosmos Cloud is a self-hosted platform for managing Docker containers with a beautiful UI, automatic HTTPS, integrated auth, and smart automation features. It's like Portainer meets Traefik meets simplicity.
|
||||
>
|
||||
> **About Cosmos Cloud**: Created by [azukaar](https://github.com/azukaar), Cosmos Cloud is a self-hosted platform for managing Docker containers with a beautiful UI, automatic HTTPS, integrated auth, and smart automation features.
|
||||
>
|
||||
> - 🌐 **Website**: https://cosmos-cloud.io/
|
||||
> - 📦 **GitHub**: https://github.com/azukaar/Cosmos-Server
|
||||
> - 📖 **Docs**: https://cosmos-cloud.io/doc
|
||||
@@ -181,7 +189,7 @@ sudo mkdir -p /opt/tor-relay
|
||||
sudo nano /opt/tor-relay/relay.conf
|
||||
```
|
||||
|
||||
Paste your relay configuration (see [example config](../examples/relay.conf)).
|
||||
Paste your relay configuration (see [example config](../examples/relay-guard.conf)).
|
||||
|
||||
**Important**: Edit at minimum:
|
||||
- `Nickname` - Your relay name
|
||||
@@ -199,15 +207,15 @@ sudo chmod 600 /opt/tor-relay/relay.conf
|
||||
2. Navigate to **ServApps** → **Import Compose File**
|
||||
3. Download our Cosmos configuration:
|
||||
```bash
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/cosmos-compose.json
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/cosmos-compose-guard.json
|
||||
```
|
||||
4. Upload or paste the JSON content
|
||||
5. **Optional**: Edit timezone if needed (default: `Asia/Tokyo`)
|
||||
5. **Optional**: Edit timezone if needed (default: `UTC`)
|
||||
```json
|
||||
"TZ=Asia/Tokyo" // Change to your timezone
|
||||
"TZ=UTC" // Universal (default)
|
||||
"TZ=America/New_York" // US East Coast
|
||||
"TZ=Europe/London" // UK
|
||||
"TZ=UTC" // Universal
|
||||
"TZ=Asia/Tokyo" // Japan
|
||||
```
|
||||
|
||||
### Step 3: Deploy
|
||||
@@ -215,7 +223,7 @@ sudo chmod 600 /opt/tor-relay/relay.conf
|
||||
1. Review the configuration
|
||||
2. Click **Create**
|
||||
3. Wait for container to start
|
||||
4. Navigate to **ServApps** → **TorGuardRelay**
|
||||
4. Navigate to **ServApps** → **TorRelay**
|
||||
5. Click **Logs** to monitor bootstrap progress
|
||||
|
||||
### Step 4: Verify Deployment
|
||||
@@ -223,7 +231,7 @@ sudo chmod 600 /opt/tor-relay/relay.conf
|
||||
From Cosmos UI, click **Console** (or use SSH):
|
||||
|
||||
```bash
|
||||
docker exec TorGuardRelay relay-status
|
||||
docker exec tor-relay status
|
||||
```
|
||||
|
||||
Look for:
|
||||
@@ -257,8 +265,6 @@ Cosmos will:
|
||||
- 📧 Notify you when updates are available
|
||||
- 🔁 Automatically restart with new version
|
||||
|
||||
You can also manually trigger updates from the Cosmos UI.
|
||||
|
||||
---
|
||||
|
||||
## Method 4: Portainer
|
||||
@@ -272,7 +278,7 @@ Navigate to your Portainer instance (usually `https://your-server:9443`)
|
||||
### Step 2: Create Stack
|
||||
|
||||
1. Click **Stacks** → **Add Stack**
|
||||
2. Name it: `tor-guard-relay`
|
||||
2. Name it: `tor-relay`
|
||||
3. Choose **Web editor**
|
||||
|
||||
### Step 3: Paste Stack Definition
|
||||
@@ -281,9 +287,9 @@ Navigate to your Portainer instance (usually `https://your-server:9443`)
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
tor-guard-relay:
|
||||
tor-relay:
|
||||
image: ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
container_name: guard-relay
|
||||
container_name: tor-relay
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
volumes:
|
||||
@@ -298,16 +304,193 @@ volumes:
|
||||
|
||||
### Step 4: Upload Configuration
|
||||
|
||||
1. Click **Volumes** → **Add Volume**
|
||||
2. Name: `tor-config`
|
||||
3. Use **File Upload** to upload your `relay.conf`
|
||||
1. SSH to your server and create config:
|
||||
```bash
|
||||
sudo mkdir -p /opt/tor-relay
|
||||
sudo nano /opt/tor-relay/relay.conf
|
||||
```
|
||||
2. Paste your relay configuration and save
|
||||
|
||||
### Step 5: Deploy
|
||||
|
||||
1. Click **Deploy the stack**
|
||||
2. Navigate to **Containers** → `guard-relay`
|
||||
2. Navigate to **Containers** → `tor-relay`
|
||||
3. Click **Logs** to monitor
|
||||
4. Click **Console** → Connect to run diagnostics
|
||||
4. Click **Console** → Connect to run diagnostics:
|
||||
```bash
|
||||
status
|
||||
health
|
||||
fingerprint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multi-Mode Deployment
|
||||
|
||||
v1.1.1 supports **guard**, **exit**, and **bridge** relays in a single container.
|
||||
|
||||
### Guard/Middle Relay (Default)
|
||||
|
||||
```bash
|
||||
# With mounted config
|
||||
docker run -d \
|
||||
--name tor-guard \
|
||||
--network host \
|
||||
-v ~/relay-guard.conf:/etc/tor/torrc:ro \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# With ENV variables
|
||||
docker run -d \
|
||||
--name tor-guard \
|
||||
--network host \
|
||||
-e TOR_RELAY_MODE=guard \
|
||||
-e TOR_NICKNAME=MyGuardRelay \
|
||||
-e TOR_CONTACT_INFO=tor@example.com \
|
||||
-e TOR_ORPORT=9001 \
|
||||
-e TOR_DIRPORT=9030 \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Exit Relay
|
||||
|
||||
```bash
|
||||
# With mounted config (recommended for exits)
|
||||
docker run -d \
|
||||
--name tor-exit \
|
||||
--network host \
|
||||
-v ~/relay-exit.conf:/etc/tor/torrc:ro \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# With ENV variables
|
||||
docker run -d \
|
||||
--name tor-exit \
|
||||
--network host \
|
||||
-e TOR_RELAY_MODE=exit \
|
||||
-e TOR_NICKNAME=MyExitRelay \
|
||||
-e TOR_CONTACT_INFO=tor@example.com \
|
||||
-e TOR_ORPORT=9001 \
|
||||
-e TOR_DIRPORT=9030 \
|
||||
-e TOR_EXIT_POLICY="accept *:80,accept *:443,reject *:*" \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Bridge Relay (obfs4)
|
||||
|
||||
```bash
|
||||
# With mounted config
|
||||
docker run -d \
|
||||
--name tor-bridge \
|
||||
--network host \
|
||||
-v ~/relay-bridge.conf:/etc/tor/torrc:ro \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# With ENV variables
|
||||
docker run -d \
|
||||
--name tor-bridge \
|
||||
--network host \
|
||||
-e TOR_RELAY_MODE=bridge \
|
||||
-e TOR_NICKNAME=MyBridge \
|
||||
-e TOR_CONTACT_INFO=tor@example.com \
|
||||
-e TOR_ORPORT=9001 \
|
||||
-e TOR_OBFS4_PORT=9002 \
|
||||
-v tor-data:/var/lib/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# Get bridge line for sharing
|
||||
docker exec tor-bridge bridge-line
|
||||
```
|
||||
|
||||
**Templates:**
|
||||
- Guard: [docker-compose-guard-env.yml](../templates/docker-compose-guard-env.yml)
|
||||
- Exit: [docker-compose-exit.yml](../templates/docker-compose-exit.yml)
|
||||
- Bridge: [docker-compose-bridge.yml](../templates/docker-compose-bridge.yml)
|
||||
|
||||
---
|
||||
|
||||
## ENV-Based Deployment
|
||||
|
||||
v1.1.1 supports full configuration via environment variables (no config file needed).
|
||||
|
||||
### Supported Environment Variables
|
||||
|
||||
#### Core Configuration
|
||||
- `TOR_RELAY_MODE` - guard, exit, or bridge (default: guard)
|
||||
- `TOR_NICKNAME` - Relay nickname (required for ENV config)
|
||||
- `TOR_CONTACT_INFO` - Contact email (required for ENV config)
|
||||
- `TOR_ORPORT` - ORPort (default: 9001)
|
||||
- `TOR_DIRPORT` - DirPort for guard/exit (default: 9030, set to 0 to disable)
|
||||
- `TOR_OBFS4_PORT` - obfs4 port for bridge mode (default: 9002)
|
||||
|
||||
#### Bandwidth Limits
|
||||
- `TOR_BANDWIDTH_RATE` - Rate limit (e.g., "50 MBytes")
|
||||
- `TOR_BANDWIDTH_BURST` - Burst limit (e.g., "100 MBytes")
|
||||
|
||||
#### Exit Policy (exit mode only)
|
||||
- `TOR_EXIT_POLICY` - Custom exit policy (e.g., "accept *:80,accept *:443,reject *:*")
|
||||
|
||||
#### Official Tor Project Bridge Naming (Drop-in Compatibility)
|
||||
- `NICKNAME` - Maps to TOR_NICKNAME
|
||||
- `EMAIL` - Maps to TOR_CONTACT_INFO
|
||||
- `OR_PORT` - Maps to TOR_ORPORT
|
||||
- `PT_PORT` - Maps to TOR_OBFS4_PORT (auto-enables bridge mode)
|
||||
- `OBFS4V_*` - Additional torrc options
|
||||
|
||||
### Docker Compose with ENV
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
tor-relay:
|
||||
image: ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
container_name: tor-relay
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
TOR_RELAY_MODE: guard
|
||||
TOR_NICKNAME: MyRelay
|
||||
TOR_CONTACT_INFO: tor@example.com
|
||||
TOR_ORPORT: 9001
|
||||
TOR_DIRPORT: 9030
|
||||
TOR_BANDWIDTH_RATE: 50 MBytes
|
||||
TOR_BANDWIDTH_BURST: 100 MBytes
|
||||
volumes:
|
||||
- tor-data:/var/lib/tor
|
||||
|
||||
volumes:
|
||||
tor-data:
|
||||
```
|
||||
|
||||
### Drop-in Replacement for Official Bridge
|
||||
|
||||
Fully compatible with `thetorproject/obfs4-bridge`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
obfs4-bridge:
|
||||
image: ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
container_name: obfs4-bridge
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
# Official Tor Project ENV naming
|
||||
NICKNAME: MyBridge
|
||||
EMAIL: tor@example.com
|
||||
OR_PORT: 9001
|
||||
PT_PORT: 9002 # Auto-enables bridge mode
|
||||
volumes:
|
||||
- obfs4-data:/var/lib/tor
|
||||
|
||||
volumes:
|
||||
obfs4-data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -318,7 +501,7 @@ After deploying with any method, verify your relay is working:
|
||||
### 1. Check Container Status
|
||||
|
||||
```bash
|
||||
docker ps | grep guard-relay
|
||||
docker ps | grep tor-relay
|
||||
```
|
||||
|
||||
Expected output:
|
||||
@@ -327,28 +510,57 @@ CONTAINER ID IMAGE STATUS
|
||||
abc123def456 ghcr.io/r3bo0tbx1/onion-relay:latest Up 5 minutes (healthy)
|
||||
```
|
||||
|
||||
### 2. Run Full Diagnostic
|
||||
### 2. Run Diagnostics
|
||||
|
||||
v1.1.1 provides **4 diagnostic tools**:
|
||||
|
||||
```bash
|
||||
docker exec guard-relay relay-status
|
||||
# Full health report with emojis
|
||||
docker exec tor-relay status
|
||||
|
||||
# JSON health data (for automation)
|
||||
docker exec tor-relay health
|
||||
|
||||
# Show fingerprint + Tor Metrics URL
|
||||
docker exec tor-relay fingerprint
|
||||
|
||||
# Get bridge line (bridge mode only)
|
||||
docker exec tor-relay bridge-line
|
||||
```
|
||||
|
||||
Look for:
|
||||
**Expected output from `status`:**
|
||||
- ✅ `Bootstrapped 100% (done): Done`
|
||||
- ✅ `ORPort is reachable from the outside`
|
||||
- ✅ No recent errors
|
||||
|
||||
### 3. Check Your Fingerprint
|
||||
### 3. Monitor Bootstrap Progress
|
||||
|
||||
```bash
|
||||
docker exec guard-relay fingerprint
|
||||
# Stream logs to see bootstrap progress (0-100%)
|
||||
docker logs -f tor-relay
|
||||
|
||||
# Check JSON health
|
||||
docker exec tor-relay health
|
||||
```
|
||||
|
||||
**Example JSON output:**
|
||||
```json
|
||||
{
|
||||
"status": "up",
|
||||
"bootstrap": 100,
|
||||
"reachable": true,
|
||||
"fingerprint": "1234567890ABCDEF...",
|
||||
"nickname": "MyRelay",
|
||||
"uptime_seconds": 3600
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Wait for Network Recognition
|
||||
|
||||
- **10-30 minutes**: Bootstrap completes (100%)
|
||||
- **1-2 hours**: Relay appears on Tor Metrics
|
||||
- **24-48 hours**: Full statistics available
|
||||
- **8+ days**: Eligible for Guard flag
|
||||
- **8+ days**: Eligible for Guard flag (guard relays only)
|
||||
|
||||
Search for your relay:
|
||||
- **Clearnet**: https://metrics.torproject.org/rs.html
|
||||
@@ -358,14 +570,26 @@ Search for your relay:
|
||||
|
||||
## Firewall Configuration
|
||||
|
||||
### Required Ports
|
||||
|
||||
| Relay Type | Ports to Open |
|
||||
|------------|---------------|
|
||||
| **Guard/Middle** | 9001/tcp (ORPort), 9030/tcp (DirPort) |
|
||||
| **Exit** | 9001/tcp (ORPort), 9030/tcp (DirPort) |
|
||||
| **Bridge** | 9001/tcp (ORPort), 9002/tcp (obfs4) |
|
||||
|
||||
> **Note:** All ports are configurable via ENV variables or config file.
|
||||
|
||||
### UFW (Ubuntu/Debian)
|
||||
|
||||
```bash
|
||||
# Allow ORPort (required)
|
||||
sudo ufw allow 9001/tcp
|
||||
# Guard/Exit relay
|
||||
sudo ufw allow 9001/tcp # ORPort
|
||||
sudo ufw allow 9030/tcp # DirPort
|
||||
|
||||
# Allow DirPort (optional but recommended)
|
||||
sudo ufw allow 9030/tcp
|
||||
# Bridge relay
|
||||
sudo ufw allow 9001/tcp # ORPort
|
||||
sudo ufw allow 9002/tcp # obfs4 port
|
||||
|
||||
# Reload firewall
|
||||
sudo ufw reload
|
||||
@@ -377,12 +601,14 @@ sudo ufw status
|
||||
### firewalld (RHEL/CentOS)
|
||||
|
||||
```bash
|
||||
# Allow ORPort
|
||||
# Guard/Exit relay
|
||||
sudo firewall-cmd --permanent --add-port=9001/tcp
|
||||
|
||||
# Allow DirPort
|
||||
sudo firewall-cmd --permanent --add-port=9030/tcp
|
||||
|
||||
# Bridge relay
|
||||
sudo firewall-cmd --permanent --add-port=9001/tcp
|
||||
sudo firewall-cmd --permanent --add-port=9002/tcp
|
||||
|
||||
# Reload
|
||||
sudo firewall-cmd --reload
|
||||
|
||||
@@ -393,12 +619,14 @@ sudo firewall-cmd --list-all
|
||||
### iptables (Advanced)
|
||||
|
||||
```bash
|
||||
# Allow ORPort
|
||||
# Guard/Exit relay
|
||||
sudo iptables -A INPUT -p tcp --dport 9001 -j ACCEPT
|
||||
|
||||
# Allow DirPort
|
||||
sudo iptables -A INPUT -p tcp --dport 9030 -j ACCEPT
|
||||
|
||||
# Bridge relay
|
||||
sudo iptables -A INPUT -p tcp --dport 9001 -j ACCEPT
|
||||
sudo iptables -A INPUT -p tcp --dport 9002 -j ACCEPT
|
||||
|
||||
# Save rules
|
||||
sudo iptables-save > /etc/iptables/rules.v4
|
||||
```
|
||||
@@ -445,19 +673,34 @@ Don't forget to open ports in your cloud provider's firewall:
|
||||
- Dynamic IP issues
|
||||
- Home network security risks
|
||||
|
||||
**Recommendation**: Use VPS for guard relays, home for bridges only.
|
||||
**Recommendation**: Use VPS for guard/exit relays, home for bridges only.
|
||||
|
||||
---
|
||||
|
||||
## Monitoring Setup
|
||||
|
||||
### Option 1: Manual Monitoring Script
|
||||
### Option 1: JSON Health API
|
||||
|
||||
v1.1.1 provides a `health` tool that outputs JSON for monitoring integration:
|
||||
|
||||
```bash
|
||||
# Get health status (raw JSON)
|
||||
docker exec tor-relay health
|
||||
|
||||
# Parse with jq (requires jq on host)
|
||||
docker exec tor-relay health | jq .
|
||||
|
||||
# Check specific field
|
||||
docker exec tor-relay health | jq .bootstrap
|
||||
```
|
||||
|
||||
### Option 2: Manual Monitoring Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Save as: /usr/local/bin/check-tor-relay.sh
|
||||
|
||||
CONTAINER="guard-relay"
|
||||
CONTAINER="tor-relay"
|
||||
|
||||
echo "🧅 Tor Relay Health Check - $(date)"
|
||||
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
@@ -469,9 +712,9 @@ if ! docker ps | grep -q "$CONTAINER"; then
|
||||
fi
|
||||
|
||||
# Run diagnostics
|
||||
docker exec "$CONTAINER" relay-status
|
||||
docker exec "$CONTAINER" status
|
||||
|
||||
# Check for errors
|
||||
# Check for errors in recent logs
|
||||
ERRORS=$(docker logs "$CONTAINER" --tail 100 2>&1 | grep -iE "(error|critical)" | wc -l)
|
||||
|
||||
if [ "$ERRORS" -gt 5 ]; then
|
||||
@@ -492,9 +735,31 @@ crontab -e
|
||||
0 */6 * * * /usr/local/bin/check-tor-relay.sh >> /var/log/tor-health.log 2>&1
|
||||
```
|
||||
|
||||
### Option 2: Prometheus + Grafana
|
||||
### Option 3: Prometheus + Grafana
|
||||
|
||||
Coming soon! Watch the repo for monitoring stack templates.
|
||||
Use the `health` tool with Prometheus node_exporter textfile collector:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Save as: /usr/local/bin/tor-metrics-exporter.sh
|
||||
# Requires: jq installed on host (apt install jq / brew install jq)
|
||||
|
||||
HEALTH=$(docker exec tor-relay health)
|
||||
|
||||
# Export metrics
|
||||
echo "$HEALTH" | jq -r '
|
||||
"tor_bootstrap_percent \(.bootstrap)",
|
||||
"tor_reachable \(if .reachable then 1 else 0 end)",
|
||||
"tor_uptime_seconds \(.uptime_seconds // 0)"
|
||||
' > /var/lib/node_exporter/textfile_collector/tor.prom
|
||||
```
|
||||
|
||||
Run via cron every 5 minutes:
|
||||
```bash
|
||||
*/5 * * * * /usr/local/bin/tor-metrics-exporter.sh
|
||||
```
|
||||
|
||||
> 📖 **Complete guide:** See [Monitoring Documentation](MONITORING.md) for advanced setups.
|
||||
|
||||
---
|
||||
|
||||
@@ -504,9 +769,9 @@ Coming soon! Watch the repo for monitoring stack templates.
|
||||
|
||||
```bash
|
||||
# Check Docker logs
|
||||
docker logs guard-relay --tail 50
|
||||
docker logs tor-relay --tail 50
|
||||
|
||||
# Validate configuration
|
||||
# Validate configuration (if using mounted config)
|
||||
docker run --rm \
|
||||
-v ~/tor-relay/relay.conf:/etc/tor/torrc:ro \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest \
|
||||
@@ -527,10 +792,26 @@ sudo netstat -tulpn | grep 9001
|
||||
|
||||
```bash
|
||||
# Verify mount path
|
||||
docker inspect guard-relay | grep -A 10 Mounts
|
||||
docker inspect tor-relay | grep -A 10 Mounts
|
||||
|
||||
# Check file permissions
|
||||
ls -la ~/tor-relay/relay.conf
|
||||
|
||||
# View generated config (ENV mode)
|
||||
docker exec tor-relay cat /etc/tor/torrc
|
||||
```
|
||||
|
||||
### Bootstrap Stuck
|
||||
|
||||
```bash
|
||||
# Check bootstrap progress
|
||||
docker exec tor-relay health | jq .bootstrap
|
||||
|
||||
# Check for errors
|
||||
docker logs tor-relay --tail 100 | grep -i error
|
||||
|
||||
# Verify ports are open
|
||||
docker exec tor-relay status
|
||||
```
|
||||
|
||||
---
|
||||
@@ -540,16 +821,18 @@ ls -la ~/tor-relay/relay.conf
|
||||
After successful deployment:
|
||||
|
||||
1. ✅ Monitor logs for 24 hours
|
||||
2. ✅ Verify on Tor Metrics
|
||||
3. ✅ Set up monitoring/alerts
|
||||
2. ✅ Verify on Tor Metrics (https://metrics.torproject.org/rs.html)
|
||||
3. ✅ Set up monitoring/alerts with `health` JSON API
|
||||
4. ✅ Join [Tor Relay Operators mailing list](https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays)
|
||||
5. ✅ Consider running multiple relays
|
||||
5. ✅ Consider running multiple relays for better network contribution
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
- 📖 [Main README](../README.md)
|
||||
- 🔧 [Tools Documentation](TOOLS.md) - Complete guide to the 4 diagnostic tools
|
||||
- 📊 [Monitoring Guide](MONITORING.md) - External monitoring integration
|
||||
- 🐛 [Report Issues](https://github.com/r3bo0tbx1/tor-guard-relay/issues)
|
||||
- 💬 [Tor Project Forum](https://forum.torproject.net/)
|
||||
- 📧 [Relay Operators List](https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays)
|
||||
- 📧 [Relay Operators List](https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays)
|
||||
|
||||
392
docs/LOCAL-TESTING.md
Normal file
392
docs/LOCAL-TESTING.md
Normal file
@@ -0,0 +1,392 @@
|
||||
# Local Testing Guide
|
||||
|
||||
**For Contributors and Developers Only**
|
||||
|
||||
> ⚠️ **Most Users Should Use Published Images**
|
||||
>
|
||||
> If you're deploying a Tor relay, use the published images from Docker Hub or GHCR:
|
||||
> - **Docker Hub**: `r3bo0tbx1/onion-relay:latest`
|
||||
> - **GHCR**: `ghcr.io/r3bo0tbx1/onion-relay:latest`
|
||||
>
|
||||
> This guide is for **contributors** who are modifying code, scripts, or workflows.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
- Docker 20.10+
|
||||
- Docker Compose (optional)
|
||||
- Local Docker Registry v2 (for development workflow)
|
||||
- dos2unix (for Windows contributors)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Development Workflow with Local Registry
|
||||
|
||||
### Step 1: Start Local Registry
|
||||
|
||||
```bash
|
||||
# Start a local Docker Registry v2
|
||||
docker run -d -p 5000:5000 --name registry registry:2
|
||||
|
||||
# Verify it's running
|
||||
curl http://localhost:5000/v2/_catalog
|
||||
```
|
||||
|
||||
### Step 2: Build and Push to Local Registry
|
||||
|
||||
```bash
|
||||
# Clone repository
|
||||
git clone https://github.com/r3bo0tbx1/tor-guard-relay.git
|
||||
cd tor-guard-relay
|
||||
|
||||
# Normalize line endings (important for Windows)
|
||||
dos2unix docker-entrypoint.sh healthcheck.sh tools/* 2>/dev/null || true
|
||||
|
||||
# Build image
|
||||
docker build -t localhost:5000/onion-relay:test .
|
||||
|
||||
# Push to local registry
|
||||
docker push localhost:5000/onion-relay:test
|
||||
|
||||
# Verify in registry
|
||||
curl http://localhost:5000/v2/onion-relay/tags/list
|
||||
```
|
||||
|
||||
### Step 3: Test from Local Registry
|
||||
|
||||
```bash
|
||||
# Pull from local registry
|
||||
docker pull localhost:5000/onion-relay:test
|
||||
|
||||
# Run test container
|
||||
docker run --rm localhost:5000/onion-relay:test status
|
||||
```
|
||||
|
||||
**Why use local registry?**
|
||||
- Mirrors production workflow
|
||||
- Tests multi-arch builds locally
|
||||
- Easier to share with team members on same network
|
||||
- Closer to CI/CD environment
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Test Scenarios
|
||||
|
||||
### Test 1: Guard Relay (Mounted Config)
|
||||
|
||||
```bash
|
||||
# Create test config
|
||||
cat > /tmp/relay-test.conf << 'EOF'
|
||||
Nickname TestGuardRelay
|
||||
ContactInfo test@example.com
|
||||
ORPort 9001
|
||||
DirPort 9030
|
||||
ExitRelay 0
|
||||
ExitPolicy reject *:*
|
||||
DataDirectory /var/lib/tor
|
||||
Log notice file /var/log/tor/notices.log
|
||||
SocksPort 0
|
||||
EOF
|
||||
|
||||
# Run guard relay
|
||||
docker run -d \
|
||||
--name test-guard \
|
||||
--network host \
|
||||
-v /tmp/relay-test.conf:/etc/tor/torrc:ro \
|
||||
-v test-guard-data:/var/lib/tor \
|
||||
-v test-guard-logs:/var/log/tor \
|
||||
localhost:5000/onion-relay:test
|
||||
|
||||
# Verify
|
||||
docker logs test-guard
|
||||
# Expected: ✅ Using mounted configuration: /etc/tor/torrc
|
||||
|
||||
# Test diagnostics
|
||||
docker exec test-guard status
|
||||
docker exec test-guard health | jq .
|
||||
docker exec test-guard fingerprint
|
||||
|
||||
# Cleanup
|
||||
docker stop test-guard && docker rm test-guard
|
||||
docker volume rm test-guard-data test-guard-logs
|
||||
```
|
||||
|
||||
### Test 2: Bridge with Official ENV Naming
|
||||
|
||||
**Tests drop-in compatibility with `thetorproject/obfs4-bridge`:**
|
||||
|
||||
```bash
|
||||
# Run bridge with official naming
|
||||
docker run -d \
|
||||
--name test-bridge \
|
||||
--network host \
|
||||
-e OR_PORT=9001 \
|
||||
-e PT_PORT=9002 \
|
||||
-e EMAIL="test@example.com" \
|
||||
-e NICKNAME=TestBridge \
|
||||
-e OBFS4_ENABLE_ADDITIONAL_VARIABLES=1 \
|
||||
-e OBFS4V_AddressDisableIPv6=0 \
|
||||
-e OBFS4V_MaxMemInQueues="512 MB" \
|
||||
-v test-bridge-data:/var/lib/tor \
|
||||
localhost:5000/onion-relay:test
|
||||
|
||||
# Verify auto-detection
|
||||
docker logs test-bridge
|
||||
# Expected:
|
||||
# ✅ Configuration generated from ENV vars
|
||||
# 🌐 Relay mode: bridge (auto-detected from PT_PORT)
|
||||
|
||||
# Check generated torrc
|
||||
docker exec test-bridge cat /etc/tor/torrc
|
||||
# Should include:
|
||||
# - BridgeRelay 1
|
||||
# - ServerTransportPlugin obfs4 exec /usr/bin/lyrebird
|
||||
# - ServerTransportListenAddr obfs4 0.0.0.0:9002
|
||||
# - MaxMemInQueues 512 MB
|
||||
|
||||
# Verify lyrebird is running
|
||||
docker exec test-bridge pgrep -a lyrebird
|
||||
|
||||
# Test bridge-line tool (after bootstrap)
|
||||
docker exec test-bridge bridge-line
|
||||
|
||||
# Cleanup
|
||||
docker stop test-bridge && docker rm test-bridge
|
||||
docker volume rm test-bridge-data
|
||||
```
|
||||
|
||||
### Test 3: Bridge with Mounted Config (Recommended)
|
||||
|
||||
```bash
|
||||
# Create bridge config
|
||||
cat > /tmp/bridge-test.conf << 'EOF'
|
||||
Nickname TestBridgeMounted
|
||||
ContactInfo test@example.com
|
||||
ORPort 9001
|
||||
SocksPort 0
|
||||
DataDirectory /var/lib/tor
|
||||
Log notice file /var/log/tor/notices.log
|
||||
BridgeRelay 1
|
||||
PublishServerDescriptor bridge
|
||||
ServerTransportPlugin obfs4 exec /usr/bin/lyrebird
|
||||
ServerTransportListenAddr obfs4 0.0.0.0:9002
|
||||
ExtORPort auto
|
||||
MaxMemInQueues 512 MB
|
||||
AddressDisableIPv6 0
|
||||
EOF
|
||||
|
||||
# Run bridge
|
||||
docker run -d \
|
||||
--name test-bridge-mounted \
|
||||
--network host \
|
||||
-v /tmp/bridge-test.conf:/etc/tor/torrc:ro \
|
||||
-v test-bridge-mounted-data:/var/lib/tor \
|
||||
localhost:5000/onion-relay:test
|
||||
|
||||
# Verify
|
||||
docker logs test-bridge-mounted
|
||||
# Expected: ✅ Using mounted configuration: /etc/tor/torrc
|
||||
|
||||
# Cleanup
|
||||
docker stop test-bridge-mounted && docker rm test-bridge-mounted
|
||||
docker volume rm test-bridge-mounted-data
|
||||
```
|
||||
|
||||
### Test 4: Health Check
|
||||
|
||||
```bash
|
||||
# Test health check script directly
|
||||
docker run --rm \
|
||||
-v /tmp/relay-test.conf:/etc/tor/torrc:ro \
|
||||
localhost:5000/onion-relay:test \
|
||||
/usr/local/bin/healthcheck.sh
|
||||
|
||||
# Expected: exit code 0 (healthy)
|
||||
echo "Health check status: $?"
|
||||
|
||||
# Test with invalid config
|
||||
docker run --rm localhost:5000/onion-relay:test sh -c \
|
||||
"echo 'InvalidDirective BadValue' > /etc/tor/torrc && /usr/local/bin/healthcheck.sh"
|
||||
|
||||
# Expected: exit code 1 (unhealthy)
|
||||
echo "Health check status: $?"
|
||||
```
|
||||
|
||||
### Test 5: Input Validation
|
||||
|
||||
```bash
|
||||
# Test nickname validation (should fail - too long)
|
||||
docker run --rm \
|
||||
-e TOR_NICKNAME="ThisNicknameIsWayTooLongAndShouldFail" \
|
||||
-e TOR_CONTACT_INFO="test@example.com" \
|
||||
localhost:5000/onion-relay:test 2>&1 | grep -i error
|
||||
|
||||
# Test port validation (should fail - invalid port)
|
||||
docker run --rm \
|
||||
-e TOR_NICKNAME="TestRelay" \
|
||||
-e TOR_CONTACT_INFO="test@example.com" \
|
||||
-e TOR_ORPORT="99999" \
|
||||
localhost:5000/onion-relay:test 2>&1 | grep -i error
|
||||
|
||||
# Test bandwidth format (should succeed)
|
||||
docker run --rm \
|
||||
-e TOR_NICKNAME="TestRelay" \
|
||||
-e TOR_CONTACT_INFO="test@example.com" \
|
||||
-e TOR_BANDWIDTH_RATE="10 MBytes" \
|
||||
localhost:5000/onion-relay:test \
|
||||
sh -c "cat /etc/tor/torrc | grep -i bandwidth"
|
||||
```
|
||||
|
||||
### Test 6: OBFS4V_* Whitelist Security
|
||||
|
||||
```bash
|
||||
# Test whitelisted variable (should succeed)
|
||||
docker run --rm \
|
||||
-e OR_PORT=9001 \
|
||||
-e PT_PORT=9002 \
|
||||
-e EMAIL="test@example.com" \
|
||||
-e NICKNAME=TestSec \
|
||||
-e OBFS4_ENABLE_ADDITIONAL_VARIABLES=1 \
|
||||
-e OBFS4V_MaxMemInQueues="512 MB" \
|
||||
localhost:5000/onion-relay:test \
|
||||
sh -c "cat /etc/tor/torrc | grep MaxMemInQueues"
|
||||
|
||||
# Test non-whitelisted variable (should warn and skip)
|
||||
docker run --rm \
|
||||
-e OR_PORT=9001 \
|
||||
-e PT_PORT=9002 \
|
||||
-e EMAIL="test@example.com" \
|
||||
-e NICKNAME=TestSec \
|
||||
-e OBFS4_ENABLE_ADDITIONAL_VARIABLES=1 \
|
||||
-e OBFS4V_EvilDirective="malicious value" \
|
||||
localhost:5000/onion-relay:test 2>&1 | grep -i "not in whitelist"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Verification Checklist
|
||||
|
||||
After building locally:
|
||||
|
||||
- [ ] All tool scripts are executable (`ls -l /usr/local/bin/`)
|
||||
- [ ] Tool scripts have no .sh extensions
|
||||
- [ ] All scripts use `#!/bin/sh` shebang
|
||||
- [ ] Build info exists (`cat /build-info.txt`)
|
||||
- [ ] Tor version is current (`tor --version`)
|
||||
- [ ] Lyrebird is available (`/usr/bin/lyrebird --version`)
|
||||
- [ ] Health check works for both mounted and ENV configs
|
||||
- [ ] Diagnostic tools produce correct output
|
||||
- [ ] Input validation catches invalid values
|
||||
- [ ] OBFS4V_* whitelist blocks dangerous options
|
||||
- [ ] Image size is ~20MB (`docker images localhost:5000/onion-relay:test`)
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Debugging
|
||||
|
||||
### View Generated torrc
|
||||
|
||||
```bash
|
||||
# For ENV-based config
|
||||
docker run --rm \
|
||||
-e TOR_NICKNAME=Debug \
|
||||
-e TOR_CONTACT_INFO=debug@test.com \
|
||||
localhost:5000/onion-relay:test \
|
||||
cat /etc/tor/torrc
|
||||
|
||||
# For mounted config
|
||||
docker run --rm \
|
||||
-v /tmp/relay-test.conf:/etc/tor/torrc:ro \
|
||||
localhost:5000/onion-relay:test \
|
||||
cat /etc/tor/torrc
|
||||
```
|
||||
|
||||
### Check Script Syntax
|
||||
|
||||
```bash
|
||||
# Validate all shell scripts
|
||||
for script in docker-entrypoint.sh healthcheck.sh tools/*; do
|
||||
echo "Checking $script..."
|
||||
sh -n "$script" && echo "✅ OK" || echo "❌ FAIL"
|
||||
done
|
||||
```
|
||||
|
||||
### Test Permissions
|
||||
|
||||
```bash
|
||||
# Check file permissions in image
|
||||
docker run --rm localhost:5000/onion-relay:test ls -la /usr/local/bin/
|
||||
docker run --rm localhost:5000/onion-relay:test ls -ldn /var/lib/tor
|
||||
docker run --rm localhost:5000/onion-relay:test ls -ldn /var/log/tor
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Multi-Arch Testing
|
||||
|
||||
### Build for Multiple Architectures
|
||||
|
||||
```bash
|
||||
# Set up buildx (once)
|
||||
docker buildx create --name multiarch --use
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
# Build for both AMD64 and ARM64
|
||||
docker buildx build \
|
||||
--platform linux/amd64,linux/arm64 \
|
||||
-t localhost:5000/onion-relay:multiarch \
|
||||
--push \
|
||||
.
|
||||
|
||||
# Test on current architecture
|
||||
docker pull localhost:5000/onion-relay:multiarch
|
||||
docker run --rm localhost:5000/onion-relay:multiarch cat /build-info.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧹 Cleanup
|
||||
|
||||
```bash
|
||||
# Stop and remove all test containers
|
||||
docker ps -a | grep test- | awk '{print $1}' | xargs docker rm -f
|
||||
|
||||
# Remove test volumes
|
||||
docker volume ls | grep test- | awk '{print $2}' | xargs docker volume rm
|
||||
|
||||
# Remove test images
|
||||
docker rmi localhost:5000/onion-relay:test
|
||||
docker rmi localhost:5000/onion-relay:multiarch
|
||||
|
||||
# Stop local registry
|
||||
docker stop registry && docker rm registry
|
||||
|
||||
# Clean up test configs
|
||||
rm -f /tmp/relay-test.conf /tmp/bridge-test.conf
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📚 See Also
|
||||
|
||||
- **[Contributing Guide](../CONTRIBUTING.md)** - How to contribute code
|
||||
- **[Deployment Guide](DEPLOYMENT.md)** - Production deployment methods
|
||||
- **[Migration Guide](../MIGRATION-V1.1.X.md)** - Upgrading between versions
|
||||
- **[Security Audit Report](../SECURITY-AUDIT-REPORT.md)** - Security fixes
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips for Contributors
|
||||
|
||||
1. **Always test with local registry** - Mirrors production workflow
|
||||
2. **Test both mounted config and ENV variables** - Both must work
|
||||
3. **Verify input validation** - Test edge cases and invalid inputs
|
||||
4. **Check all diagnostic tools** - Ensure they work correctly
|
||||
5. **Test on multiple architectures** - If you can (buildx helps)
|
||||
6. **Run security validation** - Use `scripts/utilities/security-validation-tests.sh`
|
||||
7. **Update documentation** - If you change behavior
|
||||
|
||||
---
|
||||
|
||||
*This guide is for development and testing. Production users should use published images from Docker Hub or GHCR.*
|
||||
474
docs/MIGRATION-V1.1.X.md
Normal file
474
docs/MIGRATION-V1.1.X.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# Stop container
|
||||
docker stop <container>
|
||||
|
||||
# Backup volumes
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v /tmp:/backup \
|
||||
alpine:3.22.2 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.22.2 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.22.2 cat /data/fingerprint > /tmp/fingerprint-backup.txt
|
||||
```
|
||||
|
||||
### Step 2: Update Configuration
|
||||
|
||||
**Cosmos JSON changes**:
|
||||
```json
|
||||
{
|
||||
"image": "r3bo0tbx1/onion-relay:1.1.1", // ← 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
|
||||
|
||||
```bash
|
||||
docker rm <container>
|
||||
```
|
||||
|
||||
### Step 4: Deploy Updated Container
|
||||
|
||||
- Import updated JSON in Cosmos UI
|
||||
- Or redeploy with `docker-compose up -d`
|
||||
|
||||
### Step 5: Verify
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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"
|
||||
```
|
||||
|
||||
### Recommended Approach: Use Mounted Config
|
||||
|
||||
**Why?**
|
||||
- ✅ More reliable than ENV variables
|
||||
- ✅ Bypasses validation complexity
|
||||
- ✅ Same as guard relay (consistent approach)
|
||||
- ✅ Easier to troubleshoot
|
||||
|
||||
### Step 1: Backup Everything
|
||||
|
||||
```bash
|
||||
# Stop container
|
||||
docker stop obfs4-bridge
|
||||
|
||||
# Backup volume (CRITICAL!)
|
||||
docker run --rm \
|
||||
-v obfs4-data:/data \
|
||||
-v /tmp:/backup \
|
||||
alpine:3.22.2 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.22.2 cat /data/fingerprint > /tmp/bridge-fingerprint-backup.txt
|
||||
cat /tmp/bridge-fingerprint-backup.txt
|
||||
```
|
||||
|
||||
### Step 2: Fix Volume Ownership (CRITICAL!)
|
||||
|
||||
```bash
|
||||
# Check current ownership (should be 101:101)
|
||||
docker run --rm -v obfs4-data:/data alpine:3.22.2 ls -ldn /data
|
||||
# Output: drwx------ ... 101 101 ...
|
||||
|
||||
# Fix ownership: 101 → 100
|
||||
docker run --rm -v obfs4-data:/data alpine:3.22.2 chown -R 100:101 /data
|
||||
|
||||
# Verify fix
|
||||
docker run --rm -v obfs4-data:/data alpine:3.22.2 ls -ldn /data
|
||||
# Output: drwx------ ... 100 101 ... ← MUST show 100!
|
||||
|
||||
# Verify key files are readable
|
||||
docker run --rm -v obfs4-data:/data alpine:3.22.2 ls -la /data/keys/
|
||||
# Should show files owned by 100:101
|
||||
```
|
||||
|
||||
### Step 3: Create Bridge Config File
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
docker rm obfs4-bridge
|
||||
```
|
||||
|
||||
### Step 5: Deploy with Mounted Config
|
||||
|
||||
**Cosmos JSON**:
|
||||
```json
|
||||
{
|
||||
"minVersion": "0.8.0",
|
||||
"services": {
|
||||
"obfs4-bridge": {
|
||||
"image": "r3bo0tbx1/onion-relay:1.1.1",
|
||||
"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
|
||||
|
||||
```bash
|
||||
# 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)
|
||||
|
||||
```bash
|
||||
# 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**:
|
||||
```bash
|
||||
docker stop obfs4-bridge
|
||||
docker run --rm -v obfs4-data:/data alpine:3.22.2 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:
|
||||
```bash
|
||||
docker stop obfs4-bridge
|
||||
docker run --rm -v obfs4-data:/data -v /tmp:/backup alpine:3.22.2 \
|
||||
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**:
|
||||
```bash
|
||||
# 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:1.1.1 --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)
|
||||
- [ ] Monitoring updated (if applicable)
|
||||
|
||||
---
|
||||
|
||||
## 📚 Additional Resources
|
||||
|
||||
- **Security Audit Report**: `SECURITY-AUDIT-REPORT.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-11-13*
|
||||
*Validated with production deployments*
|
||||
@@ -1,490 +1,371 @@
|
||||
# 🔄 Migration Guide
|
||||
# Migration Guide - Tor Guard Relay
|
||||
|
||||
Guide for migrating between Tor Guard Relay versions and from other Tor relay setups.
|
||||
This document provides general migration guidance for Tor Guard Relay deployments.
|
||||
|
||||
For **specific v1.1.0 → v1.1.1 migration**, see [`MIGRATION-V1.1.X.md`](MIGRATION-V1.1.X.md).
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
## 📋 General Migration Principles
|
||||
|
||||
This guide covers:
|
||||
- ✅ Migrating from v1.0 to v1.1
|
||||
- ✅ Migrating from official Tor Docker images
|
||||
- ✅ Migrating from manual Tor installations
|
||||
- ✅ Preserving relay identity and keys
|
||||
- ✅ Zero-downtime migration strategies
|
||||
|
||||
---
|
||||
|
||||
## 🚀 v1.0 → v1.1 Migration
|
||||
|
||||
### What's New in v1.1
|
||||
|
||||
**Major Changes:**
|
||||
- ✅ Reorganized repository structure (tools/, templates/, docs/)
|
||||
- ✅ Enhanced CI/CD workflows with multi-arch builds
|
||||
- ✅ New monitoring tools (dashboard, metrics-http)
|
||||
- ✅ Improved docker-entrypoint.sh with better error handling
|
||||
- ✅ Comprehensive documentation (TOOLS.md, MONITORING.md)
|
||||
- ✅ Updated Prometheus and Grafana templates
|
||||
- ✅ Better health checks and diagnostics
|
||||
|
||||
**Breaking Changes:**
|
||||
- ⚠️ **None** - v1.1 is backward compatible with v1.0
|
||||
- Volume mounts and configuration remain unchanged
|
||||
- All tools maintain the same interface
|
||||
|
||||
### Migration Steps
|
||||
|
||||
#### Method 1: In-Place Update (Recommended)
|
||||
### 1. Always Backup First
|
||||
|
||||
```bash
|
||||
# 1. Stop the current relay
|
||||
docker stop tor-relay
|
||||
|
||||
# 2. Backup relay data (CRITICAL - preserves identity)
|
||||
# Backup data volume
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v ~/backups:/backup \
|
||||
alpine tar czf /backup/tor-backup-$(date +%Y%m%d).tar.gz -C /data .
|
||||
-v <volume-name>:/data \
|
||||
-v /tmp:/backup \
|
||||
alpine:3.22.2 tar czf /backup/tor-backup-$(date +%Y%m%d).tar.gz /data
|
||||
|
||||
# 3. Pull new v1.1 image
|
||||
docker pull ghcr.io/r3bo0tbx1/onion-relay:v1.1
|
||||
# Verify backup
|
||||
ls -lh /tmp/tor-backup-*.tar.gz
|
||||
|
||||
# 4. Update container (data volumes persist automatically)
|
||||
docker rm tor-relay
|
||||
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
--restart unless-stopped \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v tor-guard-logs:/var/log/tor \
|
||||
-v $(pwd)/relay.conf:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
-e ENABLE_METRICS=true \
|
||||
-e ENABLE_HEALTH_CHECK=true \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:v1.1
|
||||
|
||||
# 5. Verify relay identity is preserved
|
||||
docker exec tor-relay fingerprint
|
||||
# Should show same fingerprint as before
|
||||
|
||||
# 6. Check new tools are available
|
||||
docker exec tor-relay status
|
||||
docker exec tor-relay health | jq .
|
||||
# Save fingerprint
|
||||
docker run --rm -v <volume-name>:/data alpine:3.22.2 cat /data/fingerprint > /tmp/fingerprint-backup.txt
|
||||
```
|
||||
|
||||
#### Method 2: Docker Compose Update
|
||||
### 2. Fingerprint Preservation
|
||||
|
||||
```bash
|
||||
# 1. Update docker-compose.yml
|
||||
sed -i 's/:latest/:v1.1/g' docker-compose.yml
|
||||
**Your relay identity is stored in**:
|
||||
- `/var/lib/tor/keys/secret_id_key` (RSA identity)
|
||||
- `/var/lib/tor/keys/ed25519_master_id_secret_key` (Ed25519 identity)
|
||||
- `/var/lib/tor/pt_state/obfs4_state.json` (bridge credentials, bridges only)
|
||||
|
||||
# 2. Pull new image
|
||||
docker-compose pull
|
||||
**CRITICAL**: These files must be preserved or your relay will get a new fingerprint.
|
||||
|
||||
# 3. Recreate containers (volumes persist)
|
||||
docker-compose up -d
|
||||
### 3. Configuration Approaches
|
||||
|
||||
# 4. Verify
|
||||
docker-compose exec tor-relay status
|
||||
**Recommended: Mounted Config File**
|
||||
```yaml
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /path/to/relay.conf
|
||||
target: /etc/tor/torrc
|
||||
read_only: true
|
||||
```
|
||||
|
||||
### Verification Checklist
|
||||
**Alternative: Environment Variables**
|
||||
```yaml
|
||||
environment:
|
||||
- TOR_RELAY_MODE=guard
|
||||
- TOR_NICKNAME=MyRelay
|
||||
- TOR_CONTACT_INFO=email@example.com
|
||||
```
|
||||
|
||||
After migration, verify:
|
||||
**Priority**: Mounted file > ENV variables
|
||||
|
||||
- [ ] Relay fingerprint matches pre-migration
|
||||
- [ ] Bootstrap completes to 100%
|
||||
- [ ] ORPort is reachable
|
||||
- [ ] Metrics endpoint works (if enabled)
|
||||
- [ ] New tools respond: `status`, `health`, `dashboard`
|
||||
- [ ] Logs show no errors
|
||||
- [ ] Relay appears on Tor Metrics with same identity
|
||||
---
|
||||
|
||||
## 🔄 Migration Scenarios
|
||||
|
||||
### Scenario 1: Upgrading Between Versions (Same Image)
|
||||
|
||||
**Example**: v1.1.0 → v1.1.1
|
||||
|
||||
**Steps**:
|
||||
1. Stop container
|
||||
2. Backup volumes
|
||||
3. Remove container (`docker rm`)
|
||||
4. Pull new image version
|
||||
5. Create new container with same volumes
|
||||
6. Verify fingerprint matches
|
||||
|
||||
**Expected Downtime**: 1-5 minutes
|
||||
|
||||
**See**: [`MIGRATION-V1.1.X.md`](MIGRATION-V1.1.X.md) for detailed instructions
|
||||
|
||||
### Scenario 2: Migrating from Official Tor Images
|
||||
|
||||
**Example**: `thetorproject/obfs4-bridge` → `r3bo0tbx1/onion-relay`
|
||||
|
||||
**Challenges**:
|
||||
- Different base OS (Debian → Alpine)
|
||||
- Different user UID (101 → 100)
|
||||
- Volume ownership needs fixing
|
||||
|
||||
**Steps**:
|
||||
1. Backup everything
|
||||
2. **Fix volume ownership**: `chown -R 100:101`
|
||||
3. Create config file (recommended over ENV)
|
||||
4. Deploy new container
|
||||
5. Verify fingerprint preserved
|
||||
|
||||
**Expected Downtime**: 5-10 minutes
|
||||
|
||||
**See**: [`MIGRATION-V1.1.X.md`](MIGRATION-V1.1.X.md) - Migration Path 2
|
||||
|
||||
### Scenario 3: Changing Relay Type
|
||||
|
||||
**Example**: Guard → Exit, Guard → Bridge
|
||||
|
||||
**Warning**: ⚠️ This changes your relay's role and requires careful consideration.
|
||||
|
||||
**Steps**:
|
||||
1. Understand legal implications (especially for exit relays)
|
||||
2. Update configuration
|
||||
3. Restart container
|
||||
4. Monitor logs for warnings
|
||||
5. Wait 24-48 hours for Tor network to update
|
||||
|
||||
**Fingerprint**: Preserved ✅
|
||||
|
||||
### Scenario 4: Moving to New Server
|
||||
|
||||
**Steps**:
|
||||
1. **On old server**:
|
||||
- Stop container
|
||||
- Backup volume to tarball
|
||||
- Transfer tarball to new server
|
||||
|
||||
2. **On new server**:
|
||||
- Create volume
|
||||
- Restore from tarball
|
||||
- Deploy container with same configuration
|
||||
- Verify fingerprint
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
# Quick verification script
|
||||
#!/bin/bash
|
||||
echo "🧅 v1.1 Migration Verification"
|
||||
echo "================================"
|
||||
# Old server - create backup
|
||||
docker run --rm -v tor-data:/data -v $PWD:/backup alpine:3.22.2 \
|
||||
tar czf /backup/tor-data.tar.gz /data
|
||||
|
||||
echo -n "✓ Container running: "
|
||||
docker ps | grep -q tor-relay && echo "YES" || echo "NO"
|
||||
# Transfer tor-data.tar.gz to new server
|
||||
|
||||
echo -n "✓ Fingerprint: "
|
||||
docker exec tor-relay fingerprint | grep -q "Fingerprint:" && echo "OK" || echo "FAILED"
|
||||
|
||||
echo -n "✓ Health check: "
|
||||
docker exec tor-relay health | jq -e '.status == "healthy"' &>/dev/null && echo "HEALTHY" || echo "CHECK FAILED"
|
||||
|
||||
echo -n "✓ Metrics: "
|
||||
curl -s http://localhost:9035/metrics | grep -q "tor_relay_" && echo "OK" || echo "DISABLED/FAILED"
|
||||
|
||||
echo -n "✓ Bootstrap: "
|
||||
docker exec tor-relay health | jq -r '.bootstrap.percent' | grep -q "100" && echo "100%" || echo "IN PROGRESS"
|
||||
|
||||
echo "================================"
|
||||
echo "Migration verification complete!"
|
||||
# New server - restore
|
||||
docker volume create tor-data
|
||||
docker run --rm -v tor-data:/data -v $PWD:/backup alpine:3.22.2 \
|
||||
tar xzf /backup/tor-data.tar.gz -C /
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Migrating from Official Tor Docker
|
||||
## ⚙️ Container vs Image vs Configuration
|
||||
|
||||
If you're currently using the official Tor Project Docker images:
|
||||
**Image**: The Docker image (`r3bo0tbx1/onion-relay:1.1.1`)
|
||||
- Contains Tor binary, scripts, OS
|
||||
- Immutable
|
||||
- Can be updated independently
|
||||
|
||||
### Pre-Migration
|
||||
**Container**: Running instance
|
||||
- Created from image
|
||||
- Has specific configuration
|
||||
- Must be recreated to use new image
|
||||
|
||||
```bash
|
||||
# 1. Note your current relay fingerprint
|
||||
docker exec <your-tor-container> cat /var/lib/tor/fingerprint
|
||||
# Save this - you'll verify it matches after migration
|
||||
**Configuration**: Your relay settings
|
||||
- Mounted file (`/etc/tor/torrc`)
|
||||
- OR environment variables
|
||||
- Persists across container recreations
|
||||
|
||||
# 2. Backup relay keys (CRITICAL)
|
||||
docker cp <your-tor-container>:/var/lib/tor/keys ./tor-keys-backup
|
||||
|
||||
# 3. Backup your torrc configuration
|
||||
docker cp <your-tor-container>:/etc/tor/torrc ./torrc-backup
|
||||
```
|
||||
|
||||
### Migration
|
||||
|
||||
```bash
|
||||
# 4. Stop official Tor container
|
||||
docker stop <your-tor-container>
|
||||
|
||||
# 5. Create volume for Tor Guard Relay
|
||||
docker volume create tor-guard-data
|
||||
docker volume create tor-guard-logs
|
||||
|
||||
# 6. Restore keys to new volume
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v $(pwd)/tor-keys-backup:/backup:ro \
|
||||
alpine sh -c "cp -a /backup/* /data/keys/ && chown -R 100:101 /data"
|
||||
|
||||
# 7. Start Tor Guard Relay with same config
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
--restart unless-stopped \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v tor-guard-logs:/var/log/tor \
|
||||
-v $(pwd)/torrc-backup:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# 8. Verify fingerprint matches
|
||||
docker exec tor-relay fingerprint
|
||||
```
|
||||
|
||||
### Configuration Differences
|
||||
|
||||
Official Tor images vs. Tor Guard Relay:
|
||||
|
||||
| Feature | Official Tor | Tor Guard Relay |
|
||||
|---------|-------------|-----------------|
|
||||
| Base image | Debian/Alpine | Alpine (minimal) |
|
||||
| Built-in tools | None | 9 diagnostic tools |
|
||||
| Monitoring | External | Built-in Prometheus |
|
||||
| Health checks | Basic | Comprehensive JSON |
|
||||
| Dashboard | None | Built-in HTML dashboard |
|
||||
| Auto-healing | No | Yes (permissions) |
|
||||
| Architecture | Manual | Multi-arch auto |
|
||||
**Volumes**: Your relay data
|
||||
- Identity keys
|
||||
- State information
|
||||
- Logs
|
||||
- Persists across container recreations
|
||||
|
||||
---
|
||||
|
||||
## 🖥️ Migrating from Manual Installation
|
||||
## 🔍 Verification Checklist
|
||||
|
||||
If you're running Tor directly on a server (not containerized):
|
||||
After any migration:
|
||||
|
||||
### Pre-Migration
|
||||
|
||||
```bash
|
||||
# 1. Backup relay keys (MOST IMPORTANT)
|
||||
sudo tar czf ~/tor-keys-backup.tar.gz -C /var/lib/tor keys/
|
||||
|
||||
# 2. Backup torrc
|
||||
sudo cp /etc/tor/torrc ~/torrc-backup
|
||||
|
||||
# 3. Note fingerprint
|
||||
sudo cat /var/lib/tor/fingerprint
|
||||
```
|
||||
|
||||
### Migration Strategy
|
||||
|
||||
**Option A: Side-by-Side (Zero Downtime)**
|
||||
|
||||
```bash
|
||||
# 1. Change manual Tor ORPort to temporary port
|
||||
sudo sed -i 's/ORPort 9001/ORPort 9002/g' /etc/tor/torrc
|
||||
sudo systemctl restart tor
|
||||
|
||||
# 2. Start Docker relay on port 9001 with restored keys
|
||||
docker volume create tor-guard-data
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v ~/tor-keys-backup.tar.gz:/backup.tar.gz:ro \
|
||||
alpine sh -c "tar xzf /backup.tar.gz -C /data && chown -R 100:101 /data"
|
||||
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v $(pwd)/torrc-backup:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# 3. Wait for Docker relay to be fully bootstrapped
|
||||
docker exec tor-relay status
|
||||
|
||||
# 4. Stop manual Tor
|
||||
sudo systemctl stop tor
|
||||
sudo systemctl disable tor
|
||||
|
||||
# 5. Clean up
|
||||
docker exec tor-relay fingerprint # Verify same fingerprint
|
||||
```
|
||||
|
||||
**Option B: Replace (Requires Downtime)**
|
||||
|
||||
```bash
|
||||
# 1. Stop manual Tor
|
||||
sudo systemctl stop tor
|
||||
|
||||
# 2. Create volume and restore keys
|
||||
docker volume create tor-guard-data
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v ~/tor-keys-backup.tar.gz:/backup.tar.gz:ro \
|
||||
alpine sh -c "tar xzf /backup.tar.gz -C /data && chown -R 100:101 /data"
|
||||
|
||||
# 3. Start containerized relay
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
--restart unless-stopped \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v $(pwd)/torrc-backup:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# 4. Verify
|
||||
docker exec tor-relay fingerprint
|
||||
docker exec tor-relay status
|
||||
```
|
||||
|
||||
### Post-Migration Cleanup
|
||||
|
||||
```bash
|
||||
# Optional: Remove manual Tor installation
|
||||
sudo apt-get remove --purge tor tor-geoipdb -y
|
||||
sudo apt-get autoremove -y
|
||||
|
||||
# Optional: Clean up old data (AFTER verifying Docker relay works)
|
||||
# sudo rm -rf /var/lib/tor
|
||||
# sudo rm -rf /etc/tor
|
||||
```
|
||||
- [ ] Container starts successfully
|
||||
- [ ] No errors in logs: `docker logs <container> | grep -i error`
|
||||
- [ ] Fingerprint matches backup
|
||||
- [ ] Configuration loaded correctly
|
||||
- [ ] Bootstrap reaches 100%
|
||||
- [ ] Relay/bridge is reachable
|
||||
- [ ] Diagnostic tools work:
|
||||
- `docker exec <container> status`
|
||||
- `docker exec <container> health`
|
||||
- `docker exec <container> fingerprint`
|
||||
- [ ] Tor Metrics shows relay (after 1-2 hours)
|
||||
|
||||
---
|
||||
|
||||
## 🔑 Preserving Relay Identity
|
||||
## 🛠️ Common Migration Issues
|
||||
|
||||
**CRITICAL:** Your relay's identity is stored in these files:
|
||||
### Issue: "Permission denied" Errors
|
||||
|
||||
```
|
||||
/var/lib/tor/keys/
|
||||
├── ed25519_master_id_public_key
|
||||
├── ed25519_master_id_secret_key
|
||||
├── ed25519_signing_cert
|
||||
├── ed25519_signing_secret_key
|
||||
└── secret_id_key
|
||||
```
|
||||
|
||||
**To preserve your relay's reputation and identity:**
|
||||
|
||||
1. **Always backup these files before migration**
|
||||
2. **Never lose these files** - they cannot be recovered
|
||||
3. **Verify fingerprint after migration** matches original
|
||||
4. **If fingerprint changes** - you've lost your identity and must start over
|
||||
|
||||
### Emergency Recovery
|
||||
|
||||
If you've lost your keys but have a backup:
|
||||
**Cause**: Volume ownership mismatch
|
||||
|
||||
**Fix**:
|
||||
```bash
|
||||
# Create new volume
|
||||
docker volume create tor-guard-data-recovered
|
||||
# Check ownership
|
||||
docker run --rm -v <volume>:/data alpine:3.22.2 ls -ldn /data
|
||||
|
||||
# Restore keys
|
||||
docker run --rm \
|
||||
-v tor-guard-data-recovered:/data \
|
||||
-v ~/tor-keys-backup.tar.gz:/backup.tar.gz:ro \
|
||||
alpine sh -c "mkdir -p /data/keys && tar xzf /backup.tar.gz -C /data && chown -R 100:101 /data"
|
||||
|
||||
# Start relay with recovered volume
|
||||
docker run -d \
|
||||
--name tor-relay-recovered \
|
||||
-v tor-guard-data-recovered:/var/lib/tor \
|
||||
-v $(pwd)/relay.conf:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
|
||||
# Verify fingerprint
|
||||
docker exec tor-relay-recovered fingerprint
|
||||
# Fix if needed (Alpine tor user is UID 100)
|
||||
docker run --rm -v <volume>:/data alpine:3.22.2 chown -R 100:101 /data
|
||||
```
|
||||
|
||||
---
|
||||
### Issue: Fingerprint Changed
|
||||
|
||||
## 🚨 Common Migration Issues
|
||||
**Cause**: Identity keys not preserved
|
||||
|
||||
### Issue: Fingerprint Changed After Migration
|
||||
|
||||
**Cause:** Keys were not properly preserved or restored with wrong permissions.
|
||||
|
||||
**Solution:**
|
||||
**Fix**: Restore from backup:
|
||||
```bash
|
||||
# Stop relay
|
||||
docker stop tor-relay
|
||||
|
||||
# Restore keys backup
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
-v ~/tor-keys-backup.tar.gz:/backup.tar.gz:ro \
|
||||
alpine sh -c "rm -rf /data/keys && tar xzf /backup.tar.gz -C /data && chown -R 100:101 /data"
|
||||
|
||||
# Restart
|
||||
docker start tor-relay
|
||||
docker stop <container>
|
||||
docker run --rm -v <volume>:/data -v /tmp:/backup alpine:3.22.2 \
|
||||
sh -c 'rm -rf /data/* && tar xzf /backup/tor-backup-*.tar.gz -C /'
|
||||
docker start <container>
|
||||
```
|
||||
|
||||
### Issue: Permission Denied Errors
|
||||
### Issue: Container Restart Loop
|
||||
|
||||
**Cause:** Wrong file ownership in restored keys.
|
||||
|
||||
**Solution:**
|
||||
**Debug**:
|
||||
```bash
|
||||
# Fix permissions (auto-healed on next restart, but can force)
|
||||
docker run --rm \
|
||||
-v tor-guard-data:/data \
|
||||
alpine sh -c "chown -R 100:101 /data && chmod 700 /data/keys && chmod 600 /data/keys/*"
|
||||
```
|
||||
|
||||
### Issue: Bootstrap Fails After Migration
|
||||
|
||||
**Cause:** Network connectivity or configuration issues.
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Run network diagnostics
|
||||
docker exec tor-relay net-check
|
||||
|
||||
# Check logs
|
||||
docker exec tor-relay view-logs --errors
|
||||
docker logs <container> --tail 50
|
||||
|
||||
# Verify configuration
|
||||
docker exec tor-relay cat /etc/tor/torrc
|
||||
# Verify using correct image
|
||||
docker inspect <container> --format='{{.Image}}'
|
||||
|
||||
# Check configuration
|
||||
docker exec <container> cat /etc/tor/torrc
|
||||
```
|
||||
|
||||
### Issue: Old Tor Process Still Running
|
||||
**Common causes**:
|
||||
- Invalid configuration syntax
|
||||
- Missing required fields
|
||||
- ENV variable validation failures (use mounted config instead)
|
||||
|
||||
**Cause:** Manual Tor installation not fully stopped.
|
||||
### Issue: Health Check Failing
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Stop system Tor
|
||||
sudo systemctl stop tor
|
||||
sudo systemctl disable tor
|
||||
**Cause**: Old versions had hardcoded health check path
|
||||
|
||||
# Verify nothing on port 9001
|
||||
sudo netstat -tulpn | grep 9001
|
||||
|
||||
# Kill any remaining Tor processes
|
||||
sudo pkill -9 tor
|
||||
```
|
||||
**Fix**: Update to v1.1.1+ which includes smart healthcheck script
|
||||
|
||||
---
|
||||
|
||||
## 📊 Migration Checklist
|
||||
## 📊 Migration Planning
|
||||
|
||||
Use this checklist for smooth migrations:
|
||||
### Before Migration
|
||||
|
||||
### Pre-Migration
|
||||
- [ ] Backup relay keys (most critical)
|
||||
- [ ] Backup torrc configuration
|
||||
- [ ] Note current fingerprint
|
||||
- [ ] Test backups can be extracted
|
||||
- [ ] Document current monitoring setup
|
||||
- [ ] Check current bandwidth usage
|
||||
1. **Document current state**:
|
||||
- Image version
|
||||
- Configuration source (file or ENV)
|
||||
- Volume names
|
||||
- Port mappings
|
||||
- Current fingerprint
|
||||
|
||||
2. **Test plan**:
|
||||
- What to verify post-migration
|
||||
- Rollback procedure
|
||||
- Downtime window
|
||||
|
||||
3. **Communication**:
|
||||
- Notify users (for bridges)
|
||||
- Schedule maintenance window
|
||||
- Prepare status updates
|
||||
|
||||
### During Migration
|
||||
- [ ] Pull new image version
|
||||
- [ ] Create new volumes
|
||||
- [ ] Restore keys with correct ownership
|
||||
- [ ] Mount configuration
|
||||
- [ ] Start new container
|
||||
- [ ] Verify container starts without errors
|
||||
|
||||
### Post-Migration
|
||||
- [ ] Verify same fingerprint
|
||||
- [ ] Confirm bootstrap reaches 100%
|
||||
- [ ] Check ORPort reachability
|
||||
- [ ] Test all tools (status, health, etc.)
|
||||
- [ ] Verify metrics (if enabled)
|
||||
- [ ] Update monitoring dashboards
|
||||
- [ ] Test log access
|
||||
- [ ] Check Tor Metrics shows relay as active
|
||||
1. **Follow documented procedure**
|
||||
2. **Take backups**
|
||||
3. **Verify each step**
|
||||
4. **Don't skip verification**
|
||||
|
||||
### Cleanup (after 24h of successful operation)
|
||||
- [ ] Remove old container
|
||||
- [ ] Clean up old volumes (if not reusing)
|
||||
- [ ] Remove manual Tor installation (if applicable)
|
||||
- [ ] Archive old backups
|
||||
- [ ] Update documentation
|
||||
### After Migration
|
||||
|
||||
1. **Monitor logs for 30 minutes**
|
||||
2. **Verify fingerprint**
|
||||
3. **Check Tor Metrics after 1-2 hours**
|
||||
4. **Update documentation**
|
||||
5. **Keep backups for 7 days**
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Rollback Procedure
|
||||
## 🔒 Security Considerations
|
||||
|
||||
If migration fails and you need to rollback:
|
||||
### UID/GID Consistency
|
||||
|
||||
```bash
|
||||
# 1. Stop new container
|
||||
docker stop tor-relay
|
||||
docker rm tor-relay
|
||||
**This image uses**:
|
||||
- User: `tor`
|
||||
- UID: 100
|
||||
- GID: 101
|
||||
|
||||
# 2. If upgrading from v1.0: revert to old image
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
--restart unless-stopped \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v tor-guard-logs:/var/log/tor \
|
||||
-v $(pwd)/relay.conf:/etc/tor/torrc:ro \
|
||||
-p 9001:9001 \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:v1.0
|
||||
**When migrating from Debian-based images**:
|
||||
- Old UID: 101
|
||||
- **Must fix volume ownership**
|
||||
|
||||
# 3. If migrating from manual: restore system Tor
|
||||
sudo systemctl start tor
|
||||
sudo systemctl enable tor
|
||||
### File Permissions
|
||||
|
||||
# 4. Verify fingerprint matches original
|
||||
**Expected permissions**:
|
||||
```
|
||||
drwx------ /var/lib/tor (700, owned by tor)
|
||||
drwxr-xr-x /var/log/tor (755, owned by tor)
|
||||
-rw------- keys/* (600, owned by tor)
|
||||
```
|
||||
|
||||
---
|
||||
### Capabilities
|
||||
|
||||
## 📚 Related Documentation
|
||||
**Minimal required**:
|
||||
```yaml
|
||||
cap_add:
|
||||
- NET_BIND_SERVICE # Only if using ports < 1024
|
||||
```
|
||||
|
||||
- [Deployment Guide](./DEPLOYMENT.md) - Fresh installation
|
||||
- [Backup Guide](./BACKUP.md) - Data persistence strategies
|
||||
- [Tools Reference](./TOOLS.md) - Using diagnostic tools
|
||||
- [Monitoring Guide](./MONITORING.md) - Setting up monitoring
|
||||
**Avoid granting unnecessary capabilities**.
|
||||
|
||||
---
|
||||
|
||||
## 💡 Migration Tips
|
||||
## 📚 Resources
|
||||
|
||||
1. **Always test in staging first** if you have multiple relays
|
||||
2. **Migrate during low-traffic periods** to minimize impact
|
||||
3. **Keep old backups for 30 days** after successful migration
|
||||
4. **Document your specific configuration** before starting
|
||||
5. **Have rollback plan ready** before beginning migration
|
||||
6. **Monitor closely for 24-48h** after migration
|
||||
- **v1.1.0 → v1.1.1 Migration**: [`MIGRATION-V1.1.X.md`](MIGRATION-V1.1.X.md)
|
||||
- **Deployment Guide**: [`DEPLOYMENT.md`](DEPLOYMENT.md)
|
||||
- **Troubleshooting**: [`TROUBLESHOOTING-BRIDGE-MIGRATION.md`](TROUBLESHOOTING-BRIDGE-MIGRATION.md)
|
||||
- **Tools Documentation**: [`TOOLS.md`](TOOLS.md)
|
||||
- **Security Audit**: [`../SECURITY-AUDIT-REPORT.md`](../SECURITY-AUDIT-REPORT.md)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 2025 | **Version:** 1.1
|
||||
## 🆘 Getting Help
|
||||
|
||||
If migration fails:
|
||||
|
||||
1. **Check logs**: `docker logs <container>`
|
||||
2. **Verify backup**: `ls -lh /tmp/tor-backup-*.tar.gz`
|
||||
3. **Restore from backup** if needed
|
||||
4. **Consult troubleshooting docs**
|
||||
5. **Open GitHub issue** with:
|
||||
- Migration path (what → what)
|
||||
- Error messages
|
||||
- Log output
|
||||
- Configuration (redact sensitive info)
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Quick Reference
|
||||
|
||||
### Common Commands
|
||||
|
||||
```bash
|
||||
# Backup
|
||||
docker run --rm -v <vol>:/data -v /tmp:/backup alpine:3.22.2 tar czf /backup/backup.tar.gz /data
|
||||
|
||||
# Restore
|
||||
docker run --rm -v <vol>:/data -v /tmp:/backup alpine:3.22.2 tar xzf /backup/backup.tar.gz -C /
|
||||
|
||||
# Fix ownership (Alpine)
|
||||
docker run --rm -v <vol>:/data alpine:3.22.2 chown -R 100:101 /data
|
||||
|
||||
# Get fingerprint
|
||||
docker exec <container> fingerprint
|
||||
|
||||
# Check health
|
||||
docker exec <container> health | jq .
|
||||
|
||||
# Full status
|
||||
docker exec <container> status
|
||||
```
|
||||
|
||||
### Version-Specific Migrations
|
||||
|
||||
| From | To | Guide |
|
||||
|------|-----|-------|
|
||||
| v1.1.0 | v1.1.1 | [MIGRATION-V1.1.X.md](MIGRATION-V1.1.X.md) |
|
||||
| Official bridge | v1.1.1 | [MIGRATION-V1.1.X.md](MIGRATION-V1.1.X.md) - Path 2 |
|
||||
| Future | Future | This document + version-specific guide |
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: 2025-11-13*
|
||||
|
||||
@@ -1,544 +1,456 @@
|
||||
# 📊 Monitoring & Observability Guide
|
||||
# 📊 Monitoring Guide
|
||||
|
||||
Complete guide to monitoring your Tor Guard Relay with **Prometheus**, **Grafana**, and **Alertmanager**.
|
||||
Guide to monitoring your Tor Guard Relay with external tools. The v1.1.1 ultra-optimized build (~20 MB) does not include built-in Prometheus metrics endpoints, but provides multiple alternatives for monitoring.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Overview
|
||||
|
||||
This guide covers:
|
||||
- ✅ Prometheus metrics collection
|
||||
- ✅ Grafana dashboard setup
|
||||
- ✅ Alert configuration
|
||||
- ✅ Multi-relay monitoring
|
||||
- ✅ Best practices and troubleshooting
|
||||
**What Changed in v1.1.1:**
|
||||
- ❌ Removed built-in `metrics-http` server (to reduce image size)
|
||||
- ❌ Removed Python-based dashboard
|
||||
- ✅ Kept `health` tool for JSON status output
|
||||
- ✅ Kept `status` tool for human-readable output
|
||||
- ✅ Enhanced logging for external monitoring integration
|
||||
|
||||
**Monitoring Options:**
|
||||
1. Docker health checks (built-in)
|
||||
2. `health` tool with external scrapers
|
||||
3. Log file monitoring
|
||||
4. External Prometheus exporters
|
||||
5. Cloud monitoring services
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Architecture
|
||||
## 🚀 Quick Start Options
|
||||
|
||||
```
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ Tor Relay │────▶│ Prometheus │────▶│ Grafana │
|
||||
│ :9035 │ │ :9090 │ │ :3000 │
|
||||
└─────────────┘ └──────┬──────┘ └─────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────┐
|
||||
│Alertmanager │
|
||||
│ :9093 │
|
||||
└─────────────┘
|
||||
```
|
||||
### Option 1: Docker Health Checks (Simplest)
|
||||
|
||||
**Components:**
|
||||
- **Tor Relay** - Exposes metrics via `metrics-http` tool on port 9035
|
||||
- **Prometheus** - Scrapes and stores metrics
|
||||
- **Grafana** - Visualizes metrics with dashboards
|
||||
- **Alertmanager** - Handles alerts and notifications
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### Single Relay with Monitoring
|
||||
|
||||
Use the provided Docker Compose template:
|
||||
Built-in Docker health checks automatically monitor relay status:
|
||||
|
||||
```bash
|
||||
# Download template
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/docker-compose.yml
|
||||
# Check health status
|
||||
docker inspect --format='{{.State.Health.Status}}' tor-relay
|
||||
|
||||
# Download Prometheus config
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/prometheus.yml
|
||||
|
||||
# Start services
|
||||
docker-compose up -d
|
||||
|
||||
# Access Grafana
|
||||
open http://localhost:3000
|
||||
# Get health history (requires jq on host)
|
||||
docker inspect --format='{{json .State.Health}}' tor-relay | jq
|
||||
```
|
||||
|
||||
### Multi-Relay Setup
|
||||
|
||||
For monitoring multiple relays:
|
||||
|
||||
```bash
|
||||
# Download multi-relay template
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/docker-compose-multi-relay.yml
|
||||
|
||||
# Configure and start
|
||||
docker-compose -f docker-compose-multi-relay.yml up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Metrics Reference
|
||||
|
||||
### Available Metrics
|
||||
|
||||
All metrics are prefixed with `tor_relay_` and include a `relay_name` label.
|
||||
|
||||
#### Bootstrap & Connectivity
|
||||
|
||||
```prometheus
|
||||
# Bootstrap completion percentage (0-100)
|
||||
tor_relay_bootstrap_percent{relay_name="MyRelay"} 100
|
||||
|
||||
# ORPort reachability (1=reachable, 0=unreachable)
|
||||
tor_relay_or_port_reachable{relay_name="MyRelay",port="9001"} 1
|
||||
|
||||
# DirPort reachability (1=reachable, 0=unreachable)
|
||||
tor_relay_dir_port_reachable{relay_name="MyRelay",port="9030"} 1
|
||||
```
|
||||
|
||||
#### Performance
|
||||
|
||||
```prometheus
|
||||
# Relay uptime in seconds
|
||||
tor_relay_uptime_seconds{relay_name="MyRelay"} 214830
|
||||
|
||||
# Configured bandwidth rate in bytes/sec
|
||||
tor_relay_bandwidth_rate_bytes{relay_name="MyRelay"} 52428800
|
||||
|
||||
# Configured bandwidth burst in bytes/sec
|
||||
tor_relay_bandwidth_burst_bytes{relay_name="MyRelay"} 104857600
|
||||
```
|
||||
|
||||
#### Health Status
|
||||
|
||||
```prometheus
|
||||
# Overall health status (1=healthy, 0=unhealthy)
|
||||
tor_relay_healthy{relay_name="MyRelay"} 1
|
||||
|
||||
# Error count
|
||||
tor_relay_errors_total{relay_name="MyRelay"} 0
|
||||
|
||||
# Warning count
|
||||
tor_relay_warnings_total{relay_name="MyRelay"} 0
|
||||
```
|
||||
|
||||
#### System Resources (when available)
|
||||
|
||||
```prometheus
|
||||
# CPU usage percentage
|
||||
process_cpu_seconds_total{relay_name="MyRelay"} 1234.56
|
||||
|
||||
# Memory usage in bytes
|
||||
process_resident_memory_bytes{relay_name="MyRelay"} 134217728
|
||||
|
||||
# Open file descriptors
|
||||
process_open_fds{relay_name="MyRelay"} 42
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎨 Prometheus Configuration
|
||||
|
||||
### Basic Configuration
|
||||
|
||||
**File:** `prometheus.yml`
|
||||
|
||||
**Healthcheck Configuration:**
|
||||
```yaml
|
||||
global:
|
||||
scrape_interval: 15s
|
||||
evaluation_interval: 15s
|
||||
external_labels:
|
||||
cluster: 'tor-relays'
|
||||
environment: 'production'
|
||||
# Already included in all compose templates
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "/usr/local/bin/healthcheck.sh"]
|
||||
interval: 10m
|
||||
timeout: 15s
|
||||
start_period: 30s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
# Scrape configurations
|
||||
**Monitoring:**
|
||||
- Use `docker events` to watch health changes
|
||||
- Integrate with Docker monitoring tools (Portainer, Netdata, etc.)
|
||||
- Alert on `health_status: unhealthy` events
|
||||
|
||||
---
|
||||
|
||||
### Option 2: Health Tool with External Scraper
|
||||
|
||||
Use the `health` tool's JSON output with your monitoring system:
|
||||
|
||||
**Setup Simple HTTP Wrapper:**
|
||||
```bash
|
||||
# Create simple health endpoint with netcat
|
||||
while true; do
|
||||
HEALTH=$(docker exec tor-relay health)
|
||||
echo -e "HTTP/1.1 200 OK\r\nContent-Type: application/json\r\n\r\n$HEALTH" | nc -l -p 9100
|
||||
done
|
||||
```
|
||||
|
||||
**Or use a proper wrapper script:**
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
from flask import Flask, jsonify
|
||||
import subprocess
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/health')
|
||||
def health():
|
||||
result = subprocess.run(
|
||||
['docker', 'exec', 'tor-relay', 'health'],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
return jsonify(json.loads(result.stdout))
|
||||
|
||||
@app.route('/metrics')
|
||||
def metrics():
|
||||
health_data = subprocess.run(
|
||||
['docker', 'exec', 'tor-relay', 'health'],
|
||||
capture_output=True,
|
||||
text=True
|
||||
)
|
||||
data = json.loads(health_data.stdout)
|
||||
|
||||
# Convert to Prometheus format
|
||||
metrics = f"""# HELP tor_relay_up Relay is running
|
||||
# TYPE tor_relay_up gauge
|
||||
tor_relay_up {{nickname="{data['nickname']}"}} {1 if data['status'] == 'up' else 0}
|
||||
|
||||
# HELP tor_relay_bootstrap_percent Bootstrap completion
|
||||
# TYPE tor_relay_bootstrap_percent gauge
|
||||
tor_relay_bootstrap_percent {{nickname="{data['nickname']}"}} {data['bootstrap']}
|
||||
|
||||
# HELP tor_relay_errors Error count
|
||||
# TYPE tor_relay_errors gauge
|
||||
tor_relay_errors {{nickname="{data['nickname']}"}} {data['errors']}
|
||||
"""
|
||||
return metrics, 200, {'Content-Type': 'text/plain; charset=utf-8'}
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=9100)
|
||||
```
|
||||
|
||||
**Prometheus Configuration:**
|
||||
```yaml
|
||||
scrape_configs:
|
||||
# Single relay
|
||||
- job_name: 'tor-relay'
|
||||
static_configs:
|
||||
- targets: ['tor-relay:9035']
|
||||
labels:
|
||||
relay_name: 'MyTorRelay'
|
||||
|
||||
# Multiple relays
|
||||
- job_name: 'tor-relay-multi'
|
||||
- targets: ['localhost:9100']
|
||||
scrape_interval: 60s
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Option 3: Log File Monitoring
|
||||
|
||||
Monitor Tor logs directly for events and errors:
|
||||
|
||||
**Filebeat Configuration:**
|
||||
```yaml
|
||||
# filebeat.yml
|
||||
filebeat.inputs:
|
||||
- type: log
|
||||
enabled: true
|
||||
paths:
|
||||
- /var/lib/docker/volumes/tor-guard-logs/_data/notices.log
|
||||
fields:
|
||||
service: tor-relay
|
||||
multiline:
|
||||
pattern: '^\['
|
||||
negate: true
|
||||
match: after
|
||||
|
||||
output.elasticsearch:
|
||||
hosts: ["localhost:9200"]
|
||||
index: "tor-relay-logs-%{+yyyy.MM.dd}"
|
||||
```
|
||||
|
||||
**Promtail Configuration (for Loki):**
|
||||
```yaml
|
||||
# promtail-config.yml
|
||||
server:
|
||||
http_listen_port: 9080
|
||||
|
||||
positions:
|
||||
filename: /tmp/positions.yaml
|
||||
|
||||
clients:
|
||||
- url: http://localhost:3100/loki/api/v1/push
|
||||
|
||||
scrape_configs:
|
||||
- job_name: tor-relay
|
||||
static_configs:
|
||||
- targets:
|
||||
- 'tor-relay-1:9035'
|
||||
- 'tor-relay-2:9036'
|
||||
- 'tor-relay-3:9037'
|
||||
- localhost
|
||||
labels:
|
||||
cluster: 'tor-multi-relay'
|
||||
job: tor-relay
|
||||
__path__: /var/lib/docker/volumes/tor-guard-logs/_data/*.log
|
||||
```
|
||||
|
||||
### Auto-Discovery (Docker)
|
||||
**Key Log Patterns to Monitor:**
|
||||
```bash
|
||||
# Bootstrap complete
|
||||
grep "Bootstrapped 100%" /var/log/tor/notices.log
|
||||
|
||||
For dynamic relay discovery:
|
||||
# ORPort reachability
|
||||
grep "Self-testing indicates your ORPort is reachable" /var/log/tor/notices.log
|
||||
|
||||
```yaml
|
||||
# Errors
|
||||
grep "\[err\]" /var/log/tor/notices.log
|
||||
|
||||
# Warnings
|
||||
grep "\[warn\]" /var/log/tor/notices.log
|
||||
|
||||
# Bandwidth self-test
|
||||
grep "bandwidth self-test...done" /var/log/tor/notices.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Option 4: External Prometheus Exporters
|
||||
|
||||
Use dedicated Tor exporters that parse Tor control port:
|
||||
|
||||
**Option A: tor_exporter**
|
||||
```bash
|
||||
# Install tor_exporter
|
||||
docker run -d --name tor-exporter \
|
||||
--network host \
|
||||
ghcr.io/atx/prometheus-tor_exporter:latest \
|
||||
--tor.control-address=127.0.0.1:9051
|
||||
|
||||
# Add to Prometheus
|
||||
scrape_configs:
|
||||
- job_name: 'tor-relays-docker'
|
||||
docker_sd_configs:
|
||||
- host: unix:///var/run/docker.sock
|
||||
relabel_configs:
|
||||
- source_labels: [__meta_docker_container_label_com_example_service]
|
||||
regex: 'tor-relay'
|
||||
action: keep
|
||||
- source_labels: [__meta_docker_container_name]
|
||||
target_label: relay_name
|
||||
- job_name: 'tor-exporter'
|
||||
static_configs:
|
||||
- targets: ['localhost:9099']
|
||||
```
|
||||
|
||||
**Option B: Custom exporter from health tool**
|
||||
|
||||
See Option 2 above for Python Flask example.
|
||||
|
||||
---
|
||||
|
||||
## 📈 Grafana Dashboards
|
||||
|
||||
### Pre-built Dashboard
|
||||
|
||||
A complete Grafana dashboard is provided in the repository:
|
||||
|
||||
```bash
|
||||
# Import dashboard
|
||||
curl -O https://raw.githubusercontent.com/r3bo0tbx1/tor-guard-relay/main/templates/grafana-dashboard.json
|
||||
|
||||
# In Grafana UI:
|
||||
# 1. Go to Dashboards → Import
|
||||
# 2. Upload grafana-dashboard.json
|
||||
# 3. Select Prometheus datasource
|
||||
# 4. Click Import
|
||||
```
|
||||
|
||||
### Dashboard Panels
|
||||
|
||||
The provided dashboard includes:
|
||||
|
||||
1. **Overview Row**
|
||||
- Relay Status (UP/DOWN)
|
||||
- Bootstrap Progress
|
||||
- Uptime
|
||||
- ORPort/DirPort Reachability
|
||||
|
||||
2. **Network Row**
|
||||
- Public IP Address
|
||||
- Port Status
|
||||
- Bandwidth Configuration
|
||||
|
||||
3. **Performance Row**
|
||||
- CPU Usage Graph
|
||||
- Memory Usage Graph
|
||||
- Network Traffic (if available)
|
||||
|
||||
4. **Health Row**
|
||||
- Error Count
|
||||
- Warning Count
|
||||
- Recent Issues Timeline
|
||||
|
||||
5. **Multi-Relay Row** (when monitoring multiple relays)
|
||||
- Relay Comparison Table
|
||||
- Aggregate Statistics
|
||||
|
||||
### Custom Queries
|
||||
|
||||
Example PromQL queries for custom panels:
|
||||
|
||||
```prometheus
|
||||
# Average bootstrap across all relays
|
||||
avg(tor_relay_bootstrap_percent)
|
||||
|
||||
# Relays not fully bootstrapped
|
||||
count(tor_relay_bootstrap_percent < 100)
|
||||
|
||||
# Total bandwidth capacity
|
||||
sum(tor_relay_bandwidth_rate_bytes)
|
||||
|
||||
# Relay availability (24h)
|
||||
avg_over_time(tor_relay_healthy[24h])
|
||||
|
||||
# Unreachable relays
|
||||
count(tor_relay_or_port_reachable == 0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Alerting
|
||||
|
||||
### Alert Rules
|
||||
|
||||
**File:** `prometheus-alerts.yml`
|
||||
### Option 5: Cloud Monitoring Services
|
||||
|
||||
**DataDog:**
|
||||
```yaml
|
||||
groups:
|
||||
- name: tor_relay_alerts
|
||||
interval: 30s
|
||||
rules:
|
||||
# Critical: Relay is down
|
||||
- alert: TorRelayDown
|
||||
expr: up{job="tor-relay"} == 0
|
||||
for: 5m
|
||||
labels:
|
||||
severity: critical
|
||||
alert_type: availability
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} is down"
|
||||
description: "Relay has been unreachable for 5 minutes"
|
||||
# datadog.yaml
|
||||
logs:
|
||||
- type: file
|
||||
path: /var/lib/docker/volumes/tor-guard-logs/_data/notices.log
|
||||
service: tor-relay
|
||||
source: tor
|
||||
|
||||
# Critical: Bootstrap not complete
|
||||
- alert: TorBootstrapIncomplete
|
||||
expr: tor_relay_bootstrap_percent < 100
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
alert_type: bootstrap
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} bootstrap incomplete"
|
||||
description: "Bootstrap at {{ $value }}% for 10+ minutes"
|
||||
|
||||
# Critical: ORPort unreachable
|
||||
- alert: TorORPortUnreachable
|
||||
expr: tor_relay_or_port_reachable == 0
|
||||
for: 10m
|
||||
labels:
|
||||
severity: critical
|
||||
alert_type: reachability
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} ORPort unreachable"
|
||||
description: "ORPort {{ $labels.port }} has been unreachable for 10 minutes"
|
||||
|
||||
# Warning: High error count
|
||||
- alert: TorRelayHighErrors
|
||||
expr: increase(tor_relay_errors_total[5m]) > 5
|
||||
for: 5m
|
||||
labels:
|
||||
severity: warning
|
||||
alert_type: health
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} has high error count"
|
||||
description: "{{ $value }} errors in last 5 minutes"
|
||||
|
||||
# Warning: High CPU usage
|
||||
- alert: TorRelayHighCPU
|
||||
expr: rate(process_cpu_seconds_total[5m]) > 0.8
|
||||
for: 15m
|
||||
labels:
|
||||
severity: warning
|
||||
alert_type: performance
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} high CPU"
|
||||
description: "CPU usage: {{ $value | humanizePercentage }}"
|
||||
|
||||
# Warning: High memory usage
|
||||
- alert: TorRelayHighMemory
|
||||
expr: process_resident_memory_bytes / 1024 / 1024 > 512
|
||||
for: 10m
|
||||
labels:
|
||||
severity: warning
|
||||
alert_type: performance
|
||||
annotations:
|
||||
summary: "Relay {{ $labels.relay_name }} high memory"
|
||||
description: "Memory: {{ $value | humanize }}MB"
|
||||
checks:
|
||||
http_check:
|
||||
instances:
|
||||
- name: tor-relay-health
|
||||
url: http://localhost:9100/health
|
||||
timeout: 5
|
||||
```
|
||||
|
||||
### Alertmanager Configuration
|
||||
|
||||
**File:** `alertmanager.yml`
|
||||
|
||||
**New Relic:**
|
||||
```yaml
|
||||
global:
|
||||
resolve_timeout: 5m
|
||||
slack_api_url: 'YOUR_SLACK_WEBHOOK_URL'
|
||||
integrations:
|
||||
- name: nri-docker
|
||||
env:
|
||||
DOCKER_API_VERSION: v1.40
|
||||
interval: 60s
|
||||
|
||||
route:
|
||||
receiver: 'default'
|
||||
group_by: ['alertname', 'relay_name']
|
||||
group_wait: 30s
|
||||
group_interval: 5m
|
||||
repeat_interval: 12h
|
||||
|
||||
routes:
|
||||
# Critical alerts - immediate notification
|
||||
- match:
|
||||
severity: critical
|
||||
receiver: 'critical-alerts'
|
||||
group_wait: 10s
|
||||
repeat_interval: 4h
|
||||
|
||||
# Warnings - less frequent
|
||||
- match:
|
||||
severity: warning
|
||||
receiver: 'warnings'
|
||||
group_wait: 2m
|
||||
repeat_interval: 24h
|
||||
|
||||
receivers:
|
||||
- name: 'default'
|
||||
slack_configs:
|
||||
- channel: '#tor-relay-general'
|
||||
title: '🧅 Tor Guard Relay Alert'
|
||||
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
|
||||
|
||||
- name: 'critical-alerts'
|
||||
slack_configs:
|
||||
- channel: '#tor-relay-critical'
|
||||
title: '🚨 CRITICAL: Tor Relay Alert'
|
||||
text: '{{ range .Alerts }}{{ .Annotations.summary }}{{ end }}'
|
||||
color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'
|
||||
|
||||
# Optional: Discord webhook
|
||||
webhook_configs:
|
||||
- url: 'YOUR_DISCORD_WEBHOOK_URL'
|
||||
|
||||
- name: 'warnings'
|
||||
slack_configs:
|
||||
- channel: '#tor-relay-warnings'
|
||||
title: '⚠️ Warning: Tor Relay'
|
||||
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
|
||||
- name: nri-flex
|
||||
config:
|
||||
name: tor-relay-health
|
||||
apis:
|
||||
- event_type: TorRelayHealth
|
||||
commands:
|
||||
- run: docker exec tor-relay health
|
||||
split: none
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Troubleshooting
|
||||
## 📊 Monitoring Metrics
|
||||
|
||||
### Prometheus Not Scraping Metrics
|
||||
|
||||
```bash
|
||||
# Check if metrics endpoint is accessible
|
||||
curl http://localhost:9035/metrics
|
||||
|
||||
# Check Prometheus targets
|
||||
open http://localhost:9090/targets
|
||||
|
||||
# Check container networking
|
||||
docker network inspect bridge
|
||||
|
||||
# Verify ENABLE_METRICS is set
|
||||
docker exec tor-relay env | grep ENABLE_METRICS
|
||||
```
|
||||
|
||||
### No Data in Grafana
|
||||
|
||||
```bash
|
||||
# Verify Prometheus datasource
|
||||
# Grafana → Configuration → Data Sources → Prometheus
|
||||
# Test the connection
|
||||
|
||||
# Check if Prometheus has data
|
||||
curl 'http://localhost:9090/api/v1/query?query=tor_relay_uptime_seconds'
|
||||
|
||||
# Check time range in Grafana dashboard
|
||||
# Ensure time range covers when relay was running
|
||||
```
|
||||
|
||||
### Alerts Not Firing
|
||||
|
||||
```bash
|
||||
# Check alert rules are loaded
|
||||
open http://localhost:9090/rules
|
||||
|
||||
# Verify Alertmanager connection
|
||||
open http://localhost:9090/alerts
|
||||
|
||||
# Check Alertmanager is receiving alerts
|
||||
open http://localhost:9093
|
||||
|
||||
# Test webhook endpoints
|
||||
curl -X POST YOUR_SLACK_WEBHOOK_URL -d '{"text":"Test"}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Best Practices
|
||||
|
||||
### 1. Retention Configuration
|
||||
|
||||
```yaml
|
||||
# In prometheus.yml
|
||||
global:
|
||||
# Keep metrics for 30 days
|
||||
storage.tsdb.retention.time: 30d
|
||||
|
||||
# Or limit by size
|
||||
storage.tsdb.retention.size: 10GB
|
||||
```
|
||||
|
||||
### 2. Scrape Intervals
|
||||
|
||||
- **Production:** 15-30 seconds
|
||||
- **Development:** 5-10 seconds
|
||||
- **High-load relays:** 30-60 seconds
|
||||
|
||||
### 3. Alert Tuning
|
||||
|
||||
- Set appropriate `for` durations to avoid alert fatigue
|
||||
- Use `group_wait` to batch related alerts
|
||||
- Configure escalation via `repeat_interval`
|
||||
|
||||
### 4. Dashboard Organization
|
||||
|
||||
- Use template variables for relay selection
|
||||
- Create separate dashboards for overview vs. detailed metrics
|
||||
- Use row collapse for optional sections
|
||||
|
||||
### 5. Resource Management
|
||||
|
||||
```yaml
|
||||
# Limit Prometheus memory
|
||||
command:
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
|
||||
# Set resource limits in Docker Compose
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '1'
|
||||
memory: 2G
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Security
|
||||
|
||||
### Metrics Endpoint Protection
|
||||
|
||||
```nginx
|
||||
# Nginx reverse proxy example
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name metrics.example.com;
|
||||
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
|
||||
location /metrics {
|
||||
auth_basic "Restricted";
|
||||
auth_basic_user_file /etc/nginx/.htpasswd;
|
||||
proxy_pass http://localhost:9035;
|
||||
}
|
||||
**Available from `health` tool:**
|
||||
```json
|
||||
{
|
||||
"status": "up|down|error",
|
||||
"pid": 123,
|
||||
"uptime": "2d 14h 30m",
|
||||
"bootstrap": 0-100,
|
||||
"reachable": "true|false",
|
||||
"errors": 0,
|
||||
"nickname": "MyRelay",
|
||||
"fingerprint": "ABCD..."
|
||||
}
|
||||
```
|
||||
|
||||
### Grafana Authentication
|
||||
**Key Metrics to Track:**
|
||||
- `status` - Relay health (up/down/error)
|
||||
- `bootstrap` - Connection progress (0-100%)
|
||||
- `reachable` - ORPort accessibility
|
||||
- `errors` - Error count
|
||||
- `uptime` - Relay uptime
|
||||
|
||||
**From Logs:**
|
||||
- Bootstrap events
|
||||
- ORPort reachability tests
|
||||
- Bandwidth usage
|
||||
- Connection counts (if exit relay)
|
||||
- Warning and error messages
|
||||
|
||||
---
|
||||
|
||||
## 🔔 Alerting
|
||||
|
||||
### Simple Shell Script Alert
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# check-tor-relay.sh
|
||||
# Requires: jq installed on host (apt install jq / brew install jq)
|
||||
|
||||
STATUS=$(docker exec tor-relay health | jq -r '.status')
|
||||
BOOTSTRAP=$(docker exec tor-relay health | jq -r '.bootstrap')
|
||||
ERRORS=$(docker exec tor-relay health | jq -r '.errors')
|
||||
|
||||
if [ "$STATUS" != "up" ]; then
|
||||
echo "CRITICAL: Tor relay is $STATUS"
|
||||
# Send alert via email, Slack, Discord, etc.
|
||||
curl -X POST https://hooks.slack.com/services/YOUR/WEBHOOK \
|
||||
-d "{\"text\": \"Tor relay is $STATUS\"}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ "$BOOTSTRAP" -lt 100 ]; then
|
||||
echo "WARNING: Bootstrap at $BOOTSTRAP%"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo "WARNING: $ERRORS errors detected"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "OK: Relay healthy, $BOOTSTRAP% bootstrapped"
|
||||
exit 0
|
||||
```
|
||||
|
||||
**Run with cron:**
|
||||
```cron
|
||||
*/5 * * * * /usr/local/bin/check-tor-relay.sh
|
||||
```
|
||||
|
||||
### Docker Events Alert
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# watch-docker-health.sh
|
||||
# Requires: jq installed on host (apt install jq / brew install jq)
|
||||
|
||||
docker events --filter 'event=health_status' --format '{{json .}}' | while read event; do
|
||||
STATUS=$(echo $event | jq -r '.Actor.Attributes."health_status"')
|
||||
CONTAINER=$(echo $event | jq -r '.Actor.Attributes.name')
|
||||
|
||||
if [ "$STATUS" = "unhealthy" ]; then
|
||||
echo "ALERT: $CONTAINER is unhealthy"
|
||||
# Send notification
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ Example: Complete Monitoring Stack
|
||||
|
||||
**Docker Compose with external monitoring:**
|
||||
|
||||
```yaml
|
||||
# In grafana datasource config
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=secure_password_here
|
||||
- GF_USERS_ALLOW_SIGN_UP=false
|
||||
- GF_AUTH_ANONYMOUS_ENABLED=false
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
tor-relay:
|
||||
image: r3bo0tbx1/onion-relay:latest
|
||||
container_name: tor-relay
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./relay.conf:/etc/tor/torrc:ro
|
||||
- tor-data:/var/lib/tor
|
||||
- tor-logs:/var/log/tor
|
||||
healthcheck:
|
||||
test: ["CMD", "tor", "--verify-config", "-f", "/etc/tor/torrc"]
|
||||
interval: 10m
|
||||
timeout: 15s
|
||||
retries: 3
|
||||
|
||||
# Health exporter (Python wrapper)
|
||||
health-exporter:
|
||||
image: python:3.11-slim
|
||||
container_name: tor-health-exporter
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ./health-exporter.py:/app/exporter.py
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
command: python /app/exporter.py
|
||||
depends_on:
|
||||
- tor-relay
|
||||
|
||||
# Prometheus
|
||||
prometheus:
|
||||
image: prom/prometheus:latest
|
||||
container_name: prometheus
|
||||
ports:
|
||||
- "9090:9090"
|
||||
volumes:
|
||||
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||
- prometheus-data:/prometheus
|
||||
command:
|
||||
- '--config.file=/etc/prometheus/prometheus.yml'
|
||||
- '--storage.tsdb.retention.time=30d'
|
||||
|
||||
# Grafana
|
||||
grafana:
|
||||
image: grafana/grafana:latest
|
||||
container_name: grafana
|
||||
ports:
|
||||
- "3000:3000"
|
||||
environment:
|
||||
- GF_SECURITY_ADMIN_PASSWORD=admin
|
||||
volumes:
|
||||
- grafana-data:/var/lib/grafana
|
||||
|
||||
volumes:
|
||||
tor-data:
|
||||
tor-logs:
|
||||
prometheus-data:
|
||||
grafana-data:
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips & Best Practices
|
||||
|
||||
1. **Use `health` tool** - JSON output perfect for automation
|
||||
2. **Monitor Docker health** - Built-in, no extra tools needed
|
||||
3. **Alert on status changes** - Watch for `status != "up"`
|
||||
4. **Track bootstrap** - New relays take 5-15 minutes
|
||||
5. **Monitor logs** - Tor logs are comprehensive and informative
|
||||
6. **External exporters** - Use tor_exporter for detailed metrics
|
||||
7. **Keep it simple** - Don't over-complicate monitoring
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Tools Reference](./TOOLS.md) - Detailed tool documentation
|
||||
- [Deployment Guide](./DEPLOYMENT.md) - Installation instructions
|
||||
- [Tools Reference](./TOOLS.md) - Built-in diagnostic tools
|
||||
- [Deployment Guide](./DEPLOYMENT.md) - Installation and configuration
|
||||
- [Performance Guide](./PERFORMANCE.md) - Optimization tips
|
||||
- [Backup Guide](./BACKUP.md) - Data persistence
|
||||
|
||||
---
|
||||
|
||||
## 🆘 Support
|
||||
## ❓ FAQ
|
||||
|
||||
- 📖 [Prometheus Documentation](https://prometheus.io/docs/)
|
||||
- 📖 [Grafana Documentation](https://grafana.com/docs/)
|
||||
- 🐛 [Report Issues](https://github.com/r3bo0tbx1/tor-guard-relay/issues)
|
||||
- 💬 [Community Forum](https://forum.torproject.org/)
|
||||
**Q: Why was the built-in metrics endpoint removed?**
|
||||
A: To achieve the ultra-small image size (~20 MB). The metrics server required Python, Flask, and other dependencies (~25+ MB). External monitoring is more flexible anyway.
|
||||
|
||||
**Q: Can I still use Prometheus?**
|
||||
A: Yes! Use the Python wrapper example above, or a dedicated Tor exporter like `prometheus-tor_exporter`.
|
||||
|
||||
**Q: What's the simplest monitoring option?**
|
||||
A: Docker health checks + the `health` tool. No additional infrastructure needed.
|
||||
|
||||
**Q: How do I monitor multiple relays?**
|
||||
A: Run the health exporter on each host, or use log aggregation (Loki, ELK, Datadog).
|
||||
|
||||
**Q: Where can I find the logs?**
|
||||
A:
|
||||
- Inside container: `/var/log/tor/notices.log`
|
||||
- On host: `/var/lib/docker/volumes/tor-guard-logs/_data/notices.log`
|
||||
- Via docker: `docker logs tor-relay`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 2025 | **Version:** 1.1
|
||||
**Last Updated:** November 2025 | **Version:** 1.1.1
|
||||
535
docs/MULTI-MODE.md
Normal file
535
docs/MULTI-MODE.md
Normal file
@@ -0,0 +1,535 @@
|
||||
# 🔄 Multi-Mode Relay Guide - Tor Guard Relay
|
||||
|
||||
Complete guide to running Guard/Middle relays, Exit relays, and obfs4 Bridges.
|
||||
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Mode Comparison](#mode-comparison)
|
||||
- [Guard/Middle Relay Mode](#guardmiddle-relay-mode)
|
||||
- [Exit Relay Mode](#exit-relay-mode)
|
||||
- [obfs4 Bridge Mode](#obfs4-bridge-mode)
|
||||
- [Configuration Methods](#configuration-methods)
|
||||
- [Environment Variables Reference](#environment-variables-reference)
|
||||
- [Switching Modes](#switching-modes)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Tor Guard Relay container now supports **three relay modes**:
|
||||
|
||||
| Mode | Purpose | Public Visibility | Legal Risk | Bandwidth Needs |
|
||||
|------|---------|------------------|------------|-----------------|
|
||||
| **Guard/Middle** | Entry/routing relay | High | Low | Medium-High |
|
||||
| **Exit** | Exit traffic to internet | High | **HIGH** | High |
|
||||
| **Bridge** | Help censored users | Hidden | Low | Low-Medium |
|
||||
|
||||
### Key Features
|
||||
|
||||
- ✅ **Dynamic Configuration** - Generate config from environment variables
|
||||
- ✅ **obfs4 Support** - Pluggable transport for bridges
|
||||
- ✅ **Backwards Compatible** - Still supports mounting config files
|
||||
- ✅ **Secure Defaults** - Guard/middle as default mode
|
||||
|
||||
---
|
||||
|
||||
## Mode Comparison
|
||||
|
||||
### Guard/Middle Relay (Default)
|
||||
|
||||
**What it does:**
|
||||
- Acts as entry point (guard) or routing node (middle) in Tor circuits
|
||||
- Does NOT handle exit traffic to the internet
|
||||
- Published in the main Tor directory
|
||||
|
||||
**Best for:**
|
||||
- Operators who want to contribute without legal complexity
|
||||
- Stable, high-bandwidth connections
|
||||
- Long-term operation (8+ days to earn Guard flag)
|
||||
|
||||
**Requirements:**
|
||||
- Public IP with ports 9001, 9030 accessible
|
||||
- Stable uptime (99%+ recommended)
|
||||
- 10+ Mbps bandwidth recommended
|
||||
|
||||
### Exit Relay
|
||||
|
||||
**What it does:**
|
||||
- Allows Tor traffic to exit to the internet
|
||||
- Your IP is associated with all exit traffic
|
||||
- Published in the main Tor directory
|
||||
|
||||
**Best for:**
|
||||
- Experienced operators who understand legal implications
|
||||
- Datacenters with abuse handling
|
||||
- Dedicated servers/IPs
|
||||
|
||||
**⚠️ CRITICAL REQUIREMENTS:**
|
||||
- **Understand legal risks** - read [EFF Tor Legal FAQ](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/)
|
||||
- Prepare for abuse complaints
|
||||
- Inform your ISP
|
||||
- Set up abuse@ email address
|
||||
- Have legal resources available
|
||||
- Use dedicated IP/server
|
||||
|
||||
### obfs4 Bridge
|
||||
|
||||
**What it does:**
|
||||
- Helps users in censored countries connect to Tor
|
||||
- NOT published in main directory (distributed via BridgeDB)
|
||||
- Uses obfs4 to make traffic look random
|
||||
|
||||
**Best for:**
|
||||
- Operators in non-censored countries
|
||||
- Lower bandwidth contributions
|
||||
- Helping circumvent censorship
|
||||
|
||||
**Requirements:**
|
||||
- Stable IP with ports 9001, 9002 accessible
|
||||
- Less bandwidth than relays (10+ Mbps sufficient)
|
||||
- Not blocked by censors in target countries
|
||||
|
||||
---
|
||||
|
||||
## Guard/Middle Relay Mode
|
||||
|
||||
### Quick Start with Environment Variables
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name tor-guard-relay \
|
||||
--network host \
|
||||
--restart unless-stopped \
|
||||
-e TOR_RELAY_MODE=guard \
|
||||
-e TOR_NICKNAME=MyGuardRelay \
|
||||
-e TOR_CONTACT_INFO="your-email@example.com" \
|
||||
-e TOR_BANDWIDTH_RATE="50 MBytes" \
|
||||
-e TOR_BANDWIDTH_BURST="100 MBytes" \
|
||||
-v tor-guard-data:/var/lib/tor \
|
||||
-v tor-guard-logs:/var/log/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
tor-guard-relay:
|
||||
image: ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
container_name: tor-guard-relay
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
environment:
|
||||
TOR_RELAY_MODE: guard
|
||||
TOR_NICKNAME: MyGuardRelay
|
||||
TOR_CONTACT_INFO: "your-email@example.com"
|
||||
TOR_BANDWIDTH_RATE: "50 MBytes"
|
||||
TOR_BANDWIDTH_BURST: "100 MBytes"
|
||||
volumes:
|
||||
- tor-guard-data:/var/lib/tor
|
||||
- tor-guard-logs:/var/log/tor
|
||||
|
||||
volumes:
|
||||
tor-guard-data:
|
||||
tor-guard-logs:
|
||||
```
|
||||
|
||||
Save as `docker-compose.yml` and run:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
# Check status
|
||||
docker exec tor-guard-relay status
|
||||
|
||||
# View logs
|
||||
docker logs -f tor-guard-relay
|
||||
|
||||
# Get fingerprint
|
||||
docker exec tor-guard-relay fingerprint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Exit Relay Mode
|
||||
|
||||
### ⚠️ Before You Start
|
||||
|
||||
**READ THIS FIRST:**
|
||||
1. [EFF Tor Legal FAQ](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/)
|
||||
2. [Tor Abuse Response Templates](https://community.torproject.org/relay/community-resources/tor-abuse-templates/)
|
||||
3. [Good/Bad ISPs for Exit Relays](https://community.torproject.org/relay/community-resources/good-bad-isps/)
|
||||
|
||||
**Exit Relay Checklist:**
|
||||
- [ ] Read and understand legal implications
|
||||
- [ ] Prepared to handle abuse complaints
|
||||
- [ ] Informed ISP (recommended)
|
||||
- [ ] Set up abuse@ email address
|
||||
- [ ] Using dedicated IP/server
|
||||
- [ ] Have abuse response template ready
|
||||
- [ ] Have legal resources available if needed
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name tor-exit-relay \
|
||||
--network host \
|
||||
--restart unless-stopped \
|
||||
-e TOR_RELAY_MODE=exit \
|
||||
-e TOR_NICKNAME=MyExitRelay \
|
||||
-e TOR_CONTACT_INFO="your-email@example.com <0xPGP_KEY>" \
|
||||
-e TOR_BANDWIDTH_RATE="50 MBytes" \
|
||||
-e TOR_BANDWIDTH_BURST="100 MBytes" \
|
||||
-v tor-exit-data:/var/lib/tor \
|
||||
-v tor-exit-logs:/var/log/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Exit Policy
|
||||
|
||||
By default, uses the **Reduced Exit Policy** (Tor Project recommended):
|
||||
- Allows common services (HTTP, HTTPS, SSH, email, etc.)
|
||||
- Blocks high-risk ports
|
||||
- Good starting point for exit operators
|
||||
|
||||
**Custom Exit Policy:**
|
||||
```bash
|
||||
-e TOR_EXIT_POLICY="accept *:80,accept *:443,reject *:*"
|
||||
```
|
||||
|
||||
**More restrictive (HTTPS only):**
|
||||
```bash
|
||||
-e TOR_EXIT_POLICY="accept *:443,reject *:*"
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
See [templates/docker-compose-exit.yml](../templates/docker-compose-exit.yml) for complete example.
|
||||
|
||||
### Handling Abuse Complaints
|
||||
|
||||
**Standard Response Template:**
|
||||
```
|
||||
This is a Tor exit relay (https://www.torproject.org/).
|
||||
The IP address you reported is not the source of the activity.
|
||||
Tor is an anonymity network that helps people protect their
|
||||
privacy and security online.
|
||||
|
||||
For more information about Tor and exit relays:
|
||||
- What is Tor: https://www.torproject.org/about/overview.html
|
||||
- Tor and abuse: https://blog.torproject.org/blog/tips-running-exit-node
|
||||
|
||||
If you have concerns about specific traffic, please contact
|
||||
the destination website directly. The exit relay operator
|
||||
does not control the traffic passing through the relay.
|
||||
|
||||
Contact: your-email@example.com
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## obfs4 Bridge Mode
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name tor-bridge \
|
||||
--network host \
|
||||
--restart unless-stopped \
|
||||
-e TOR_RELAY_MODE=bridge \
|
||||
-e TOR_NICKNAME=MyTorBridge \
|
||||
-e TOR_CONTACT_INFO="your-email@example.com" \
|
||||
-e TOR_ORPORT=9001 \
|
||||
-e TOR_OBFS4_PORT=9002 \
|
||||
-e TOR_BANDWIDTH_RATE="10 MBytes" \
|
||||
-e TOR_BANDWIDTH_BURST="20 MBytes" \
|
||||
-v tor-bridge-data:/var/lib/tor \
|
||||
-v tor-bridge-logs:/var/log/tor \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
```
|
||||
|
||||
### Docker Compose
|
||||
|
||||
See [templates/docker-compose-bridge.yml](../templates/docker-compose-bridge.yml) for complete example.
|
||||
|
||||
### Getting Your Bridge Line
|
||||
|
||||
**After 24-48 hours**, your bridge will be registered and you can get the bridge line:
|
||||
|
||||
```bash
|
||||
# Method 1: Check pt_state directory
|
||||
docker exec tor-bridge cat /var/lib/tor/pt_state/obfs4_bridgeline.txt
|
||||
|
||||
# Method 2: Search logs
|
||||
docker exec tor-bridge grep "bridge line" /var/log/tor/notices.log
|
||||
|
||||
# Method 3: Check pt_state directory contents
|
||||
docker exec tor-bridge ls -la /var/lib/tor/pt_state/
|
||||
```
|
||||
|
||||
Output will look like:
|
||||
```
|
||||
Bridge obfs4 <IP>:<PORT> <FINGERPRINT> cert=<CERT> iat-mode=0
|
||||
```
|
||||
|
||||
### Sharing Your Bridge
|
||||
|
||||
**IMPORTANT:**
|
||||
- Only share with people you trust
|
||||
- Do NOT publish publicly (defeats the purpose)
|
||||
- Users can also request bridges from [BridgeDB](https://bridges.torproject.org/)
|
||||
|
||||
### Verification
|
||||
|
||||
```bash
|
||||
# Check if obfs4proxy is running
|
||||
docker exec tor-bridge pgrep -a obfs4proxy
|
||||
|
||||
# Check bridge status
|
||||
docker exec tor-bridge status
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
The container supports **two configuration methods**:
|
||||
|
||||
### Method 1: Environment Variables (Recommended for Simple Setups)
|
||||
|
||||
**Pros:**
|
||||
✓ No config file to maintain
|
||||
✓ Easy to change settings
|
||||
✓ Good for simple setups
|
||||
✓ Works well with orchestration tools
|
||||
|
||||
**Cons:**
|
||||
✗ Less flexible for advanced options
|
||||
✗ Cannot set all possible Tor directives
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
docker run -d \
|
||||
-e TOR_RELAY_MODE=guard \
|
||||
-e TOR_NICKNAME=MyRelay \
|
||||
-e TOR_CONTACT_INFO="email@example.com" \
|
||||
...
|
||||
```
|
||||
|
||||
### Method 2: Config File Mount (Advanced)
|
||||
|
||||
**Pros:**
|
||||
✓ Full control over Tor configuration
|
||||
✓ Can use any Tor directive
|
||||
✓ Better for complex setups
|
||||
|
||||
**Cons:**
|
||||
✗ Need to maintain config file
|
||||
✗ Less portable
|
||||
|
||||
**Example:**
|
||||
```bash
|
||||
docker run -d \
|
||||
-v $(pwd)/relay.conf:/etc/tor/torrc:ro \
|
||||
...
|
||||
```
|
||||
|
||||
### Can I Use Both?
|
||||
|
||||
Yes! If you mount a config file, it takes precedence over environment variables.
|
||||
The container will detect the mounted file and skip dynamic config generation.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables Reference
|
||||
|
||||
### Core Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TOR_RELAY_MODE` | `guard` | Relay mode: `guard`, `exit`, or `bridge` |
|
||||
| `TOR_NICKNAME` | _(required)_ | Relay nickname (1-19 alphanumeric chars) |
|
||||
| `TOR_CONTACT_INFO` | _(required)_ | Contact email (+ optional PGP key) |
|
||||
|
||||
### Network Ports
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TOR_ORPORT` | `9001` | Tor connection port |
|
||||
| `TOR_DIRPORT` | `9030` | Directory service port (not used for bridges) |
|
||||
| `TOR_OBFS4_PORT` | `9002` | obfs4 pluggable transport port (bridges only) |
|
||||
|
||||
### Bandwidth
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TOR_BANDWIDTH_RATE` | _(none)_ | Sustained bandwidth (e.g., `50 MBytes`) |
|
||||
| `TOR_BANDWIDTH_BURST` | _(none)_ | Burst bandwidth (e.g., `100 MBytes`) |
|
||||
|
||||
### Exit Policy (Exit Mode Only)
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TOR_EXIT_POLICY` | Reduced Exit Policy | Custom exit policy (comma-separated) |
|
||||
|
||||
Example: `TOR_EXIT_POLICY="accept *:80,accept *:443,reject *:*"`
|
||||
|
||||
### Advanced
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `TOR_DATA_DIR` | `/var/lib/tor` | Tor data directory |
|
||||
| `TOR_LOG_DIR` | `/var/log/tor` | Tor log directory |
|
||||
| `TOR_CONFIG` | `/etc/tor/torrc` | Tor configuration file path |
|
||||
| `DEBUG` | `false` | Enable debug output |
|
||||
|
||||
---
|
||||
|
||||
## Switching Modes
|
||||
|
||||
You can switch between modes by changing `TOR_RELAY_MODE` and restarting:
|
||||
|
||||
### From Guard to Exit
|
||||
|
||||
```bash
|
||||
docker stop tor-relay
|
||||
docker rm tor-relay
|
||||
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
-e TOR_RELAY_MODE=exit \
|
||||
-e TOR_NICKNAME=MyExitRelay \
|
||||
... # Same volumes
|
||||
```
|
||||
|
||||
**⚠️ WARNING:** Switching to exit mode has legal implications. Read the Exit Relay section first.
|
||||
|
||||
### From Guard to Bridge
|
||||
|
||||
```bash
|
||||
docker stop tor-relay
|
||||
docker rm tor-relay
|
||||
|
||||
docker run -d \
|
||||
--name tor-relay \
|
||||
-e TOR_RELAY_MODE=bridge \
|
||||
-e TOR_NICKNAME=MyBridge \
|
||||
-e TOR_OBFS4_PORT=9002 \
|
||||
... # Same volumes
|
||||
```
|
||||
|
||||
**Note:** Your relay will get a new identity when switching modes.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Configuration Not Generating
|
||||
|
||||
**Symptom:** Container starts but uses placeholder config
|
||||
|
||||
**Solution:**
|
||||
1. Make sure no config file is mounted at `/etc/tor/torrc`
|
||||
2. Set required environment variables:
|
||||
- `TOR_NICKNAME`
|
||||
- `TOR_CONTACT_INFO`
|
||||
3. Check logs: `docker logs <container>`
|
||||
|
||||
### Bridge Line Not Appearing
|
||||
|
||||
**Symptom:** Bridge line file doesn't exist after 24+ hours
|
||||
|
||||
**Solution:**
|
||||
1. Check both ports are accessible: `9001` and `9002`
|
||||
2. Verify obfs4proxy is running: `docker exec <container> pgrep obfs4proxy`
|
||||
3. Check logs for obfs4proxy errors: `docker logs <container> | grep obfs4`
|
||||
4. Wait 48 hours - bridge distribution takes time
|
||||
|
||||
### Exit Relay - Too Many Abuse Complaints
|
||||
|
||||
**Symptom:** Receiving excessive abuse complaints
|
||||
|
||||
**Solutions:**
|
||||
1. Switch to more restrictive exit policy (HTTPS only)
|
||||
2. Consider running as guard relay instead
|
||||
3. Check if your ISP supports exit relays: [Good/Bad ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/)
|
||||
4. Use abuse complaint template to respond efficiently
|
||||
|
||||
### Ports Not Accessible
|
||||
|
||||
**Symptom:** `ORPort not reachable` in status
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Check firewall
|
||||
sudo ufw status
|
||||
|
||||
# Open required ports
|
||||
sudo ufw allow 9001/tcp
|
||||
sudo ufw allow 9030/tcp # Guards/exits only
|
||||
sudo ufw allow 9002/tcp # Bridges only
|
||||
|
||||
# Test from outside
|
||||
nc -zv <your-ip> 9001
|
||||
```
|
||||
|
||||
### Low/No Traffic
|
||||
|
||||
**Symptom:** Relay shows very little bandwidth usage
|
||||
|
||||
**Normal for:**
|
||||
- New relays (2-8 weeks to build reputation)
|
||||
- Bridges (intentionally low visibility)
|
||||
- Guards without Guard flag (need 8+ days uptime)
|
||||
|
||||
**Check:**
|
||||
1. Verify relay is reachable: `docker exec <container> status`
|
||||
2. Check Tor Metrics: https://metrics.torproject.org/rs.html
|
||||
3. Ensure adequate bandwidth: `TOR_BANDWIDTH_RATE`
|
||||
|
||||
---
|
||||
|
||||
## Resources
|
||||
|
||||
### Official Tor Project
|
||||
|
||||
- [Relay Setup Guide](https://community.torproject.org/relay/setup/)
|
||||
- [Bridge Setup Guide](https://community.torproject.org/relay/setup/bridge/)
|
||||
- [Relay Requirements](https://community.torproject.org/relay/relays-requirements/)
|
||||
- [Tor Metrics](https://metrics.torproject.org/)
|
||||
- [BridgeDB](https://bridges.torproject.org/)
|
||||
|
||||
### Legal & Compliance
|
||||
|
||||
- [EFF Tor Legal FAQ](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/)
|
||||
- [Abuse Response Templates](https://community.torproject.org/relay/community-resources/tor-abuse-templates/)
|
||||
- [Good/Bad ISPs](https://community.torproject.org/relay/community-resources/good-bad-isps/)
|
||||
|
||||
### Technical Documentation
|
||||
|
||||
- [obfs4 Specification](https://gitlab.com/yawning/obfs4)
|
||||
- [Tor Manual](https://2019.www.torproject.org/docs/tor-manual.html.en)
|
||||
|
||||
### This Project
|
||||
|
||||
- [Main README](../README.md)
|
||||
- [Deployment Guide](DEPLOYMENT.md)
|
||||
- [Tools Documentation](TOOLS.md)
|
||||
- [Monitoring Guide](MONITORING.md)
|
||||
|
||||
---
|
||||
|
||||
**Made with 💜 for a freer, uncensored internet**
|
||||
|
||||
*Protecting privacy, one relay at a time* 🧅✨
|
||||
@@ -346,38 +346,65 @@ time docker exec guard-relay tor --resolve example.com
|
||||
|
||||
## Monitoring & Metrics
|
||||
|
||||
### 1. Enable Prometheus Metrics
|
||||
v1.1.1 uses **external monitoring** with the `health` JSON API for minimal image size and maximum security.
|
||||
|
||||
**In docker-compose.yml:**
|
||||
### 1. JSON Health API
|
||||
|
||||
```yaml
|
||||
services:
|
||||
tor-guard-relay:
|
||||
environment:
|
||||
- "ENABLE_METRICS=true"
|
||||
- "METRICS_PORT=9035"
|
||||
```
|
||||
|
||||
**Or in relay.conf:**
|
||||
|
||||
```conf
|
||||
# Prometheus metrics port
|
||||
# MetricsPort 9035
|
||||
```
|
||||
|
||||
### 2. Access Metrics Endpoint
|
||||
Get relay metrics via the `health` tool:
|
||||
|
||||
```bash
|
||||
# Pull metrics
|
||||
curl http://localhost:9035/metrics
|
||||
# Get full health status (raw JSON)
|
||||
docker exec guard-relay health
|
||||
|
||||
# Example output:
|
||||
# tor_relay_bandwidth_read_bytes 1234567890
|
||||
# tor_relay_bandwidth_write_bytes 1987654321
|
||||
# tor_relay_connections 234
|
||||
# Parse with jq (requires jq on host)
|
||||
docker exec guard-relay health | jq .
|
||||
|
||||
# Check specific metrics
|
||||
docker exec guard-relay health | jq .bootstrap # Bootstrap percentage
|
||||
docker exec guard-relay health | jq .reachable # ORPort reachability
|
||||
docker exec guard-relay health | jq .uptime_seconds # Uptime
|
||||
```
|
||||
|
||||
### 3. Set Up Prometheus Monitoring
|
||||
**Example JSON output:**
|
||||
```json
|
||||
{
|
||||
"status": "up",
|
||||
"bootstrap": 100,
|
||||
"reachable": true,
|
||||
"fingerprint": "1234567890ABCDEF...",
|
||||
"nickname": "MyRelay",
|
||||
"uptime_seconds": 86400
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Prometheus Integration (External)
|
||||
|
||||
Use the `health` tool with Prometheus node_exporter textfile collector:
|
||||
|
||||
**Create metrics exporter script:**
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /usr/local/bin/tor-metrics-exporter.sh
|
||||
# Requires: jq on host (apt install jq / brew install jq)
|
||||
|
||||
HEALTH=$(docker exec guard-relay health)
|
||||
|
||||
echo "$HEALTH" | jq -r '
|
||||
"tor_bootstrap_percent \(.bootstrap)",
|
||||
"tor_reachable \(if .reachable then 1 else 0 end)",
|
||||
"tor_uptime_seconds \(.uptime_seconds // 0)"
|
||||
' > /var/lib/node_exporter/textfile_collector/tor.prom
|
||||
```
|
||||
|
||||
**Run via cron every 5 minutes:**
|
||||
```bash
|
||||
chmod +x /usr/local/bin/tor-metrics-exporter.sh
|
||||
crontab -e
|
||||
*/5 * * * * /usr/local/bin/tor-metrics-exporter.sh
|
||||
```
|
||||
|
||||
### 3. Set Up Prometheus Scraping
|
||||
|
||||
**prometheus.yml:**
|
||||
|
||||
@@ -386,7 +413,7 @@ global:
|
||||
scrape_interval: 15s
|
||||
|
||||
scrape_configs:
|
||||
- job_name: 'tor-relay'
|
||||
- job_name: 'node_exporter' # Scrapes textfile collector
|
||||
static_configs:
|
||||
- targets: ['localhost:9035']
|
||||
metrics_path: '/metrics'
|
||||
@@ -548,7 +575,9 @@ docker exec guard-relay grep "RelayBandwidth" /etc/tor/torrc
|
||||
docker logs guard-relay 2>&1 | grep "Average"
|
||||
|
||||
# Verify ORPort is reachable
|
||||
docker exec guard-relay relay-status | grep "reachable"
|
||||
docker exec guard-relay status | grep "reachable"
|
||||
# Or use JSON health check
|
||||
docker exec guard-relay health | jq .reachable
|
||||
```
|
||||
|
||||
**Solutions:**
|
||||
|
||||
549
docs/TOOLS.md
549
docs/TOOLS.md
@@ -1,22 +1,17 @@
|
||||
# 🛠️ Tools Reference Guide
|
||||
|
||||
**Tor Guard Relay v1.1** includes a comprehensive suite of diagnostic and management tools built directly into the container. All tools are Alpine-compatible, executable without file extensions, and designed for production use.
|
||||
**Tor Guard Relay v1.1.1** includes 4 essential diagnostic tools built directly into the ultra-optimized ~20 MB container. All tools are busybox-compatible, executable without file extensions, and designed for production use.
|
||||
|
||||
---
|
||||
|
||||
## 📋 Tool Overview
|
||||
|
||||
| Tool | Purpose | Output Format | ENV Variables |
|
||||
|------|---------|---------------|---------------|
|
||||
| **status** | Complete relay health report | Text (emoji) | None |
|
||||
| **fingerprint** | Display relay fingerprint | Text | None |
|
||||
| **health** | JSON health diagnostics | JSON | None |
|
||||
| **metrics** | Prometheus metrics | Prometheus | `RELAY_NICKNAME` |
|
||||
| **metrics-http** | HTTP metrics server | HTTP | `METRICS_PORT` |
|
||||
| **dashboard** | Live HTML dashboard | HTML | None |
|
||||
| **setup** | Interactive config wizard | Interactive | All Tor vars |
|
||||
| **net-check** | Network diagnostics | Text (emoji) | None |
|
||||
| **view-logs** | Live log streaming | Text | `TOR_LOG_DIR` |
|
||||
| Tool | Purpose | Output Format | Notes |
|
||||
|------|---------|---------------|-------|
|
||||
| **status** | Complete relay health report | Text (emoji) | Full diagnostic dashboard |
|
||||
| **health** | JSON health diagnostics | JSON | Machine-readable for monitoring |
|
||||
| **fingerprint** | Display relay fingerprint | Text | With Tor Metrics link |
|
||||
| **bridge-line** | Get obfs4 bridge line | Text | Bridge mode only |
|
||||
|
||||
---
|
||||
|
||||
@@ -24,7 +19,7 @@
|
||||
|
||||
### `status`
|
||||
|
||||
**Purpose:** Comprehensive relay health and status report
|
||||
**Purpose:** Comprehensive relay health and status report with emoji formatting
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
@@ -33,35 +28,79 @@ docker exec tor-relay status
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
🧅 Tor Relay Status Report
|
||||
═══════════════════════════════════
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🧅 Tor Relay Status
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📦 Build Information
|
||||
Version: v1.1
|
||||
Build Date: 2025-11-04
|
||||
Architecture: amd64
|
||||
🚀 Status: RUNNING (PID: 123)
|
||||
✅ Bootstrap: 100% COMPLETE
|
||||
🌐 ORPort: REACHABLE
|
||||
🪪 Nickname: MyGuardRelay
|
||||
🔑 Fingerprint: ABCD1234...WXYZ9876
|
||||
✅ Errors: 0
|
||||
⏱️ Uptime: 2d 14h 30m
|
||||
|
||||
🚀 Bootstrap Progress
|
||||
Status: ✅ Complete (100%)
|
||||
Circuits: 3 active
|
||||
|
||||
🔗 Network Status
|
||||
ORPort: ✅ Reachable (9001)
|
||||
Public IP: 203.0.113.42
|
||||
|
||||
📊 Performance
|
||||
Uptime: 2d 14h 30m
|
||||
Bandwidth: 50 MB/s
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
💡 Tip: Use 'docker logs -f <container>' for live logs
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
```
|
||||
|
||||
**Environment Variables:** None required
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Status retrieved successfully
|
||||
- `1` - Tor service not running or error
|
||||
|
||||
---
|
||||
|
||||
### `health`
|
||||
|
||||
**Purpose:** Machine-readable JSON health check for monitoring systems and automation
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
docker exec tor-relay health
|
||||
|
||||
# Parse with jq
|
||||
docker exec tor-relay health | jq .status
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"status": "up",
|
||||
"pid": 123,
|
||||
"uptime": "2d 14h 30m",
|
||||
"bootstrap": 100,
|
||||
"reachable": "true",
|
||||
"errors": 0,
|
||||
"nickname": "MyGuardRelay",
|
||||
"fingerprint": "ABCD1234567890ABCDEF1234567890ABCDEFGHIJ"
|
||||
}
|
||||
```
|
||||
|
||||
**Status Values:**
|
||||
- `up` - Relay is running and healthy
|
||||
- `down` - Relay is not running
|
||||
- `error` - Critical issues detected
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Health check completed
|
||||
- `1` - Critical error or Tor not running
|
||||
|
||||
**Integration Example:**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Simple health monitoring script
|
||||
HEALTH=$(docker exec tor-relay health)
|
||||
STATUS=$(echo "$HEALTH" | jq -r '.status')
|
||||
|
||||
if [ "$STATUS" != "up" ]; then
|
||||
echo "ALERT: Relay is $STATUS"
|
||||
# Send notification
|
||||
fi
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `fingerprint`
|
||||
|
||||
**Purpose:** Display relay fingerprint with direct links to Tor Metrics
|
||||
@@ -73,274 +112,71 @@ docker exec tor-relay fingerprint
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
🔑 Tor Relay Fingerprint
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🔑 Relay Fingerprint
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Nickname: MyTorRelay
|
||||
Fingerprint: 1234 5678 90AB CDEF 1234 5678 90AB CDEF 1234 5678
|
||||
🪪 Nickname: MyTorRelay
|
||||
🔑 Fingerprint: ABCD 1234 5678 90AB CDEF 1234 5678 90AB CDEF 1234
|
||||
|
||||
🔗 Tor Metrics: https://metrics.torproject.org/rs.html#details/123456...
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🔗 Tor Metrics: https://metrics.torproject.org/rs.html#details/ABCD...
|
||||
|
||||
💡 Your relay will appear in Tor Metrics after 1-2 hours
|
||||
```
|
||||
|
||||
**Environment Variables:** None required
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Fingerprint retrieved
|
||||
- `1` - Fingerprint not yet available (bootstrapping)
|
||||
- `1` - Fingerprint not yet available (still bootstrapping)
|
||||
|
||||
**When Available:**
|
||||
- Guard/Middle relays: ~1-2 hours after first start
|
||||
- Exit relays: ~1-2 hours after first start
|
||||
- Bridges: Not published publicly (by design)
|
||||
|
||||
---
|
||||
|
||||
### `health`
|
||||
### `bridge-line`
|
||||
|
||||
**Purpose:** Machine-readable JSON health check for monitoring systems
|
||||
**Purpose:** Get the obfs4 bridge line for sharing with users (bridge mode only)
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
docker exec tor-relay health
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"uptime": 214830,
|
||||
"bootstrap": {
|
||||
"percent": 100,
|
||||
"status": "Done"
|
||||
},
|
||||
"timestamp": "2025-11-04T12:30:45Z",
|
||||
"relay_info": {
|
||||
"nickname": "MyTorRelay",
|
||||
"fingerprint": "1234567890ABCDEF...",
|
||||
"or_port": 9001,
|
||||
"dir_port": 9030
|
||||
},
|
||||
"network": {
|
||||
"or_port_reachable": true,
|
||||
"dir_port_reachable": true,
|
||||
"public_ip": "203.0.113.42"
|
||||
},
|
||||
"issues": {
|
||||
"errors": 0,
|
||||
"warnings": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Environment Variables:** None required
|
||||
|
||||
**Status Values:**
|
||||
- `healthy` - All systems operational
|
||||
- `warning` - Minor issues detected
|
||||
- `error` - Critical issues present
|
||||
- `bootstrapping` - Still connecting to Tor network
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Health check completed
|
||||
- `1` - Critical error or Tor not running
|
||||
|
||||
---
|
||||
|
||||
### `metrics`
|
||||
|
||||
**Purpose:** Generate Prometheus-format metrics for monitoring
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
docker exec tor-relay metrics
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```prometheus
|
||||
# HELP tor_relay_uptime_seconds Relay uptime in seconds
|
||||
# TYPE tor_relay_uptime_seconds gauge
|
||||
tor_relay_uptime_seconds{relay_name="MyTorRelay"} 214830
|
||||
|
||||
# HELP tor_relay_bootstrap_percent Bootstrap completion percentage
|
||||
# TYPE tor_relay_bootstrap_percent gauge
|
||||
tor_relay_bootstrap_percent{relay_name="MyTorRelay"} 100
|
||||
|
||||
# HELP tor_relay_or_port_reachable ORPort reachability status
|
||||
# TYPE tor_relay_or_port_reachable gauge
|
||||
tor_relay_or_port_reachable{relay_name="MyTorRelay",port="9001"} 1
|
||||
|
||||
# HELP tor_relay_bandwidth_rate_bytes Configured bandwidth rate
|
||||
# TYPE tor_relay_bandwidth_rate_bytes gauge
|
||||
tor_relay_bandwidth_rate_bytes{relay_name="MyTorRelay"} 52428800
|
||||
```
|
||||
|
||||
**Environment Variables:**
|
||||
- `RELAY_NICKNAME` - Sets the relay name label in metrics (optional)
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Metrics generated
|
||||
- `1` - Error generating metrics
|
||||
|
||||
---
|
||||
|
||||
### `metrics-http`
|
||||
|
||||
**Purpose:** HTTP server for exposing Prometheus metrics
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
# Start metrics HTTP server (runs in background)
|
||||
metrics-http 9035
|
||||
|
||||
# Access metrics endpoint
|
||||
curl http://localhost:9035/metrics
|
||||
```
|
||||
|
||||
**Environment Variables:**
|
||||
- `METRICS_PORT` - Port to listen on (default: 9035)
|
||||
|
||||
**Endpoints:**
|
||||
- `GET /metrics` - Prometheus metrics
|
||||
- `GET /health` - Health check endpoint
|
||||
- `GET /` - Simple status page
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Server running
|
||||
- `1` - Port already in use or error
|
||||
|
||||
**Note:** Automatically started by docker-entrypoint.sh if `ENABLE_METRICS=true`
|
||||
|
||||
---
|
||||
|
||||
### `dashboard`
|
||||
|
||||
**Purpose:** Interactive HTML dashboard with real-time relay status
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
# Generate dashboard HTML
|
||||
docker exec tor-relay dashboard > dashboard.html
|
||||
|
||||
# Or access via HTTP if metrics-http is running
|
||||
curl http://localhost:9035/dashboard
|
||||
```
|
||||
|
||||
**Features:**
|
||||
- Real-time bootstrap progress
|
||||
- Network reachability status
|
||||
- Performance metrics visualization
|
||||
- Quick action buttons
|
||||
- Auto-refresh every 30 seconds
|
||||
|
||||
**Environment Variables:** None required
|
||||
|
||||
**Browser Access:**
|
||||
When `metrics-http` is running, access dashboard at:
|
||||
`http://<server-ip>:9035/dashboard`
|
||||
|
||||
---
|
||||
|
||||
### `setup`
|
||||
|
||||
**Purpose:** Interactive wizard for generating relay configuration
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
docker exec -it tor-relay setup
|
||||
```
|
||||
|
||||
**Interactive Prompts:**
|
||||
1. Relay Nickname
|
||||
2. Contact Information (email)
|
||||
3. ORPort (default: 9001)
|
||||
4. DirPort (default: 9030)
|
||||
5. Bandwidth Rate (MB/s)
|
||||
6. Bandwidth Burst (MB/s)
|
||||
7. IPv6 support (yes/no)
|
||||
8. Exit policy (guard/middle only)
|
||||
|
||||
**Output:** Generates `/etc/tor/torrc` or outputs to stdout
|
||||
|
||||
**Environment Variables:**
|
||||
- `TOR_CONFIG` - Config file path (default: /etc/tor/torrc)
|
||||
- All standard Tor environment variables
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Configuration created successfully
|
||||
- `1` - Invalid input or error
|
||||
|
||||
---
|
||||
|
||||
### `net-check`
|
||||
|
||||
**Purpose:** Comprehensive network diagnostics for relay troubleshooting
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
docker exec tor-relay net-check
|
||||
docker exec tor-bridge bridge-line
|
||||
```
|
||||
|
||||
**Output Example:**
|
||||
```
|
||||
🌐 Network Diagnostics Report
|
||||
════════════════════════════════════
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🌉 obfs4 Bridge Line
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
✅ IPv4 Connectivity: OK (203.0.113.42)
|
||||
✅ IPv6 Connectivity: OK (2001:db8::1)
|
||||
✅ DNS Resolution: OK
|
||||
✅ Tor Consensus: Reachable
|
||||
✅ ORPort 9001: OPEN
|
||||
✅ DirPort 9030: OPEN
|
||||
Bridge obfs4 203.0.113.42:9002 ABCD...WXYZ cert=abc123...xyz789 iat-mode=0
|
||||
|
||||
🔍 Diagnostic Details:
|
||||
• Public IPv4: 203.0.113.42
|
||||
• Public IPv6: 2001:db8::1
|
||||
• DNS Resolver: 1.1.1.1
|
||||
• Tor Authority: 128.31.0.34:9131 (reachable)
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
📋 Sharing Guidelines:
|
||||
• Only share with people you trust
|
||||
• Do NOT publish publicly
|
||||
• Helps users in censored countries
|
||||
|
||||
💡 Bridge line available 24-48 hours after first start
|
||||
```
|
||||
|
||||
**Checks Performed:**
|
||||
- IPv4 connectivity and public IP detection
|
||||
- IPv6 connectivity and public IP detection (if enabled)
|
||||
- DNS resolution (multiple resolvers)
|
||||
- Tor directory authority connectivity
|
||||
- ORPort reachability (internal and external)
|
||||
- DirPort reachability (internal and external)
|
||||
|
||||
**Environment Variables:** None required
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - All checks passed
|
||||
- `1` - One or more checks failed
|
||||
- `0` - Bridge line retrieved
|
||||
- `1` - Bridge line not yet available or not in bridge mode
|
||||
|
||||
---
|
||||
**When Available:**
|
||||
- Bridges take 24-48 hours after first start to generate the bridge line
|
||||
- The bridge line is stored in `/var/lib/tor/pt_state/obfs4_bridgeline.txt`
|
||||
- Also visible in logs: `docker logs <container> | grep "bridge line"`
|
||||
|
||||
### `view-logs`
|
||||
|
||||
**Purpose:** Stream Tor relay logs with optional filtering
|
||||
|
||||
**Usage:**
|
||||
```bash
|
||||
# View last 50 lines
|
||||
docker exec tor-relay view-logs
|
||||
|
||||
# Follow logs in real-time
|
||||
docker exec tor-relay view-logs -f
|
||||
|
||||
# Filter for errors only
|
||||
docker exec tor-relay view-logs --errors
|
||||
|
||||
# Filter for warnings and errors
|
||||
docker exec tor-relay view-logs --warn
|
||||
```
|
||||
|
||||
**Options:**
|
||||
- `-f, --follow` - Follow log output (like tail -f)
|
||||
- `-n <lines>` - Show last N lines (default: 50)
|
||||
- `--errors` - Show only ERROR level messages
|
||||
- `--warn` - Show WARNING and ERROR messages
|
||||
- `--bootstrap` - Show only bootstrap-related messages
|
||||
|
||||
**Environment Variables:**
|
||||
- `TOR_LOG_DIR` - Log directory path (default: /var/log/tor)
|
||||
|
||||
**Exit Codes:**
|
||||
- `0` - Logs displayed successfully
|
||||
- `1` - Log file not found or error
|
||||
**Important:**
|
||||
- Only works in bridge mode (`TOR_RELAY_MODE=bridge`)
|
||||
- Requires persistent volumes for `/var/lib/tor`
|
||||
- Bridge addresses are NOT published in public directories
|
||||
|
||||
---
|
||||
|
||||
@@ -348,52 +184,65 @@ docker exec tor-relay view-logs --warn
|
||||
|
||||
### 1. Quick Health Check
|
||||
```bash
|
||||
# Simple status check
|
||||
# Visual status check
|
||||
docker exec tor-relay status
|
||||
|
||||
# JSON health check for automation
|
||||
docker exec tor-relay health | jq .status
|
||||
|
||||
# Check bootstrap progress
|
||||
docker exec tor-relay health | jq .bootstrap
|
||||
```
|
||||
|
||||
### 2. Setup Prometheus Monitoring
|
||||
### 2. Find Your Relay on Tor Metrics
|
||||
```bash
|
||||
# Start metrics HTTP server
|
||||
docker exec tor-relay metrics-http 9035 &
|
||||
|
||||
# Configure Prometheus to scrape:
|
||||
# http://<relay-ip>:9035/metrics
|
||||
```
|
||||
|
||||
### 3. Troubleshoot Network Issues
|
||||
```bash
|
||||
# Run comprehensive network diagnostics
|
||||
docker exec tor-relay net-check
|
||||
|
||||
# Check relay fingerprint and Metrics link
|
||||
# Get fingerprint and metrics link
|
||||
docker exec tor-relay fingerprint
|
||||
|
||||
# View recent errors
|
||||
docker exec tor-relay view-logs --errors | tail -20
|
||||
# Wait 1-2 hours after first start
|
||||
# Click the Tor Metrics link or search manually
|
||||
```
|
||||
|
||||
### 4. Monitor Bootstrap Progress
|
||||
### 3. Share Your Bridge
|
||||
```bash
|
||||
# Watch bootstrap in real-time
|
||||
watch -n 5 'docker exec tor-relay health | jq .bootstrap'
|
||||
# Get bridge line (bridge mode only)
|
||||
docker exec tor-bridge bridge-line
|
||||
|
||||
# Or use status tool
|
||||
docker exec tor-relay status | grep Bootstrap
|
||||
# Wait 24-48 hours after first start
|
||||
# Share ONLY with trusted users, NOT publicly
|
||||
```
|
||||
|
||||
### 5. Generate Configuration
|
||||
### 4. Automated Monitoring
|
||||
```bash
|
||||
# Interactive setup
|
||||
docker exec -it tor-relay setup
|
||||
# Simple monitoring script
|
||||
while true; do
|
||||
STATUS=$(docker exec tor-relay health | jq -r '.status')
|
||||
BOOTSTRAP=$(docker exec tor-relay health | jq -r '.bootstrap')
|
||||
|
||||
# Or use environment variables
|
||||
docker run -e RELAY_NICKNAME=MyRelay \
|
||||
-e RELAY_CONTACT=admin@example.com \
|
||||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||||
echo "[$(date)] Status: $STATUS | Bootstrap: $BOOTSTRAP%"
|
||||
|
||||
if [ "$STATUS" != "up" ]; then
|
||||
# Send alert
|
||||
echo "ALERT: Relay is down!"
|
||||
fi
|
||||
|
||||
sleep 60
|
||||
done
|
||||
```
|
||||
|
||||
### 5. Check Logs
|
||||
```bash
|
||||
# View recent logs
|
||||
docker logs --tail 100 tor-relay
|
||||
|
||||
# Follow logs in real-time
|
||||
docker logs -f tor-relay
|
||||
|
||||
# Filter for errors
|
||||
docker logs tor-relay 2>&1 | grep -i error
|
||||
|
||||
# Filter for warnings
|
||||
docker logs tor-relay 2>&1 | grep -i warn
|
||||
```
|
||||
|
||||
---
|
||||
@@ -401,10 +250,10 @@ docker run -e RELAY_NICKNAME=MyRelay \
|
||||
## 🔐 Security Notes
|
||||
|
||||
- All tools run as non-root `tor` user
|
||||
- No tools write to disk (except setup when instructed)
|
||||
- Metrics expose no sensitive data
|
||||
- Dashboard can be password-protected via reverse proxy
|
||||
- Logs contain no sensitive user data (Tor privacy design)
|
||||
- Tools are read-only and don't modify relay state
|
||||
- No sensitive data exposed (fingerprints are public by design)
|
||||
- Bridge lines should be shared privately, not published
|
||||
- Logs contain no user traffic data (Tor privacy design)
|
||||
|
||||
---
|
||||
|
||||
@@ -412,62 +261,100 @@ docker run -e RELAY_NICKNAME=MyRelay \
|
||||
|
||||
### Tool not found
|
||||
```bash
|
||||
# Verify tool exists and is executable
|
||||
# Verify tools exist
|
||||
docker exec tor-relay ls -la /usr/local/bin/
|
||||
|
||||
# Should show: status, health, fingerprint, bridge-line
|
||||
|
||||
# Check PATH
|
||||
docker exec tor-relay echo $PATH
|
||||
```
|
||||
|
||||
### Permission denied
|
||||
```bash
|
||||
# Should not happen - tools auto-fixed by entrypoint
|
||||
# If it does, check Dockerfile COPY command
|
||||
|
||||
# Manual fix (shouldn't be needed):
|
||||
docker exec -u root tor-relay chmod +x /usr/local/bin/*
|
||||
# Should not happen - tools are set to +x in Dockerfile
|
||||
# If it does, rebuild image:
|
||||
docker build --no-cache -t tor-relay:latest .
|
||||
```
|
||||
|
||||
### Empty or error output
|
||||
### Empty output or errors
|
||||
```bash
|
||||
# Check if Tor is running
|
||||
docker exec tor-relay pgrep tor
|
||||
docker exec tor-relay ps aux | grep tor
|
||||
|
||||
# Check logs for errors
|
||||
docker exec tor-relay view-logs --errors
|
||||
docker logs tor-relay | tail -50
|
||||
|
||||
# Restart container
|
||||
docker restart tor-relay
|
||||
```
|
||||
|
||||
### Metrics HTTP server fails to start
|
||||
### Fingerprint not available
|
||||
```bash
|
||||
# Check if port is in use
|
||||
docker exec tor-relay netstat -tulpn | grep 9035
|
||||
# Normal during bootstrap (first 5-15 minutes)
|
||||
# Check bootstrap progress
|
||||
docker exec tor-relay health | jq .bootstrap
|
||||
|
||||
# Try different port
|
||||
docker exec tor-relay metrics-http 9036
|
||||
# Wait for 100% bootstrap
|
||||
docker logs tor-relay | grep "Bootstrapped 100%"
|
||||
```
|
||||
|
||||
### Bridge line not available
|
||||
```bash
|
||||
# Normal for first 24-48 hours
|
||||
# Check if in bridge mode
|
||||
docker exec tor-relay grep BridgeRelay /etc/tor/torrc
|
||||
|
||||
# Check for obfs4 files
|
||||
docker exec tor-relay ls -la /var/lib/tor/pt_state/
|
||||
|
||||
# Check logs
|
||||
docker logs tor-relay | grep -i obfs4
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips & Best Practices
|
||||
|
||||
1. **Use `health` for automation** - JSON output is perfect for scripts and monitoring systems
|
||||
|
||||
2. **Check `status` during troubleshooting** - Human-readable format with emoji makes issues obvious
|
||||
|
||||
3. **Save your fingerprint** - Store it somewhere safe for relay tracking
|
||||
|
||||
4. **Monitor bootstrap** - New relays take 5-15 minutes to fully bootstrap
|
||||
|
||||
5. **Be patient with bridges** - Bridge lines take 24-48 hours to generate
|
||||
|
||||
6. **Use docker logs** - Built-in logging is comprehensive and easier than installing extra tools
|
||||
|
||||
7. **Keep it simple** - This minimal toolset covers 99% of relay operation needs
|
||||
|
||||
---
|
||||
|
||||
## 📚 Related Documentation
|
||||
|
||||
- [Deployment Guide](./DEPLOYMENT.md) - Installation and configuration
|
||||
- [Monitoring Guide](./MONITORING.md) - Prometheus and Grafana setup
|
||||
- [Multi-Mode Guide](./MULTI-MODE.md) - Guard, Exit, and Bridge modes
|
||||
- [Backup Guide](./BACKUP.md) - Data persistence and recovery
|
||||
- [Performance Guide](./PERFORMANCE.md) - Optimization tips
|
||||
|
||||
---
|
||||
|
||||
## 💡 Tips
|
||||
## ❓ FAQ
|
||||
|
||||
1. **Automation**: Use `health` tool's JSON output for monitoring scripts
|
||||
2. **Monitoring**: Always enable `metrics-http` for production relays
|
||||
3. **Diagnostics**: Run `net-check` after any network configuration changes
|
||||
4. **Logs**: Use `view-logs --follow` during initial bootstrap
|
||||
5. **Dashboard**: Useful for at-a-glance status without CLI
|
||||
**Q: Why only 4 tools instead of 9?**
|
||||
A: The v1.1.1 build prioritizes size optimization (~20 MB vs 45+ MB). These 4 tools cover all essential operations. For advanced monitoring, use external tools like Prometheus.
|
||||
|
||||
**Q: Where are metrics/monitoring endpoints?**
|
||||
A: Removed to achieve ultra-small image size. Use `health` tool with external monitoring systems or check `/var/log/tor/notices.log` directly.
|
||||
|
||||
**Q: Can I still use Prometheus?**
|
||||
A: Yes! Export logs or use `health` JSON output with a Prometheus exporter. See [MONITORING.md](./MONITORING.md) for alternatives.
|
||||
|
||||
**Q: What happened to the dashboard?**
|
||||
A: Removed (required Python/Flask). Use `status` tool for visual output or build your own dashboard using `health` JSON.
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** November 2025 | **Version:** 1.1
|
||||
**Last Updated:** November 2025 | **Version:** 1.1.1
|
||||
508
docs/TROUBLESHOOTING-BRIDGE-MIGRATION.md
Normal file
508
docs/TROUBLESHOOTING-BRIDGE-MIGRATION.md
Normal file
@@ -0,0 +1,508 @@
|
||||
# Troubleshooting Bridge Migration to v1.1.1
|
||||
|
||||
This guide addresses the specific issue where migrating from `thetorproject/obfs4-bridge` to `r3bo0tbx1/onion-relay:1.1.1` results in configuration validation failures and changing fingerprints.
|
||||
|
||||
## Problem Description
|
||||
|
||||
### Symptoms
|
||||
|
||||
1. **Container crash loop** with these logs:
|
||||
```
|
||||
✅ Using mounted configuration: /etc/tor/torrc
|
||||
🛑 Configuration validation failed!
|
||||
🛑 ERROR: Invalid Tor configuration. Set DEBUG=true for details.
|
||||
```
|
||||
|
||||
2. **Fingerprints changing on every restart** - CRITICAL issue indicating bridge identity loss:
|
||||
```
|
||||
2025-11-12 17:45:45: CD2A0C40DA625C943A2174171D18AFF2849328DC
|
||||
2025-11-12 17:50:18: 5895203866064C4270F909BE4327B43AA5E5D44A
|
||||
2025-11-12 17:58:31: D059C6613DB06B256AD488859659A9A605E8643B
|
||||
```
|
||||
|
||||
### Root Cause
|
||||
|
||||
The `thetorproject/obfs4-bridge` image creates a `torrc` file that may persist in the Docker volume or get recreated. When you migrate to `r3bo0tbx1/onion-relay:1.1.1`, the entrypoint script checks for existing configuration files with this priority:
|
||||
|
||||
1. **Priority 1**: Existing `/etc/tor/torrc` file (mounted or in volume)
|
||||
2. **Priority 2**: Environment variables (OR_PORT, PT_PORT, EMAIL, NICKNAME)
|
||||
|
||||
If an old `torrc` exists, v1.1.1 tries to use it but it may be:
|
||||
- Incompatible format
|
||||
- Using different paths
|
||||
- Missing required directives for v1.1.1 validation
|
||||
|
||||
The **changing fingerprints** indicate an even more serious issue: the `/var/lib/tor/keys/` directory is being lost, meaning your bridge identity is being regenerated each time.
|
||||
|
||||
## Emergency Fix Procedure
|
||||
|
||||
### Step 1: Run Diagnostic Script
|
||||
|
||||
We've provided a comprehensive diagnostic script that will:
|
||||
- Check if your volume exists
|
||||
- Verify Tor identity keys are preserved
|
||||
- Find and remove incompatible torrc files
|
||||
- Create a backup of your current volume
|
||||
- Extract your current fingerprint
|
||||
|
||||
**Run this first:**
|
||||
|
||||
```bash
|
||||
# Make sure you're in the tor-guard-relay directory
|
||||
cd /path/to/tor-guard-relay
|
||||
|
||||
# Run the diagnostic script
|
||||
./bridge-migration-fix.sh
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🔧 Bridge Migration Emergency Fix
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
ℹ️ Step 1: Checking container status...
|
||||
✅ Container found
|
||||
|
||||
ℹ️ Step 2: Inspecting volume obfs4-data...
|
||||
✅ Volume exists
|
||||
ℹ️ Volume mountpoint: /var/lib/docker/volumes/obfs4-data/_data
|
||||
|
||||
ℹ️ Step 3: Checking volume contents...
|
||||
|
||||
📁 Volume contents:
|
||||
drwxr-xr-x 5 tor tor 4096 Nov 12 17:45 .
|
||||
drwxr-xr-x 3 root root 4096 Nov 12 17:40 ..
|
||||
drwx------ 2 tor tor 4096 Nov 12 17:45 keys
|
||||
drwx------ 2 tor tor 4096 Nov 12 17:45 pt_state
|
||||
-rw-r--r-- 1 tor tor 12345 Nov 12 17:45 cached-descriptors
|
||||
|
||||
🔑 Checking for Tor identity keys...
|
||||
✅ keys/ directory exists
|
||||
-rw------- 1 tor tor 1024 Nov 12 17:45 secret_id_key
|
||||
-rw------- 1 tor tor 96 Nov 12 17:45 ed25519_master_id_secret_key
|
||||
✅ secret_id_key found (RSA identity)
|
||||
✅ ed25519_master_id_secret_key found (Ed25519 identity)
|
||||
|
||||
🔐 Checking for obfs4 bridge state...
|
||||
✅ pt_state/ directory exists
|
||||
-rw------- 1 tor tor 512 Nov 12 17:45 obfs4_state.json
|
||||
✅ obfs4_state.json found (bridge credentials)
|
||||
|
||||
ℹ️ Step 4: Checking for incompatible torrc files...
|
||||
✅ No torrc files found in volume (this is GOOD)
|
||||
|
||||
ℹ️ Step 5: Creating backup of volume...
|
||||
✅ Backup created: bridge-backup-20251112-180000.tar.gz
|
||||
ℹ️ Keep this backup safe - it contains your bridge identity keys!
|
||||
|
||||
ℹ️ Step 6: No torrc cleanup needed
|
||||
|
||||
ℹ️ Step 7: Extracting current bridge fingerprint...
|
||||
✅ Current fingerprint: B1702095E8D048CF68190284BB11E183A0CDD533
|
||||
ℹ️ Save this! You'll verify it matches after migration.
|
||||
ℹ️ Tor Metrics: https://metrics.torproject.org/rs.html#search/B1702095E8D048CF68190284BB11E183A0CDD533
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ Diagnosis and cleanup complete!
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
✅ Your bridge identity keys are preserved
|
||||
✅ No torrc cleanup was needed
|
||||
✅ Backup created: bridge-backup-20251112-180000.tar.gz
|
||||
```
|
||||
|
||||
### Step 2: Deploy Fixed Configuration
|
||||
|
||||
After the diagnostic script completes, use the corrected Cosmos JSON:
|
||||
|
||||
**File:** `templates/cosmos-compose-bridge-migrated-v1.1.1.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"minVersion": "0.8.0",
|
||||
"services": {
|
||||
"obfs4-bridge": {
|
||||
"image": "localhost:5000/r3bo0tbx1/onion-relay:latest",
|
||||
"container_name": "obfs4-bridge",
|
||||
"restart": "unless-stopped",
|
||||
"network_mode": "host",
|
||||
"environment": [
|
||||
"OR_PORT=9001",
|
||||
"PT_PORT=9005",
|
||||
"EMAIL=admin@email.org",
|
||||
"NICKNAME=MyObfs4Bridge",
|
||||
"OBFS4_ENABLE_ADDITIONAL_VARIABLES=1",
|
||||
"OBFS4V_AddressDisableIPv6=0",
|
||||
"OBFS4V_MaxMemInQueues=1024 MB"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"type": "volume",
|
||||
"source": "obfs4-data",
|
||||
"target": "/var/lib/tor"
|
||||
}
|
||||
],
|
||||
"security_opt": ["no-new-privileges:true"],
|
||||
"cap_add": ["NET_BIND_SERVICE", "CHOWN", "SETUID", "SETGID", "DAC_OVERRIDE"],
|
||||
"labels": {
|
||||
"cosmos-stack": "TorBridge",
|
||||
"cosmos-stack-main": "obfs4-bridge",
|
||||
"cosmos-icon": "https://iili.io/KsXP2Y7.png",
|
||||
"cosmos-auto-update": "true",
|
||||
"cosmos-force-network-secured": "false",
|
||||
"cosmos-version": "1.1.1"
|
||||
}
|
||||
}
|
||||
},
|
||||
"volumes": {
|
||||
"obfs4-data": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Key points:**
|
||||
- ✅ Uses ENV variables (OR_PORT, PT_PORT, etc.) - official Tor Project naming
|
||||
- ✅ Volume mount: `obfs4-data` → `/var/lib/tor` (preserves keys)
|
||||
- ✅ No `/etc/tor/torrc` bind mount (lets v1.1.1 generate config from ENV)
|
||||
- ✅ Bridge mode auto-detected from `PT_PORT`
|
||||
- ✅ `OBFS4_ENABLE_ADDITIONAL_VARIABLES=1` enables OBFS4V_* processing
|
||||
|
||||
### Step 3: Verify Migration Success
|
||||
|
||||
After deploying, verify everything works:
|
||||
|
||||
```bash
|
||||
# 1. Check container is running
|
||||
docker ps | grep obfs4-bridge
|
||||
|
||||
# 2. Check logs for successful startup
|
||||
docker logs -f obfs4-bridge
|
||||
```
|
||||
|
||||
**Expected successful startup logs:**
|
||||
```
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
🧅 Tor Guard Relay v1.1.1 - Initialization
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
🗂️ Phase 1: Directory Structure
|
||||
Created directories:
|
||||
• Data: /var/lib/tor
|
||||
• Logs: /var/log/tor
|
||||
• Run: /run/tor
|
||||
|
||||
🔐 Phase 2: Permission Hardening
|
||||
✅ Permissions configured securely
|
||||
|
||||
🔧 Phase 3: Configuration Setup
|
||||
Generating configuration from environment variables...
|
||||
✅ Configuration generated from ENV vars
|
||||
|
||||
🔎 Phase 4: Configuration Validation
|
||||
📦 Tor version: Tor version 0.4.8.20.
|
||||
Validating torrc syntax...
|
||||
✅ Configuration is valid
|
||||
|
||||
📊 Phase 5: Build Information
|
||||
🌐 Relay mode: bridge
|
||||
🔧 Config source: environment
|
||||
|
||||
🧩 Phase 6: Available Diagnostic Tools
|
||||
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
✅ Starting Tor relay...
|
||||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
Nov 12 18:30:00.000 [notice] Tor 0.4.8.20 running on Linux...
|
||||
Nov 12 18:30:00.000 [notice] Read configuration file "/etc/tor/torrc".
|
||||
Nov 12 18:30:01.000 [notice] Bootstrapped 5% (conn): Connecting to a relay
|
||||
Nov 12 18:30:02.000 [notice] Bootstrapped 10% (conn_done): Connected to a relay
|
||||
...
|
||||
Nov 12 18:30:10.000 [notice] Bootstrapped 100% (done): Done
|
||||
```
|
||||
|
||||
**Critical checks:**
|
||||
|
||||
1. **Config source must be "environment"**, not "mounted":
|
||||
```
|
||||
✅ Configuration generated from ENV vars ← GOOD
|
||||
🔧 Config source: environment ← GOOD
|
||||
```
|
||||
|
||||
2. **Relay mode must be "bridge"** (auto-detected from PT_PORT):
|
||||
```
|
||||
🌐 Relay mode: bridge ← GOOD
|
||||
```
|
||||
|
||||
3. **Verify fingerprint matches** (from diagnostic script):
|
||||
```bash
|
||||
docker exec obfs4-bridge fingerprint
|
||||
```
|
||||
|
||||
Should output the SAME fingerprint from Step 1. If it's different, your keys weren't preserved!
|
||||
|
||||
4. **Check health**:
|
||||
```bash
|
||||
docker exec obfs4-bridge health | jq .
|
||||
```
|
||||
|
||||
Expected output:
|
||||
```json
|
||||
{
|
||||
"status": "ok",
|
||||
"relay_mode": "bridge",
|
||||
"bootstrap": "100%",
|
||||
"fingerprint": "B1702095E8D048CF68190284BB11E183A0CDD533",
|
||||
"nickname": "MyObfs4Bridge",
|
||||
"or_port": 9001,
|
||||
"obfs4_port": 9005
|
||||
}
|
||||
```
|
||||
|
||||
5. **Get bridge line** (after 10-30 minutes of operation):
|
||||
```bash
|
||||
docker exec obfs4-bridge bridge-line
|
||||
```
|
||||
|
||||
## If Still Failing: Advanced Debugging
|
||||
|
||||
### Enable DEBUG mode
|
||||
|
||||
If the container still crashes, add `DEBUG=true` to environment to see exact validation error:
|
||||
|
||||
```json
|
||||
"environment": [
|
||||
"DEBUG=true", // ← Add this first
|
||||
"OR_PORT=9001",
|
||||
"PT_PORT=9005",
|
||||
// ... rest of ENV vars
|
||||
]
|
||||
```
|
||||
|
||||
Redeploy and check logs:
|
||||
```bash
|
||||
docker logs obfs4-bridge 2>&1 | grep -A 10 "Configuration validation failed"
|
||||
```
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Issue 1: "Using mounted configuration" when you don't have a mount
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
✅ Using mounted configuration: /etc/tor/torrc
|
||||
🛑 Configuration validation failed!
|
||||
```
|
||||
|
||||
**Cause:** Old torrc file exists somewhere (in volume or image)
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Check if torrc exists in volume
|
||||
docker run --rm -v obfs4-data:/data alpine find /data -name "torrc"
|
||||
|
||||
# Remove any found torrc files
|
||||
docker run --rm -v obfs4-data:/data alpine rm -f /data/torrc /data/etc/tor/torrc
|
||||
```
|
||||
|
||||
#### Issue 2: Fingerprints still changing after migration
|
||||
|
||||
**Symptom:** `docker exec obfs4-bridge fingerprint` shows different value each time
|
||||
|
||||
**Cause:** Volume is being recreated or not properly mounted
|
||||
|
||||
**Fix:**
|
||||
```bash
|
||||
# Verify volume exists and has keys
|
||||
docker run --rm -v obfs4-data:/data alpine ls -la /data/keys
|
||||
|
||||
# Should see:
|
||||
# -rw------- secret_id_key
|
||||
# -rw------- ed25519_master_id_secret_key
|
||||
|
||||
# If missing, restore from backup:
|
||||
docker run --rm \
|
||||
-v obfs4-data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/bridge-backup-YYYYMMDD-HHMMSS.tar.gz -C /
|
||||
```
|
||||
|
||||
#### Issue 3: Permission errors after migration
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
[warn] Directory /var/lib/tor cannot be read: Permission denied
|
||||
```
|
||||
|
||||
**Fix:** v1.1.1 has automatic permission healing. If it still fails:
|
||||
```bash
|
||||
# Fix permissions manually
|
||||
docker run --rm -v obfs4-data:/data alpine chown -R 1000:1000 /data
|
||||
docker run --rm -v obfs4-data:/data alpine chmod 700 /data
|
||||
```
|
||||
|
||||
#### Issue 4: obfs4 transport not working
|
||||
|
||||
**Symptom:**
|
||||
```
|
||||
[warn] We were supposed to start obfs4 but couldn't
|
||||
```
|
||||
|
||||
**Fix:** Verify lyrebird is installed:
|
||||
```bash
|
||||
docker exec obfs4-bridge which lyrebird
|
||||
# Should output: /usr/bin/lyrebird
|
||||
|
||||
# Check if obfs4 port is configured
|
||||
docker exec obfs4-bridge grep -i "ServerTransportListenAddr" /etc/tor/torrc
|
||||
# Should output: ServerTransportListenAddr obfs4 0.0.0.0:9005
|
||||
```
|
||||
|
||||
## Rollback Procedure
|
||||
|
||||
If migration fails and you need to go back to the official bridge image:
|
||||
|
||||
### Step 1: Stop v1.1.1 container
|
||||
|
||||
```bash
|
||||
docker stop obfs4-bridge
|
||||
docker rm obfs4-bridge
|
||||
```
|
||||
|
||||
### Step 2: Restore backup (if needed)
|
||||
|
||||
```bash
|
||||
# Only if you lost keys or data
|
||||
docker volume rm obfs4-data
|
||||
docker volume create obfs4-data
|
||||
|
||||
docker run --rm \
|
||||
-v obfs4-data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/bridge-backup-YYYYMMDD-HHMMSS.tar.gz -C /
|
||||
```
|
||||
|
||||
### Step 3: Redeploy official bridge
|
||||
|
||||
Use your original `thetorproject/obfs4-bridge` configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"minVersion": "0.8.0",
|
||||
"services": {
|
||||
"obfs4-bridge": {
|
||||
"image": "thetorproject/obfs4-bridge:latest",
|
||||
"container_name": "obfs4-bridge",
|
||||
"restart": "unless-stopped",
|
||||
"network_mode": "host",
|
||||
"environment": [
|
||||
"OR_PORT=9001",
|
||||
"PT_PORT=9005",
|
||||
"EMAIL=admin@email.org",
|
||||
"NICKNAME=MyObfs4Bridge"
|
||||
],
|
||||
"volumes": [
|
||||
{
|
||||
"type": "volume",
|
||||
"source": "obfs4-data",
|
||||
"target": "/var/lib/tor"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"volumes": {
|
||||
"obfs4-data": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4: Verify rollback success
|
||||
|
||||
```bash
|
||||
docker logs -f obfs4-bridge
|
||||
|
||||
# Should start successfully and reuse existing keys
|
||||
# Fingerprint should match your original
|
||||
```
|
||||
|
||||
## Prevention for Future Migrations
|
||||
|
||||
1. **Always backup first:**
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v obfs4-data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar czf /backup/bridge-backup-$(date +%Y%m%d).tar.gz /data
|
||||
```
|
||||
|
||||
2. **Test with DEBUG=true** on first migration
|
||||
|
||||
3. **Verify fingerprint immediately** after migration
|
||||
|
||||
4. **Keep old container stopped** (not removed) until you verify new one works:
|
||||
```bash
|
||||
docker stop obfs4-bridge # ← Just stop, don't remove
|
||||
# ... deploy new v1.1.1 container with different name ...
|
||||
# ... verify it works ...
|
||||
# ... then remove old container
|
||||
```
|
||||
|
||||
5. **Monitor Tor Metrics** for 24-48 hours to ensure bridge stays published
|
||||
|
||||
## Support
|
||||
|
||||
If you've followed all steps and still have issues:
|
||||
|
||||
1. Run diagnostic script and save output:
|
||||
```bash
|
||||
./bridge-migration-fix.sh > migration-debug.log 2>&1
|
||||
```
|
||||
|
||||
2. Collect container logs with DEBUG:
|
||||
```bash
|
||||
# Add DEBUG=true to environment, redeploy, then:
|
||||
docker logs obfs4-bridge > container-debug.log 2>&1
|
||||
```
|
||||
|
||||
3. Open an issue with:
|
||||
- `migration-debug.log`
|
||||
- `container-debug.log`
|
||||
- Your Cosmos JSON (remove sensitive info like EMAIL)
|
||||
- Output of `docker volume inspect obfs4-data`
|
||||
|
||||
**GitHub Issues:** https://github.com/r3bo0tbx1/tor-guard-relay/issues
|
||||
|
||||
## Summary Checklist
|
||||
|
||||
Before migration:
|
||||
- [ ] Run `bridge-migration-fix.sh` diagnostic script
|
||||
- [ ] Save current fingerprint
|
||||
- [ ] Create backup of `obfs4-data` volume
|
||||
- [ ] Verify identity keys exist in volume
|
||||
|
||||
After migration:
|
||||
- [ ] Container starts without crash loop
|
||||
- [ ] Logs show "Config source: environment" (not "mounted")
|
||||
- [ ] Relay mode is "bridge" (auto-detected)
|
||||
- [ ] Fingerprint matches original (verify with `docker exec obfs4-bridge fingerprint`)
|
||||
- [ ] Health check passes (`docker exec obfs4-bridge health | jq .`)
|
||||
- [ ] Bootstrap reaches 100%
|
||||
- [ ] Bridge line available after 10-30 minutes (`docker exec obfs4-bridge bridge-line`)
|
||||
- [ ] Tor Metrics still shows your bridge (wait 1-2 hours)
|
||||
|
||||
**Migration should preserve:**
|
||||
- ✅ Bridge fingerprint (same identity keys)
|
||||
- ✅ obfs4 credentials (pt_state/obfs4_state.json)
|
||||
- ✅ Bridge reputation and history
|
||||
- ✅ All configuration (ORPort, PT port, nickname, contact info)
|
||||
|
||||
**Migration adds:**
|
||||
- ✨ Official Tor Project ENV variable compatibility
|
||||
- ✨ Bootstrap progress logs in terminal
|
||||
- ✨ Enhanced emoji logging (v1.1.0 style)
|
||||
- ✨ 4 diagnostic tools (status, health, fingerprint, bridge-line)
|
||||
- ✨ Auto-detection of bridge mode from PT_PORT
|
||||
- ✨ OBFS4V_* variable processing
|
||||
|
||||
Your bridge identity and reputation are preserved throughout the migration!
|
||||
Reference in New Issue
Block a user