mirror of
https://github.com/r3bo0tbx1/tor-guard-relay.git
synced 2026-04-05 16:22:01 +02:00
- Add Dockerfile.edge 🐚🔧 - Add stable and edge CI matrix 🔁📦 - GHCR edge-only deployment 🟣📤 - SBOMs for both variants 📜🔍 - Tests, screenshots, logo 🧪🖼️ - Update docs and PR template 📝 - Remove dependabot.yml 🗑️
626 lines
17 KiB
Bash
626 lines
17 KiB
Bash
#!/bin/sh
|
||
# quick-start.sh - Interactive Tor relay deployment script
|
||
# Helps beginners set up guard, exit, or bridge relays
|
||
|
||
set -e
|
||
|
||
# Color output helpers (if terminal supports it)
|
||
if [ -t 1 ]; then
|
||
BOLD='\033[1m'
|
||
GREEN='\033[0;32m'
|
||
BLUE='\033[0;34m'
|
||
YELLOW='\033[1;33m'
|
||
RED='\033[0;31m'
|
||
NC='\033[0m' # No Color
|
||
else
|
||
BOLD=''
|
||
GREEN=''
|
||
BLUE=''
|
||
YELLOW=''
|
||
RED=''
|
||
NC=''
|
||
fi
|
||
|
||
# Logging helpers
|
||
log() { printf "${BOLD}%s${NC}\n" "$1"; }
|
||
info() { printf " ${BLUE}ℹ️ %s${NC}\n" "$1"; }
|
||
success() { printf "${GREEN}✅ %s${NC}\n" "$1"; }
|
||
warn() { printf "${YELLOW}⚠️ %s${NC}\n" "$1"; }
|
||
error() { printf "${RED}🛑 ERROR: %s${NC}\n" "$1"; exit 1; }
|
||
|
||
# Banner
|
||
show_banner() {
|
||
cat << "EOF"
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
🧅 Tor Guard Relay - Quick Start Setup
|
||
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||
|
||
This script will help you deploy a Tor relay in minutes!
|
||
|
||
EOF
|
||
}
|
||
|
||
# Prompt for input with default value
|
||
prompt() {
|
||
prompt_text="$1"
|
||
default_val="$2"
|
||
var_name="$3"
|
||
|
||
if [ -n "$default_val" ]; then
|
||
printf "${BOLD}%s${NC} [${GREEN}%s${NC}]: " "$prompt_text" "$default_val"
|
||
else
|
||
printf "${BOLD}%s${NC}: " "$prompt_text"
|
||
fi
|
||
|
||
read -r input
|
||
if [ -z "$input" ]; then
|
||
input="$default_val"
|
||
fi
|
||
|
||
eval "$var_name=\"\$input\""
|
||
}
|
||
|
||
# Validate nickname
|
||
validate_nickname() {
|
||
nickname="$1"
|
||
|
||
# Length check (1-19 characters)
|
||
nickname_len=$(printf "%s" "$nickname" | wc -c)
|
||
if [ "$nickname_len" -lt 1 ] || [ "$nickname_len" -gt 19 ]; then
|
||
warn "Nickname must be 1-19 characters (you entered: $nickname_len)"
|
||
return 1
|
||
fi
|
||
|
||
# Alphanumeric only
|
||
if ! printf "%s" "$nickname" | grep -qE '^[a-zA-Z0-9]+$'; then
|
||
warn "Nickname must contain only letters and numbers"
|
||
return 1
|
||
fi
|
||
|
||
# Reserved names
|
||
case "$(printf "%s" "$nickname" | tr '[:upper:]' '[:lower:]')" in
|
||
unnamed|noname|default|tor|relay|bridge|exit)
|
||
warn "Cannot use reserved name: $nickname"
|
||
return 1
|
||
;;
|
||
esac
|
||
|
||
return 0
|
||
}
|
||
|
||
# Validate email
|
||
validate_email() {
|
||
email="$1"
|
||
|
||
# Basic length check
|
||
email_len=$(printf "%s" "$email" | wc -c)
|
||
if [ "$email_len" -lt 5 ]; then
|
||
warn "Email must be at least 5 characters"
|
||
return 1
|
||
fi
|
||
|
||
# Very basic email format check
|
||
if ! printf "%s" "$email" | grep -qE '^[^@]+@[^@]+\.[^@]+$'; then
|
||
warn "Email format appears invalid (should be: name@domain.com)"
|
||
return 1
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# Validate port
|
||
validate_port() {
|
||
port="$1"
|
||
port_name="$2"
|
||
|
||
# Integer check
|
||
if ! printf "%s" "$port" | grep -qE '^[0-9]+$'; then
|
||
warn "$port_name must be a valid number"
|
||
return 1
|
||
fi
|
||
|
||
# Range check
|
||
if [ "$port" -lt 1 ] || [ "$port" -gt 65535 ]; then
|
||
warn "$port_name must be between 1-65535"
|
||
return 1
|
||
fi
|
||
|
||
# Warn about privileged ports
|
||
if [ "$port" -lt 1024 ]; then
|
||
warn "$port_name is a privileged port (<1024) - may require CAP_NET_BIND_SERVICE capability"
|
||
fi
|
||
|
||
return 0
|
||
}
|
||
|
||
# Main menu
|
||
show_menu() {
|
||
log ""
|
||
log "What type of Tor relay do you want to run?"
|
||
log ""
|
||
printf " ${BOLD}1)${NC} ${GREEN}Guard/Middle Relay${NC} - Safest option, routes traffic\n"
|
||
printf " ${BOLD}2)${NC} ${YELLOW}Exit Relay${NC} - Advanced, requires legal compliance\n"
|
||
printf " ${BOLD}3)${NC} ${BLUE}Bridge Relay${NC} - Helps users in censored regions (obfs4)\n"
|
||
printf " ${BOLD}4)${NC} ${RED}Quit${NC}\n"
|
||
log ""
|
||
}
|
||
|
||
# Collect common information
|
||
collect_common_info() {
|
||
log ""
|
||
log "📋 Basic Relay Information"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
# Nickname
|
||
while true; do
|
||
prompt "Relay Nickname (1-19 alphanumeric)" "MyTorRelay" NICKNAME
|
||
if validate_nickname "$NICKNAME"; then
|
||
success "Nickname accepted: $NICKNAME"
|
||
break
|
||
fi
|
||
done
|
||
|
||
log ""
|
||
|
||
# Email
|
||
while true; do
|
||
prompt "Contact Email" "admin@example.com" EMAIL
|
||
if validate_email "$EMAIL"; then
|
||
success "Email accepted: $EMAIL"
|
||
break
|
||
fi
|
||
done
|
||
|
||
log ""
|
||
|
||
# ORPort
|
||
while true; do
|
||
if [ "$RELAY_MODE" = "guard" ]; then
|
||
prompt "ORPort (recommended: 443 or 9001)" "9001" OR_PORT
|
||
elif [ "$RELAY_MODE" = "exit" ]; then
|
||
prompt "ORPort (recommended: 443)" "443" OR_PORT
|
||
else
|
||
prompt "ORPort (recommended: 443 or 9001)" "9001" OR_PORT
|
||
fi
|
||
|
||
if validate_port "$OR_PORT" "ORPort"; then
|
||
success "ORPort set to: $OR_PORT"
|
||
break
|
||
fi
|
||
done
|
||
}
|
||
|
||
# Guard relay specific
|
||
collect_guard_info() {
|
||
log ""
|
||
log "⚙️ Guard Relay Configuration"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
info "Guard relays provide directory services and route traffic."
|
||
info "They are the safest and easiest type of relay to operate."
|
||
log ""
|
||
|
||
# DirPort
|
||
while true; do
|
||
prompt "DirPort (set to 0 to disable)" "9030" DIR_PORT
|
||
|
||
if [ "$DIR_PORT" = "0" ]; then
|
||
success "DirPort disabled"
|
||
break
|
||
fi
|
||
|
||
if validate_port "$DIR_PORT" "DirPort"; then
|
||
success "DirPort set to: $DIR_PORT"
|
||
break
|
||
fi
|
||
done
|
||
|
||
log ""
|
||
|
||
# Bandwidth
|
||
prompt "Bandwidth Rate (e.g., 50 MBytes, leave empty for unlimited)" "" BANDWIDTH_RATE
|
||
if [ -n "$BANDWIDTH_RATE" ]; then
|
||
prompt "Bandwidth Burst (e.g., 100 MBytes)" "" BANDWIDTH_BURST
|
||
fi
|
||
}
|
||
|
||
# Exit relay specific
|
||
collect_exit_info() {
|
||
log ""
|
||
log "⚠️ Exit Relay Configuration"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
warn "EXIT RELAYS ARE ADVANCED AND HAVE LEGAL IMPLICATIONS!"
|
||
log ""
|
||
info "Exit relays route traffic to the public internet."
|
||
info "You WILL receive abuse complaints and may need to respond to legal requests."
|
||
info "Make sure you understand the risks and legal requirements."
|
||
log ""
|
||
|
||
# Confirmation
|
||
prompt "Are you sure you want to run an exit relay? (yes/no)" "no" CONFIRM
|
||
|
||
if [ "$CONFIRM" != "yes" ] && [ "$CONFIRM" != "YES" ]; then
|
||
error "Exit relay setup cancelled. Consider running a guard or bridge relay instead."
|
||
fi
|
||
|
||
log ""
|
||
|
||
# DirPort
|
||
while true; do
|
||
prompt "DirPort (set to 0 to disable)" "9030" DIR_PORT
|
||
|
||
if [ "$DIR_PORT" = "0" ]; then
|
||
success "DirPort disabled"
|
||
break
|
||
fi
|
||
|
||
if validate_port "$DIR_PORT" "DirPort"; then
|
||
success "DirPort set to: $DIR_PORT"
|
||
break
|
||
fi
|
||
done
|
||
|
||
log ""
|
||
|
||
# Exit policy
|
||
log "Exit Policy Options:"
|
||
printf " ${BOLD}1)${NC} Reduced exit (recommended) - allows common ports\n"
|
||
printf " ${BOLD}2)${NC} Reject all (safer) - effectively a guard relay\n"
|
||
printf " ${BOLD}3)${NC} Custom policy - you provide the policy\n"
|
||
log ""
|
||
|
||
prompt "Exit Policy Choice" "1" POLICY_CHOICE
|
||
|
||
case "$POLICY_CHOICE" in
|
||
1)
|
||
EXIT_POLICY="ExitPolicy accept *:80\\nExitPolicy accept *:443\\nExitPolicy reject *:*"
|
||
info "Using reduced exit policy (HTTP/HTTPS only)"
|
||
;;
|
||
2)
|
||
EXIT_POLICY="ExitPolicy reject *:*"
|
||
info "Using reject all policy"
|
||
;;
|
||
3)
|
||
prompt "Enter custom exit policy (e.g., 'ExitPolicy reject *:*')" "ExitPolicy reject *:*" EXIT_POLICY
|
||
;;
|
||
*)
|
||
EXIT_POLICY="ExitPolicy reject *:*"
|
||
warn "Invalid choice, using reject all"
|
||
;;
|
||
esac
|
||
|
||
log ""
|
||
|
||
# Bandwidth
|
||
prompt "Bandwidth Rate (e.g., 50 MBytes, leave empty for unlimited)" "" BANDWIDTH_RATE
|
||
if [ -n "$BANDWIDTH_RATE" ]; then
|
||
prompt "Bandwidth Burst (e.g., 100 MBytes)" "" BANDWIDTH_BURST
|
||
fi
|
||
}
|
||
|
||
# Bridge relay specific
|
||
collect_bridge_info() {
|
||
log ""
|
||
log "🌉 Bridge Relay Configuration"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
info "Bridge relays help users in censored regions access Tor."
|
||
info "They use obfs4 pluggable transport to disguise Tor traffic."
|
||
log ""
|
||
|
||
# PT_PORT (obfs4 port)
|
||
while true; do
|
||
prompt "obfs4 Port (PT_PORT, recommended: 443 or 9002)" "9002" PT_PORT
|
||
|
||
if validate_port "$PT_PORT" "PT_PORT"; then
|
||
success "obfs4 Port set to: $PT_PORT"
|
||
break
|
||
fi
|
||
done
|
||
|
||
log ""
|
||
|
||
# Bandwidth
|
||
prompt "Bandwidth Rate (e.g., 50 MBytes, leave empty for unlimited)" "" BANDWIDTH_RATE
|
||
if [ -n "$BANDWIDTH_RATE" ]; then
|
||
prompt "Bandwidth Burst (e.g., 100 MBytes)" "" BANDWIDTH_BURST
|
||
fi
|
||
}
|
||
|
||
# Generate docker run command
|
||
generate_docker_run() {
|
||
log ""
|
||
log "🐳 Docker Run Command"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
cat > /tmp/tor-relay-run.sh << EOF
|
||
#!/bin/sh
|
||
# Tor ${RELAY_MODE} Relay - Generated by quick-start.sh
|
||
# Run this script to start your Tor relay
|
||
|
||
docker run -d \\
|
||
--name tor-${RELAY_MODE} \\
|
||
--network host \\
|
||
--restart unless-stopped \\
|
||
--cap-drop ALL \\
|
||
--cap-add NET_BIND_SERVICE \\
|
||
--security-opt no-new-privileges \\
|
||
-e NICKNAME="${NICKNAME}" \\
|
||
-e EMAIL="${EMAIL}" \\
|
||
-e OR_PORT=${OR_PORT} \\
|
||
EOF
|
||
|
||
# Mode-specific additions
|
||
if [ "$RELAY_MODE" = "guard" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-e TOR_RELAY_MODE=guard \\
|
||
-e TOR_DIRPORT=${DIR_PORT} \\
|
||
EOF
|
||
elif [ "$RELAY_MODE" = "exit" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-e TOR_RELAY_MODE=exit \\
|
||
-e TOR_DIRPORT=${DIR_PORT} \\
|
||
-e TOR_EXIT_POLICY="${EXIT_POLICY}" \\
|
||
EOF
|
||
elif [ "$RELAY_MODE" = "bridge" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-e PT_PORT=${PT_PORT} \\
|
||
EOF
|
||
fi
|
||
|
||
# Bandwidth (if set)
|
||
if [ -n "$BANDWIDTH_RATE" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-e TOR_BANDWIDTH_RATE="${BANDWIDTH_RATE}" \\
|
||
EOF
|
||
fi
|
||
|
||
if [ -n "$BANDWIDTH_BURST" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-e TOR_BANDWIDTH_BURST="${BANDWIDTH_BURST}" \\
|
||
EOF
|
||
fi
|
||
|
||
# Volumes and image
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
-v tor-${RELAY_MODE}-data:/var/lib/tor \\
|
||
-v tor-${RELAY_MODE}-logs:/var/log/tor \\
|
||
ghcr.io/r3bo0tbx1/onion-relay:latest
|
||
|
||
# Wait for container to start
|
||
sleep 5
|
||
|
||
# Show container status
|
||
docker ps | grep tor-${RELAY_MODE}
|
||
|
||
echo ""
|
||
echo "✅ Tor ${RELAY_MODE} relay started!"
|
||
echo ""
|
||
echo "📋 Useful commands:"
|
||
echo " docker logs tor-${RELAY_MODE} - View logs"
|
||
echo " docker exec tor-${RELAY_MODE} status - Full health check"
|
||
echo " docker exec tor-${RELAY_MODE} health - JSON health API"
|
||
EOF
|
||
|
||
if [ "$RELAY_MODE" = "bridge" ]; then
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
echo " docker exec tor-${RELAY_MODE} bridge-line - Get bridge line to share"
|
||
EOF
|
||
else
|
||
cat >> /tmp/tor-relay-run.sh << EOF
|
||
echo " docker exec tor-${RELAY_MODE} fingerprint - Get relay fingerprint"
|
||
EOF
|
||
fi
|
||
|
||
chmod +x /tmp/tor-relay-run.sh
|
||
|
||
success "Docker run script generated: /tmp/tor-relay-run.sh"
|
||
log ""
|
||
cat /tmp/tor-relay-run.sh
|
||
log ""
|
||
}
|
||
|
||
# Generate docker-compose.yml
|
||
generate_docker_compose() {
|
||
log ""
|
||
log "🐳 Docker Compose Configuration"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
cat > /tmp/docker-compose.yml << EOF
|
||
# Tor ${RELAY_MODE} Relay - Generated by quick-start.sh
|
||
# Deploy with: docker-compose up -d
|
||
|
||
version: '3.8'
|
||
|
||
services:
|
||
tor-${RELAY_MODE}:
|
||
image: ghcr.io/r3bo0tbx1/onion-relay:latest
|
||
container_name: tor-${RELAY_MODE}
|
||
restart: unless-stopped
|
||
network_mode: host
|
||
|
||
# Security settings
|
||
cap_drop:
|
||
- ALL
|
||
cap_add:
|
||
- NET_BIND_SERVICE
|
||
security_opt:
|
||
- no-new-privileges:true
|
||
|
||
# Environment variables
|
||
environment:
|
||
NICKNAME: "${NICKNAME}"
|
||
EMAIL: "${EMAIL}"
|
||
OR_PORT: ${OR_PORT}
|
||
EOF
|
||
|
||
# Mode-specific additions
|
||
if [ "$RELAY_MODE" = "guard" ]; then
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
TOR_RELAY_MODE: guard
|
||
TOR_DIRPORT: ${DIR_PORT}
|
||
EOF
|
||
elif [ "$RELAY_MODE" = "exit" ]; then
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
TOR_RELAY_MODE: exit
|
||
TOR_DIRPORT: ${DIR_PORT}
|
||
TOR_EXIT_POLICY: "${EXIT_POLICY}"
|
||
EOF
|
||
elif [ "$RELAY_MODE" = "bridge" ]; then
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
PT_PORT: ${PT_PORT}
|
||
EOF
|
||
fi
|
||
|
||
# Bandwidth (if set)
|
||
if [ -n "$BANDWIDTH_RATE" ]; then
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
TOR_BANDWIDTH_RATE: "${BANDWIDTH_RATE}"
|
||
EOF
|
||
fi
|
||
|
||
if [ -n "$BANDWIDTH_BURST" ]; then
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
TOR_BANDWIDTH_BURST: "${BANDWIDTH_BURST}"
|
||
EOF
|
||
fi
|
||
|
||
# Volumes
|
||
cat >> /tmp/docker-compose.yml << EOF
|
||
|
||
# Data persistence
|
||
volumes:
|
||
- tor-${RELAY_MODE}-data:/var/lib/tor
|
||
- tor-${RELAY_MODE}-logs:/var/log/tor
|
||
|
||
volumes:
|
||
tor-${RELAY_MODE}-data:
|
||
driver: local
|
||
tor-${RELAY_MODE}-logs:
|
||
driver: local
|
||
EOF
|
||
|
||
success "Docker Compose file generated: /tmp/docker-compose.yml"
|
||
log ""
|
||
cat /tmp/docker-compose.yml
|
||
log ""
|
||
}
|
||
|
||
# Next steps
|
||
show_next_steps() {
|
||
log ""
|
||
log "🚀 Next Steps"
|
||
log "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||
log ""
|
||
|
||
log "1. Review the generated configuration:"
|
||
info " - Docker run script: /tmp/tor-relay-run.sh"
|
||
info " - Docker Compose file: /tmp/docker-compose.yml"
|
||
log ""
|
||
|
||
log "2. Deploy your relay:"
|
||
info " ${BOLD}Option A:${NC} Run the script"
|
||
info " sh /tmp/tor-relay-run.sh"
|
||
log ""
|
||
info " ${BOLD}Option B:${NC} Use Docker Compose"
|
||
info " cp /tmp/docker-compose.yml ~/tor-relay/"
|
||
info " cd ~/tor-relay && docker-compose up -d"
|
||
log ""
|
||
|
||
log "3. Monitor your relay:"
|
||
info " docker logs tor-${RELAY_MODE}"
|
||
info " docker exec tor-${RELAY_MODE} status"
|
||
log ""
|
||
|
||
if [ "$RELAY_MODE" = "bridge" ]; then
|
||
log "4. Share your bridge line:"
|
||
info " Wait 2-5 minutes for Tor to bootstrap (100%)"
|
||
info " docker exec tor-${RELAY_MODE} bridge-line"
|
||
info " Share the output with users in censored regions"
|
||
log ""
|
||
else
|
||
log "4. Find your relay on Tor Metrics:"
|
||
info " Wait 24-48 hours for your relay to appear"
|
||
info " docker exec tor-${RELAY_MODE} fingerprint"
|
||
info " Visit the Tor Metrics URL shown"
|
||
log ""
|
||
fi
|
||
|
||
if [ "$RELAY_MODE" = "exit" ]; then
|
||
warn "IMPORTANT FOR EXIT RELAYS:"
|
||
info " - Monitor abuse complaints: ${EMAIL}"
|
||
info " - Set up reverse DNS (PTR record) for your IP"
|
||
info " - Consider getting AS number and WHOIS info"
|
||
info " - Read: https://community.torproject.org/relay/community-resources/tor-exit-guidelines/"
|
||
log ""
|
||
fi
|
||
|
||
log "5. Documentation:"
|
||
info " - FAQ: https://github.com/r3bo0tbx1/tor-guard-relay/blob/main/docs/FAQ.md"
|
||
info " - Architecture: https://github.com/r3bo0tbx1/tor-guard-relay/blob/main/docs/ARCHITECTURE.md"
|
||
info " - Monitoring: https://github.com/r3bo0tbx1/tor-guard-relay/blob/main/docs/MONITORING.md"
|
||
log ""
|
||
|
||
success "Setup complete! Thank you for supporting the Tor network! 🧅"
|
||
log ""
|
||
}
|
||
|
||
# Main execution
|
||
main() {
|
||
show_banner
|
||
|
||
# Main menu loop
|
||
while true; do
|
||
show_menu
|
||
prompt "Choose an option" "1" CHOICE
|
||
|
||
case "$CHOICE" in
|
||
1)
|
||
RELAY_MODE="guard"
|
||
collect_common_info
|
||
collect_guard_info
|
||
generate_docker_run
|
||
generate_docker_compose
|
||
show_next_steps
|
||
exit 0
|
||
;;
|
||
2)
|
||
RELAY_MODE="exit"
|
||
collect_common_info
|
||
collect_exit_info
|
||
generate_docker_run
|
||
generate_docker_compose
|
||
show_next_steps
|
||
exit 0
|
||
;;
|
||
3)
|
||
RELAY_MODE="bridge"
|
||
collect_common_info
|
||
collect_bridge_info
|
||
generate_docker_run
|
||
generate_docker_compose
|
||
show_next_steps
|
||
exit 0
|
||
;;
|
||
4)
|
||
log ""
|
||
log "👋 Goodbye! Thank you for considering running a Tor relay."
|
||
log ""
|
||
exit 0
|
||
;;
|
||
*)
|
||
warn "Invalid choice. Please select 1-4."
|
||
;;
|
||
esac
|
||
done
|
||
}
|
||
|
||
main "$@"
|