feat(security): enforce localhost-only binding for internal services (v1.0.2)

BREAKING CHANGE: Internal services now bind to 127.0.0.1 by default

This release enforces strict port security with a two-tier model:
- Public: 9001 (ORPort), 9030 (DirPort)
- Internal: 9035+ (metrics, health, dashboard) - localhost-only

Changes:
- CHANGELOG.md: Updated version entries, aligned to v1.0.2
- README.md: Updated version references and deployment examples
- SECURITY.md: Enhanced with network architecture and port policy
- relay-status.sh: Added port security validation (v1.0.2)
- integration-check.sh: Added port/version validation phases (v1.0.2)

Security Improvements:
- Prevents unauthorized external access to internal endpoints
- Adds reverse proxy, SSH tunnel, and VPN access guidance
- Includes comprehensive migration guide for existing deployments
- Adds automated security validation in diagnostic tools

Migration Required:
If accessing metrics/health externally, use reverse proxy with auth,
SSH tunneling, or VPN. See SECURITY.md for details.

Version: 1.0.2
This commit is contained in:
rE-Bo0t.bx1
2025-11-05 18:19:04 +08:00
parent 5e70cf0b2d
commit 25fd7a09d7
12 changed files with 1503 additions and 408 deletions

View File

@@ -41,7 +41,7 @@ jobs:
- name: 📥 Checkout Repository
uses: actions/checkout@v5
with:
fetch-depth: 0 # Full history for tag detection
fetch-depth: 0
- name: 🔍 Detect Version & Build Type
id: version
@@ -109,7 +109,7 @@ jobs:
with:
platforms: arm64,amd64
- name: <EFBFBD> Set up Docker Buildx
- name: 🏗 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 🏷️ Generate Docker Tags
@@ -198,21 +198,49 @@ jobs:
IMAGE_TAG="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${VERSION}"
fi
echo "Validating image: ${IMAGE_TAG}"
echo "🔍 Validating image: ${IMAGE_TAG}"
# Pull and verify image exists
echo "📦 Pulling image..."
docker pull "${IMAGE_TAG}" || exit 1
# Verify Alpine base
echo "🐧 Checking Alpine base..."
docker run --rm "${IMAGE_TAG}" cat /etc/os-release | grep -i alpine || exit 1
# Verify build info exists
echo "📋 Checking build metadata..."
docker run --rm "${IMAGE_TAG}" cat /build-info.txt || exit 1
# Verify Tor is installed
docker run --rm "${IMAGE_TAG}" tor --version || exit 1
# Verify Tor is installed and functional
echo "🧅 Verifying Tor installation..."
TOR_VERSION=$(docker run --rm "${IMAGE_TAG}" tor --version | head -1)
if [ -z "$TOR_VERSION" ]; then
echo "❌ Tor version check failed"
exit 1
fi
echo "✅ Tor version: $TOR_VERSION"
echo "✅ Image validation successful"
# Verify required tools exist
echo "🛠️ Checking diagnostic tools..."
for tool in health metrics status fingerprint view-logs net-check setup dashboard; do
if docker run --rm "${IMAGE_TAG}" sh -c "command -v $tool" > /dev/null 2>&1; then
echo " ✅ $tool found"
else
echo " ⚠️ $tool not found (may be optional)"
fi
done
# Verify entrypoint is executable
echo "🔧 Checking entrypoint..."
docker run --rm "${IMAGE_TAG}" sh -c "test -x /usr/local/bin/docker-entrypoint.sh" || exit 1
# Verify permissions on critical directories
echo "🔒 Checking permissions..."
docker run --rm "${IMAGE_TAG}" sh -c "ls -ld /var/lib/tor | grep '^d.*tor tor'" || exit 1
echo ""
echo "✅ All validation checks passed"
release-notes:
name: 📝 Generate Release Notes
@@ -321,9 +349,9 @@ jobs:
\`\`\`
## 📚 Documentation
- [Deployment Guide](https://github.com/${{ github.repository }}/blob/main/DEPLOYMENT.md)
- [Backup Guide](https://github.com/${{ github.repository }}/blob/main/BACKUP.md)
- [Performance Tuning](https://github.com/${{ github.repository }}/blob/main/PERFORMANCE.md)
- [Deployment Guide](https://github.com/${{ github.repository }}/blob/main/docs/DEPLOYMENT.md)
- [Backup Guide](https://github.com/${{ github.repository }}/blob/main/docs/BACKUP.md)
- [Performance Tuning](https://github.com/${{ github.repository }}/blob/main/docs/PERFORMANCE.md)
EOF
- name: ✅ Workflow Complete

View File

@@ -14,7 +14,8 @@ on:
- 'Dockerfile'
- 'docker-entrypoint.sh'
- 'tools/**'
- '.github/workflows/build.yml'
- '.github/workflows/release.yml'
- '.github/workflows/validate.yml'
permissions:
contents: read
@@ -26,63 +27,108 @@ jobs:
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: 🔍 Lint Dockerfile
- name: 🔍 Lint Dockerfile with Hadolint
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
failure-threshold: warning
- name: 🔍 Validate Dockerfile Syntax
run: |
# Check Dockerfile syntax
docker build --dry-run . || exit 1
echo "✓ Dockerfile syntax valid"
echo "Validating Dockerfile build context..."
docker build --no-cache --target builder -t tor-relay-test . 2>&1 | tee /tmp/docker-build.log || true
# Check for common errors
if grep -i "error" /tmp/docker-build.log; then
echo "❌ Dockerfile validation failed"
exit 1
fi
echo "✅ Dockerfile syntax valid"
- name: 🔍 Lint Shell Scripts
run: |
# Check shell script syntax
for script in docker-entrypoint.sh tools/* integration-check.sh; do
echo "Checking shell script syntax..."
# Check entrypoint
if [ -f docker-entrypoint.sh ]; then
bash -n docker-entrypoint.sh || exit 1
echo "✅ docker-entrypoint.sh syntax valid"
fi
# Check all tools
for script in tools/*; do
if [ -f "$script" ]; then
# Check if it's a shell script
if head -1 "$script" | grep -q "^#!/"; then
sh -n "$script" || exit 1
echo "✅ $script syntax valid"
fi
fi
done
# Check additional scripts
for script in integration-check.sh relay-status.sh; do
if [ -f "$script" ]; then
bash -n "$script" || exit 1
echo " $script syntax valid"
echo " $script syntax valid"
fi
done
- name: 🔍 Install ShellCheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: 🔍 Run ShellCheck on Scripts
run: |
echo "Running ShellCheck on shell scripts..."
# Check entrypoint with specific exclusions
if [ -f docker-entrypoint.sh ]; then
shellcheck -S warning docker-entrypoint.sh || true
fi
# Check tools directory
find tools -type f -exec shellcheck -S warning {} \; || true
echo "✅ ShellCheck analysis complete"
- name: 🔍 Lint YAML Files
run: |
# Install yq if not available
if ! command -v yq &> /dev/null; then
curl -sL https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o yq
chmod +x yq
export PATH=$PWD:$PATH
fi
# Check YAML syntax
for yaml in templates/*.yml docs/*.yml .github/workflows/*.yml; do
echo "Installing yamllint..."
pip install yamllint
echo "Validating YAML files..."
for yaml in templates/*.yml docs/*.yml .github/workflows/*.yml .github/dependabot.yml; do
if [ -f "$yaml" ]; then
yq eval '.' "$yaml" > /dev/null || exit 1
echo " $yaml syntax valid"
yamllint -d relaxed "$yaml" || exit 1
echo " $yaml syntax valid"
fi
done
- name: 🔍 Validate JSON Files
run: |
# Check JSON syntax
for json in templates/*.json examples/*.json; do
echo "Validating JSON files..."
for json in templates/*.json examples/*.json .github/*.json; do
if [ -f "$json" ]; then
python3 -m json.tool "$json" > /dev/null || exit 1
echo " $json syntax valid"
echo " $json syntax valid"
fi
done
- name: 📋 Check Documentation
run: |
# Verify key documentation files exist
echo "Verifying required documentation files..."
required_docs=(
"README.md"
"docs/DEPLOYMENT.md"
"docs/BACKUP.md"
"docs/PERFORMANCE.md"
"docs/LEGAL.md"
"CHANGELOG.md"
"SECURITY.md"
"CONTRIBUTING.md"
"CODE_OF_CONDUCT.md"
"LICENSE.txt"
)
for doc in "${required_docs[@]}"; do
@@ -90,8 +136,20 @@ jobs:
echo "❌ Missing documentation: $doc"
exit 1
fi
echo " $doc exists"
echo " $doc exists"
done
# Check docs directory structure
if [ -d "docs" ]; then
echo "📁 Checking docs/ directory..."
for doc in DEPLOYMENT.md BACKUP.md PERFORMANCE.md LEGAL.md MONITORING.md TOOLS.md; do
if [ -f "docs/$doc" ]; then
echo "✅ docs/$doc exists"
else
echo "⚠️ docs/$doc missing (optional)"
fi
done
fi
- name: ✅ Lint Summary
run: echo "✅ All linting checks passed"
@@ -103,7 +161,7 @@ jobs:
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: ⚙️ Set up QEMU
uses: docker/setup-qemu-action@v3
@@ -114,7 +172,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: 🐳 Build Image (amd64 for testing)
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
@@ -124,6 +182,8 @@ jobs:
build-args: |
BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')
BUILD_VERSION=test-${{ github.run_number }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 💾 Save Image for Testing
run: |
@@ -131,7 +191,7 @@ jobs:
echo "Image size: $(du -h /tmp/tor-relay-test.tar | cut -f1)"
- name: 📤 Upload Image Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: docker-image
path: /tmp/tor-relay-test.tar
@@ -144,10 +204,10 @@ jobs:
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: 📥 Download Docker Image
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: docker-image
path: /tmp
@@ -157,53 +217,82 @@ jobs:
docker load -i /tmp/tor-relay-test.tar
docker image ls tor-relay
- name: 🧪 Run Container
- name: 🧪 Run Container Smoke Test
run: |
# Start container in background (without actual Tor relay, just test setup)
echo "Starting container for smoke test..."
# Start container in background (test mode)
docker run -d \
--name tor-test \
--network host \
-e ENABLE_METRICS=true \
-e ENABLE_HEALTH_CHECK=true \
-v /tmp/torrc:/etc/tor/torrc:ro \
tor-relay:test \
/bin/sh -c "echo 'Test mode'; sleep 30" || true
/bin/sh -c "echo 'Test mode active'; sleep 60" || true
# Wait for container to start
sleep 5
- name: ✅ Check Container Status
run: |
echo "Container status:"
docker ps -a | grep tor-test || true
docker logs tor-test 2>&1 | head -20 || true
echo ""
echo "Container logs:"
docker logs tor-test 2>&1 | head -30 || true
- name: 🧩 Run Integration Check
- name: 🧩 Verify Tools Installation
run: |
# Check tool availability inside image
docker run --rm \
-v $(pwd):/workspace:ro \
tor-relay:test \
ls -la /usr/local/bin/ || exit 1
echo "Checking installed tools..."
docker run --rm tor-relay:test ls -la /usr/local/bin/ || exit 1
echo ""
echo "Available diagnostic tools:"
docker run --rm tor-relay:test sh -c "ls -1 /usr/local/bin/ | grep -v '^tor$' | sort"
# List available tools
docker run --rm tor-relay:test sh -c "ls -1 /usr/local/bin/ | grep -v '^tor$'" || true
- name: 🧅 Verify Tor Installation
run: |
echo "Checking Tor version..."
TOR_VERSION=$(docker run --rm tor-relay:test tor --version | head -1)
if [ -z "$TOR_VERSION" ]; then
echo "❌ Tor installation failed"
exit 1
fi
echo "✅ Tor installed: $TOR_VERSION"
- name: 📋 Verify File Structure
run: |
docker run --rm tor-relay:test sh -c "
echo '=== Directory Structure ===' && \
ls -la / | grep -E 'var|etc|usr' && \
echo '' && \
echo '=== Tools Directory ===' && \
ls -la /usr/local/bin/ && \
echo '' && \
echo '=== Data Directory ===' && \
ls -la /var/lib/tor 2>/dev/null || echo '(data dir empty, expected)' && \
echo '' && \
echo '=== Log Directory ===' && \
ls -la /var/log/tor 2>/dev/null || echo '(log dir empty, expected)'
"
- name: 🏥 Check Build Metadata
run: |
echo "Checking build metadata..."
docker run --rm tor-relay:test cat /build-info.txt || exit 1
- name: 🔒 Verify Permissions
run: |
echo "Verifying directory permissions..."
docker run --rm tor-relay:test sh -c "
ls -ld /var/lib/tor | grep -q '^d.*tor tor' && echo '✅ /var/lib/tor permissions correct' || exit 1
ls -ld /var/log/tor | grep -q '^d.*tor tor' && echo '✅ /var/log/tor permissions correct' || exit 1
"
- name: ✅ Integration Tests Summary
run: echo "✅ Integration tests completed"
run: echo "✅ Integration tests completed successfully"
- name: 🧹 Cleanup
if: always()
@@ -218,10 +307,10 @@ jobs:
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: 📥 Download Docker Image
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: docker-image
path: /tmp
@@ -238,11 +327,18 @@ jobs:
severity: 'CRITICAL,HIGH'
- name: 📤 Upload Trivy Results
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
continue-on-error: true
- name: 🔒 Trivy Vulnerability Report
uses: aquasecurity/trivy-action@master
with:
image-ref: 'tor-relay:test'
format: 'table'
severity: 'CRITICAL,HIGH'
- name: ✅ Security Scan Complete
run: echo "✅ Security scan completed"
@@ -252,18 +348,20 @@ jobs:
needs: build
strategy:
fail-fast: false
matrix:
test-case:
- 'help-flags'
- 'file-permissions'
- 'alpine-compatibility'
- 'tool-executability'
steps:
- name: 📥 Checkout Repository
uses: actions/checkout@v4
uses: actions/checkout@v5
- name: 📥 Download Docker Image
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
with:
name: docker-image
path: /tmp
@@ -272,33 +370,63 @@ jobs:
run: docker load -i /tmp/tor-relay-test.tar
- name: "🧪 Test: Help Flags"
if: "matrix.test-case == 'help-flags'"
if: matrix.test-case == 'help-flags'
run: |
# Test that tools respond to --help
docker run --rm tor-relay:test sh -c "
/usr/local/bin/health --help > /dev/null && echo '✓ health --help' || true
/usr/local/bin/metrics --help > /dev/null && echo '✓ metrics --help' || true
/usr/local/bin/dashboard --help > /dev/null && echo '✓ dashboard --help' || true
" || true
echo "Testing tool help flags..."
for tool in health metrics status fingerprint view-logs net-check setup dashboard; do
if docker run --rm tor-relay:test sh -c "command -v $tool" > /dev/null 2>&1; then
echo "Testing $tool --help..."
docker run --rm tor-relay:test $tool --help > /dev/null && echo "✅ $tool --help works" || echo "⚠️ $tool --help failed"
fi
done
- name: "🧪 Test: File Permissions"
if: "matrix.test-case == 'file-permissions'"
if: matrix.test-case == 'file-permissions'
run: |
# Verify executable permissions
echo "Verifying file permissions..."
# Check tool executability
docker run --rm tor-relay:test sh -c "
test -x /usr/local/bin/health && echo '✓ health is executable' || exit 1
test -x /usr/local/bin/metrics && echo '✓ metrics is executable' || exit 1
test -x /usr/local/bin/dashboard && echo '✓ dashboard is executable' || exit 1
for tool in health metrics status fingerprint view-logs net-check setup dashboard; do
if command -v \$tool > /dev/null 2>&1; then
test -x /usr/local/bin/\$tool && echo \"✅ \$tool is executable\" || exit 1
fi
done
"
# Check entrypoint
docker run --rm tor-relay:test sh -c "
test -x /usr/local/bin/docker-entrypoint.sh && echo '✅ entrypoint is executable' || exit 1
"
- name: "🧪 Test: Alpine Compatibility"
if: "matrix.test-case == 'alpine-compatibility'"
if: matrix.test-case == 'alpine-compatibility'
run: |
# Verify Alpine base image
echo "Verifying Alpine base image..."
docker run --rm tor-relay:test sh -c "
cat /etc/os-release | grep -i alpine && echo ' Alpine base confirmed' || exit 1
test -x /bin/sh && echo ' /bin/sh available' || exit 1
apk --version > /dev/null 2>&1 && echo ' apk available' || exit 1
cat /etc/os-release | grep -i alpine && echo ' Alpine base confirmed' || exit 1
test -x /bin/sh && echo ' /bin/sh available' || exit 1
apk --version > /dev/null 2>&1 && echo ' apk available' || exit 1
command -v tor > /dev/null 2>&1 && echo '✅ tor available' || exit 1
"
- name: "🧪 Test: Tool Executability"
if: matrix.test-case == 'tool-executability'
run: |
echo "Testing tool execution..."
# Test each tool can execute without errors
docker run --rm tor-relay:test sh -c "
# Test health (should work even without Tor running)
health --json > /dev/null 2>&1 || echo 'health requires Tor process'
# Test metrics
metrics --help > /dev/null 2>&1 && echo '✅ metrics executable' || exit 1
# Test status
status --help > /dev/null 2>&1 && echo '✅ status executable' || exit 1
"
summary:
@@ -314,43 +442,46 @@ jobs:
# 🧱 Build & Validation Pipeline
## Pipeline Status
- Lint: ${{ needs.lint.result }}
- Build: ${{ needs.build.result }}
- Integration: ${{ needs.integration.result }}
- Security: ${{ needs.security.result }}
- Test Matrix: ${{ needs.test-matrix.result }}
- **Lint:** \`${{ needs.lint.result }}\`
- **Build:** \`${{ needs.build.result }}\`
- **Integration:** \`${{ needs.integration.result }}\`
- **Security:** \`${{ needs.security.result }}\`
- **Test Matrix:** \`${{ needs.test-matrix.result }}\`
## Build Information
- **Branch:** `${{ github.ref }}`
- **Commit:** `${{ github.sha }}`
- **Run Number:** `${{ github.run_number }}`
- **Date:** `$(date -u +'%Y-%m-%dT%H:%M:%SZ')`
- **Branch:** \`${{ github.ref }}\`
- **Commit:** \`${{ github.sha }}\`
- **Run Number:** \`${{ github.run_number }}\`
- **Date:** \`$(date -u +'%Y-%m-%dT%H:%M:%SZ')\`
## Checks Performed
- ✅ Dockerfile syntax validation
- ✅ Shell script linting
- ✅ Dockerfile validation with Hadolint
- ✅ Shell script syntax checking
- ✅ ShellCheck analysis
- ✅ YAML validation
- ✅ JSON validation
- ✅ Documentation verification
- ✅ Docker image build
- ✅ Container startup test
- ✅ Docker image build (multi-arch ready)
- ✅ Container smoke test
- ✅ Tor installation verification
- ✅ Tool availability check
- ✅ Security scanning
- ✅ File permissions check
- ✅ Alpine compatibility check
- ✅ Permission verification
- ✅ Security scanning with Trivy
- ✅ Test matrix execution
## Next Steps
If all checks pass:
- Image is ready for testing
- Image is ready for production use
- Release workflow will handle publishing to GHCR
- Tag with semantic version to trigger release
EOF
- name: ✅ Build Pipeline Complete
if: success()
run: echo "✅ All build checks passed successfully"
run: echo "✅ All build and validation checks passed successfully"
- name: ❌ Build Pipeline Failed
if: failure()
run: |
echo "❌ Build pipeline failed"
echo "❌ Build pipeline failed - check logs above for details"
exit 1

View File

@@ -9,8 +9,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Planned Features
- Bridge relay variant
- Additional monitoring integrations
## [1.1.1] - 2025-11-05
## [1.0.2] - 2025-11-05
### 🔒 Security Hardening
**Network Exposure Model**
- Enforced strict two-port exposure policy (9001 ORPort, 9030 DirPort only)
- All monitoring services (metrics, health, dashboard) bound to localhost (127.0.0.1)
- Updated documentation to reflect secure-by-default configuration
**Tool Security**
- Changed default bind addresses from 0.0.0.0 → 127.0.0.1 (dashboard, metrics-http)
- Added automatic configuration backup in setup tool
- Implemented rate limiting for HTTP servers
- Enhanced SIGTERM handling for clean shutdowns
**Infrastructure**
- Pinned base image to Alpine 3.22.2 for reproducible builds
- Updated GitHub Actions to latest versions
- Fixed invalid docker build commands in CI/CD
- Enhanced process cleanup in docker-entrypoint.sh
### 📚 Documentation
**New Content**
- Comprehensive port exposure policy documentation
- Security model clarification (public vs internal ports)
- Enhanced deployment examples with security warnings
- Improved monitoring setup guides with localhost binding examples
**Updates**
- All documentation aligned to v1.0.2
- Corrected version references throughout
- Enhanced security warnings for external port exposure
- Updated template configurations
### 🛠️ Technical Improvements
**Scripts**
- Enhanced integration-check.sh with port validation
- Improved relay-status.sh output formatting
- Added version consistency checks
**Templates**
- Updated all docker-compose templates with explicit port policies
- Enhanced Prometheus/Grafana configurations
- Improved Cosmos Cloud templates with security annotations
### 🐛 Fixes
- Corrected version inconsistencies across documentation
- Fixed port exposure examples in deployment guides
- Updated monitoring endpoint documentation
---
## [1.0.1] - 2025-11-05
### 🎉 Major Restructuring
@@ -39,6 +94,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Same tool interfaces
- Volume mounts unchanged
---
## [1.0.0] - 2025-11-01
@@ -119,6 +175,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Release Information
- **First Release:** v1.0 (November 1, 2025)
- **Current Release:** v1.0.2
- **Latest Release:** [GitHub Releases](https://github.com/r3bo0tbx1/tor-guard-relay/releases/latest)
- **Docker Images:** [GHCR Package](https://github.com/r3bo0tbx1/tor-guard-relay/pkgs/container/onion-relay)
@@ -126,8 +183,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
| Version | Status | Support Period |
|---------|--------|----------------|
| 1.0.x | ✅ Actively Supported | Current |
| Future versions | - | TBD |
| 1.0.2 | ✅ Actively Supported | Current |
| 1.0.1 | ✅ Supported | Until v1.1.0 |
| 1.0.0 | ⚠️ Legacy | Security updates only |
[1.0]: https://github.com/r3bo0tbx1/tor-guard-relay/releases/tag/v1.0
[Unreleased]: https://github.com/r3bo0tbx1/tor-guard-relay/compare/v1.0...HEAD
[1.0.2]: https://github.com/r3bo0tbx1/tor-guard-relay/releases/tag/v1.0.2
[1.0.1]: https://github.com/r3bo0tbx1/tor-guard-relay/releases/tag/v1.0.1
[1.0.0]: https://github.com/r3bo0tbx1/tor-guard-relay/releases/tag/v1.0.0
[Unreleased]: https://github.com/r3bo0tbx1/tor-guard-relay/compare/v1.0.2...HEAD

View File

@@ -1,12 +1,17 @@
# syntax=docker/dockerfile:1.7
FROM alpine:latest
# ============================================================================
# Tor Guard Relay - Hardened relay with diagnostics and auto-healing
# Base: Alpine 3.22.2 | Multi-arch: amd64, arm64
# ============================================================================
# Metadata Arguments
FROM alpine:3.22.2
# Build arguments
ARG BUILD_DATE
ARG BUILD_VERSION
ARG TARGETARCH
# Labels
# OCI labels
LABEL maintainer="rE-Bo0t.bx1 <r3bo0tbx1@brokenbotnet.com>" \
org.opencontainers.image.title="Tor Guard Relay" \
org.opencontainers.image.description="🧅 Hardened Tor Guard Relay with diagnostics & auto-healing" \
@@ -15,16 +20,16 @@ LABEL maintainer="rE-Bo0t.bx1 <r3bo0tbx1@brokenbotnet.com>" \
org.opencontainers.image.source="https://github.com/r3bo0tbx1/tor-guard-relay" \
org.opencontainers.image.documentation="https://github.com/r3bo0tbx1/tor-guard-relay#readme" \
org.opencontainers.image.licenses="MIT" \
org.opencontainers.image.vendor="r3bo0tbx1" \
org.opencontainers.image.authors="rE-Bo0t.bx1 <r3bo0tbx1@brokenbotnet.com>" \
org.opencontainers.image.url="https://github.com/r3bo0tbx1/tor-guard-relay" \
org.opencontainers.image.base.name="docker.io/library/alpine:3.22.2" \
org.opencontainers.image.revision="${TARGETARCH}"
# Core dependencies
# - tor: main service
# - bash: entrypoint logic
# - tini: init process manager
# - curl: for diagnostics and network checks
# - jq, grep, coreutils: JSON parsing & utils
# - bind-tools: provides nslookup/dig for DNS diagnostics
# - netcat-openbsd: for port checking in net-check
# Install core dependencies
# tor: relay daemon | bash: entrypoint | tini: init system (PID 1)
# curl: diagnostics | jq: JSON parsing | bind-tools: DNS (dig/nslookup)
# netcat-openbsd: port checking | coreutils/grep: utilities
RUN apk add --no-cache \
tor \
bash \
@@ -37,24 +42,27 @@ RUN apk add --no-cache \
netcat-openbsd && \
rm -rf /var/cache/apk/*
# Directory structure setup
# Setup directories with proper permissions
# /var/lib/tor: data (keys, state) - 700 for security
# /var/log/tor: logs - 755 for diagnostics
# /run/tor: runtime (PID, socket) - 755 for health checks
RUN mkdir -p /var/lib/tor /var/log/tor /run/tor && \
chown -R tor:tor /var/lib/tor /var/log/tor /run/tor && \
chmod 700 /var/lib/tor && \
chmod 755 /var/log/tor /run/tor
# Default configuration placeholder
# Default configuration placeholder (mount your own at runtime)
RUN echo "# 🧅 Tor configuration is mounted at runtime" > /etc/tor/torrc
# Build metadata
# Embed build metadata
RUN printf "Version: %s\nBuild Date: %s\nArchitecture: %s\n" \
"${BUILD_VERSION:-dev}" "${BUILD_DATE:-unknown}" "${TARGETARCH:-amd64}" > /build-info.txt
# Copy entrypoint and diagnostic tools
# Copy application files
COPY docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh
COPY tools/ /usr/local/bin/
# Normalize scripts: remove CRLFs, BOMs, and fix permissions
# Normalize scripts: remove CRLF, BOM, and set permissions
RUN set -eux; \
for f in /usr/local/bin/*; do \
[ -f "$f" ] || continue; \
@@ -63,35 +71,39 @@ RUN set -eux; \
chmod +x "$f"; \
done; \
echo "🧩 Installed tools:"; \
ls -1 /usr/local/bin | grep -E 'docker-entrypoint|net-check|metrics|health|view-logs' || true
ls -1 /usr/local/bin | grep -E 'docker-entrypoint|net-check|metrics|health|view-logs|status|fingerprint|setup|dashboard' || true
# Environment defaults
# Environment configuration
ENV TOR_DATA_DIR=/var/lib/tor \
TOR_LOG_DIR=/var/log/tor \
TOR_CONFIG=/etc/tor/torrc \
ENABLE_METRICS=false \
ENABLE_HEALTH_CHECK=true \
ENABLE_NET_CHECK=true \
ENABLE_NET_CHECK=false \
PATH="/usr/local/bin:$PATH"
# Cleanup
# Cleanup to minimize image size
RUN rm -rf /usr/share/man /tmp/* /var/tmp/* /root/.cache/*
# Runtime permissions (non-root safe)
# Ensure runtime directory writable by tor user
RUN mkdir -p /run/tor && \
chown -R tor:tor /run/tor && \
chmod 770 /run/tor
# Non-root execution
# Switch to non-root user
USER tor
# Expose relay + diagnostics ports
EXPOSE 9001 9035 9036
# Expose network ports
# 9001: ORPort - Tor relay traffic (REQUIRED, PUBLIC)
# 9030: DirPort - Directory service (OPTIONAL, PUBLIC)
# 9035: Metrics - Prometheus endpoint (OPTIONAL, localhost recommended)
# 9036: Health - Status endpoint (OPTIONAL, localhost recommended)
EXPOSE 9001 9030
# Healthcheck - ensures Tor config remains valid
# Health check - validates Tor config every 10 minutes
HEALTHCHECK --interval=10m --timeout=15s --start-period=30s --retries=3 \
CMD tor --verify-config -f "$TOR_CONFIG" || exit 1
# Entrypoint through tini
# Use tini for signal handling, entrypoint for initialization
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"]
CMD ["tor", "-f", "/etc/tor/torrc"]
CMD ["tor", "-f", "/etc/tor/torrc"]

View File

@@ -37,6 +37,24 @@
---
## 🔒 Security Model
**Port Exposure Policy:**
- **9001** (ORPort) - Tor relay traffic - **PUBLIC**
- **9030** (DirPort) - Directory service - **PUBLIC**
- **9035** (Metrics) - Prometheus endpoint - **LOCALHOST ONLY** (127.0.0.1)
- **9036** (Health) - Health check API - **LOCALHOST ONLY** (127.0.0.1)
All monitoring and diagnostic services are bound to `127.0.0.1` by default. To expose externally:
```bash
# ⚠️ INSECURE - Only for testing/development
docker run -e DASHBOARD_BIND=0.0.0.0 ...
```
**Production recommendation**: Use reverse proxy with authentication for external monitoring access.
---
## ⚡ Quick Start
### System Requirements
@@ -52,10 +70,16 @@
**Supported Architectures:** AMD64 (x86_64) • ARM64 (aarch64)
### Network Security Notice
⚠️ **Port Exposure:**
- Only ports **9001** (ORPort) and **9030** (DirPort) should be publicly accessible
- Monitoring services (9035, 9036) are **localhost-only** by default
- Use `--network host` or explicit port mapping: `-p 9001:9001 -p 9030:9030`
### Deploy in 30 Seconds
**Step 1:** Create your relay configuration (or use our [example](examples/relay.conf)):
```bash
# Create config directory
mkdir -p ~/tor-relay && cd ~/tor-relay
@@ -69,7 +93,6 @@ nano relay.conf
```
**Step 2:** Run the relay:
```bash
docker run -d \
--name tor-relay \
@@ -82,7 +105,6 @@ docker run -d \
```
**Step 3:** Verify it's running:
```bash
# Check status
docker exec tor-relay status
@@ -513,7 +535,7 @@ Images are automatically rebuilt weekly to include security patches:
![GitHub Stars](https://img.shields.io/github/stars/r3bo0tbx1/tor-guard-relay?style=for-the-badge)
![GitHub Issues](https://img.shields.io/github/issues/r3bo0tbx1/tor-guard-relay?style=for-the-badge)
**Current Version:** v1.1
**Current Version:** v1.0.2
**Status:** Production Ready
**Last Build:** Weekly (Mondays 03:00 UTC)

View File

@@ -14,26 +14,248 @@ We actively support the following versions with security updates:
| Version | Supported | Status |
|----------|------------|--------|
| 1.0 | ✅ | Current stable release |
| 1.0.2 | ✅ | Current stable release |
| 1.0.1 | ✅ | Maintenance support |
| 1.0.0 | ⚠️ | Security patches only |
| < 1.0 | ❌ | Pre-release versions |
---
## 🔒 Network Security Model
### External Port Exposure
**CRITICAL: Only TWO ports should be exposed to the public internet:**
```
EXPOSED PORTS (Public):
9001/tcp → Tor ORPort (Onion Router Port)
9030/tcp → Tor DirPort (Directory Service Port)
```
**All other services MUST bind to localhost only (127.0.0.1)** for security:
```
INTERNAL SERVICES (Localhost Only):
127.0.0.1:9035 → Prometheus metrics endpoint
127.0.0.1:9036 → Health check API
127.0.0.1:9037 → Dashboard HTTP server
127.0.0.1:9038+ → Additional relay instances
```
### Network Architecture
This project follows a **two-tier port exposure model**:
#### 🌐 Public Ports (External Access Required)
- **9001** - ORPort (Tor relay traffic)
- Must be publicly accessible
- Firewall: Allow inbound TCP
- Required for relay operation
- **9030** - DirPort (Directory service)
- Should be publicly accessible
- Optional but recommended
- Reduces load on directory authorities
#### 🔒 Internal Ports (Localhost Only)
- **9035** - Metrics HTTP (Prometheus endpoint)
- Bound to 127.0.0.1 by default
- Access via: `docker exec` or localhost tunnel
- ⚠️ Never expose without authentication
- **9036** - Health Check (Status API)
- Bound to 127.0.0.1 by default
- For monitoring systems only
- ⚠️ Never expose without authentication
- **9037** - Dashboard HTTP (Web UI)
- Bound to 127.0.0.1 by default
- Access via: SSH tunnel or reverse proxy
- ⚠️ Never expose without authentication
### Port Policy Rationale
**Why this matters:**
-**Minimizes attack surface** - Only Tor protocol ports exposed
-**Prevents unauthorized access** - Metrics/dashboards remain private
-**Follows Tor best practices** - Standard relay configuration
-**Defense in depth** - Additional layer beyond firewall rules
**Security implications:**
- Exposed ORPort (9001): Required for Tor relay operation
- Exposed DirPort (9030): Optional but recommended for directory service
- Internal metrics (9035+): Protected from external access
- No other services should be externally accessible
### Port Exposure Best Practices
#### ✅ Secure Configuration
```bash
# Docker CLI - Secure port mapping
docker run -d \
--name tor-relay \
-p 9001:9001 \
-p 9030:9030 \
-p 127.0.0.1:9035:9035 \
-p 127.0.0.1:9036:9036 \
ghcr.io/r3bo0tbx1/onion-relay:latest
```
```yaml
# Docker Compose - Secure port mapping
services:
tor-relay:
ports:
- "9001:9001" # Public - ORPort
- "9030:9030" # Public - DirPort
- "127.0.0.1:9035:9035" # Localhost - Metrics
- "127.0.0.1:9036:9036" # Localhost - Health
```
#### ❌ Insecure Configuration (DO NOT USE)
```bash
# ❌ BAD - Exposes monitoring without auth
docker run -p 0.0.0.0:9035:9035 ...
# ❌ BAD - Exposes all internal services
docker run -p 9035:9035 -p 9036:9036 ...
# ⚠️ USE WITH CAUTION - Host network mode
docker run --network host ...
# Only use if you understand implications and have proper firewall rules
```
### External Monitoring Access
If you need external access to metrics/health endpoints, use one of these secure methods:
#### Option 1: Reverse Proxy with Authentication (Recommended)
```nginx
# Nginx with HTTP Basic Auth
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://127.0.0.1:9035;
}
location /health {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:9036;
}
}
```
#### Option 2: SSH Tunnel
```bash
# Forward remote metrics to local machine
ssh -L 9035:localhost:9035 user@relay-server
ssh -L 9036:localhost:9036 user@relay-server
# Access locally (no public exposure)
curl http://localhost:9035/metrics
curl http://localhost:9036/health
```
#### Option 3: VPN Access
- Deploy relay and monitoring in same VPN
- Access internal ports over encrypted VPN tunnel
- No public exposure required
- Recommended for multi-relay deployments
### Default Behavior Changes (v1.0.2)
Prior to v1.0.2, some tools defaulted to `0.0.0.0` (all interfaces). **As of v1.0.2:**
| Tool | Previous Default | New Default | Override |
|------|------------------|-------------|----------|
| dashboard | 0.0.0.0:8080 | 127.0.0.1:8080 | `DASHBOARD_BIND=0.0.0.0` |
| metrics-http | 0.0.0.0:9035 | 127.0.0.1:9035 | `METRICS_BIND=0.0.0.0` |
**Migration Note**: If you previously relied on external access without explicit configuration, you must now:
1. **Use environment variables** to bind to `0.0.0.0` (NOT recommended), OR
2. **Implement reverse proxy** with authentication (RECOMMENDED)
Example of override (only if you understand the security implications):
```bash
# NOT RECOMMENDED - Only use in trusted networks
docker run -d \
-e METRICS_BIND=0.0.0.0 \
-p 9035:9035 \
ghcr.io/r3bo0tbx1/onion-relay:latest
```
### Firewall Configuration
**Recommended firewall rules:**
```bash
# UFW (Ubuntu/Debian)
sudo ufw default deny incoming
sudo ufw allow 9001/tcp # ORPort
sudo ufw allow 9030/tcp # DirPort (optional)
sudo ufw enable
# iptables
sudo iptables -A INPUT -p tcp --dport 9001 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 9030 -j ACCEPT
sudo iptables -A INPUT -j DROP
# firewalld (RHEL/CentOS)
sudo firewall-cmd --permanent --add-port=9001/tcp
sudo firewall-cmd --permanent --add-port=9030/tcp
sudo firewall-cmd --reload
```
### Docker Network Mode
**Host networking (network_mode: host):**
- Used for dual-stack IPv4/IPv6 support
- Allows direct port binding without NAT
- Services still bind to 127.0.0.1 for internal access
- Container remains isolated (non-root user, dropped capabilities)
**Security measures when using host networking:**
- Non-root execution (runs as `tor` user)
- Capability restrictions (`--cap-drop ALL`)
- No new privileges (`--security-opt no-new-privileges:true`)
- Minimal Alpine base image
- Automatic permission healing
---
## Security Updates
- Security patches are released as soon as possible after discovery.
- Critical vulnerabilities are prioritized.
- Weekly automated builds include the latest Alpine and Tor security updates.
- Subscribe to [GitHub Releases](https://github.com/r3bo0tbx1/tor-guard-relay/releases) for notifications.
- Security patches are released as soon as possible after discovery
- Critical vulnerabilities are prioritized
- Weekly automated builds include the latest Alpine and Tor security updates
- Subscribe to [GitHub Releases](https://github.com/r3bo0tbx1/tor-guard-relay/releases) for notifications
### Automated Hardening
To reduce patch-lag risk, GitHub Actions automatically:
1. Pulls the latest Alpine base image.
2. Installs the latest Tor package.
3. Applies security patches.
4. Rebuilds multi-architecture images.
5. Publishes to GHCR.
1. Pulls the latest Alpine base image
2. Installs the latest Tor package
3. Applies security patches
4. Rebuilds multi-architecture images
5. Publishes to GHCR
These rebuilds include Alpine CVE patches and Tor security fixes without changing functionality.
@@ -47,36 +269,40 @@ These rebuilds include Alpine CVE patches and Tor security fixes without changin
**Email:** r3bo0tbx1@brokenbotnet.com
**Subject:** `[SECURITY] Tor Guard Relay <short summary>`
Please use my PGP [0xB3BD6196E1CFBFB4 🔑](https://keys.openpgp.org/vks/v1/by-fingerprint/33727F5377D296C320AF704AB3BD6196E1CFBFB4) to encrypt if your report contains sensitive technical details.
Please use my PGP key [0xB3BD6196E1CFBFB4 🔑](https://keys.openpgp.org/vks/v1/by-fingerprint/33727F5377D296C320AF704AB3BD6196E1CFBFB4) to encrypt if your report contains sensitive technical details.
### Information to Include
1. **Description** of the vulnerability.
2. **Steps to reproduce** the issue.
3. **Impact assessment** (who is affected, what's at risk).
4. **Suggested fix** (if you have one).
5. **Your contact information** for follow-up.
1. **Description** of the vulnerability
2. **Steps to reproduce** the issue
3. **Impact assessment** (who is affected, what's at risk)
4. **Suggested fix** (if you have one)
5. **Your contact information** for follow-up
### What to Expect
- **Acknowledgment:** within 48 hours
- **Initial assessment:** within 1 week
- **Status updates:** every 2 weeks until resolved
**Resolution timelines**
- **Acknowledgment:** within 48 hours
- **Initial assessment:** within 1 week
- **Status updates:** every 2 weeks until resolved
**Resolution timelines:**
| Severity | Response Time |
|-----------|----------------|
| Critical | 1 to 7 days |
| High | 1 to 4 weeks |
| Medium | 1 to 3 months |
| Critical | 1-7 days |
| High | 1-4 weeks |
| Medium | 1-3 months |
| Low | Next release cycle |
### Coordinated Disclosure
We follow responsible disclosure practices:
1. **Report received** → We acknowledge and investigate.
2. **Fix developed** → We create and test a patch.
3. **Coordinated release** → We agree on disclosure timing.
4. **Public disclosure** → We release the fix and advisory.
5. **Credit given** → We acknowledge the reporter (unless anonymity is requested).
1. **Report received** → We acknowledge and investigate
2. **Fix developed** → We create and test a patch
3. **Coordinated release** → We agree on disclosure timing
4. **Public disclosure** → We release the fix and advisory
5. **Credit given** → We acknowledge the reporter (unless anonymity is requested)
---
@@ -84,7 +310,31 @@ We follow responsible disclosure practices:
### For Relay Operators
#### Port Security Configuration
```bash
# Verify only required ports are exposed
docker ps --format "table {{.Names}}\t{{.Ports}}"
# Expected output should show ONLY:
# 0.0.0.0:9001->9001/tcp
# 0.0.0.0:9030->9030/tcp
# Check internal services bind to localhost
docker exec guard-relay netstat -tlnp | grep -E "9035|9036|9037"
# Should show 127.0.0.1:PORT only
# Test external accessibility (should fail for metrics)
curl -m 5 http://YOUR_PUBLIC_IP:9035/metrics
# Should timeout or be refused
# Test internal accessibility (should work from container)
docker exec guard-relay curl -s http://127.0.0.1:9035/metrics
# Should return Prometheus metrics
```
#### Configuration Security
```bash
# Secure your relay.conf file
chmod 600 /path/to/relay.conf
@@ -92,7 +342,7 @@ chown root:root /path/to/relay.conf
# Use read-only mounts
-v /path/to/relay.conf:/etc/tor/torrc:ro
````
```
#### Contact Information
@@ -107,16 +357,13 @@ ContactInfo your-email proof:uri-rsa abuse:abuse@example.com
#### Network Security
```bash
# Firewall rules (UFW example)
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 9001/tcp # ORPort
sudo ufw allow 22/tcp # SSH (be careful!)
sudo ufw enable
# Regular security updates
apt update && apt upgrade -y # Ubuntu/Debian
yum update -y # RHEL/CentOS
# Verify firewall rules
sudo ufw status numbered
sudo iptables -L -n -v
```
#### Monitoring
@@ -126,10 +373,13 @@ yum update -y # RHEL/CentOS
docker logs guard-relay 2>&1 | grep -iE "(error|warn|critical)"
# Scheduled health checks
0 */6 * * * docker exec guard-relay relay-status >> /var/log/relay-check.log
0 */6 * * * docker exec guard-relay status >> /var/log/relay-check.log
# Resource monitoring
docker stats guard-relay --no-stream
# Port accessibility audit
docker exec guard-relay net-check
```
---
@@ -138,17 +388,17 @@ docker stats guard-relay --no-stream
#### Code Security
* Never commit secrets or API keys.
* Use `.gitignore` for sensitive files.
* Review dependencies for vulnerabilities.
* Follow the principle of least privilege.
* Validate all user inputs.
* Never commit secrets or API keys
* Use `.gitignore` for sensitive files
* Review dependencies for vulnerabilities
* Follow the principle of least privilege
* Validate all user inputs
#### Docker Security
```dockerfile
# Always specify explicit base version
FROM alpine:edge # Pinned dynamically in CI for latest security patches
FROM alpine:3.22.2 # Pinned version for reproducibility
# Run as non-root user
USER tor
@@ -176,27 +426,26 @@ echo "relay.conf" >> .gitignore
### Host Network Mode
**What:** Container uses `--network host`
**What:** Container uses `--network host`
**Why:** Enables Tor dual-stack (IPv4 + IPv6) support
**Security Impact:**
* ✅ Container cannot access other containers
* ✅ Runs as non-root user (`tor`)
* ⚠️ Shares host network namespace
* ⚠️ Can bind to any host port
* ⚠️ Can bind to any host port (mitigated by localhost binding)
**Mitigations:**
* Drops unnecessary capabilities
* Uses `no-new-privileges:true`
* Only grants required capabilities
* Internal services bind to 127.0.0.1 only
* Relies on proper firewall configuration
### Volume Permissions
**What:** Persistent volumes store keys and state.
**Security Impact:** Keys live in `/var/lib/tor`; protect them from unauthorized access.
**What:** Persistent volumes store keys and state
**Security Impact:** Keys live in `/var/lib/tor`; protect from unauthorized access
**Mitigation:**
@@ -211,11 +460,10 @@ chown tor:tor /var/lib/tor
### Configuration Exposure
**What:** Configuration is mounted from the host.
**What:** Configuration is mounted from the host
**Impact:** May reveal bandwidth limits, ContactInfo, etc.
**Mitigation:**
* Use read-only mount (`:ro`)
* Set restrictive file permissions (600)
* Never commit configs
@@ -233,15 +481,31 @@ chown tor:tor /var/lib/tor
* ✅ Read-only configuration mount
* ✅ Automatic permission healing
* ✅ Configuration validation on startup
* ✅ Localhost-only binding for internal services
### Port Binding Security
**External (public) services:**
```
ORPort 9001 # Binds to 0.0.0.0:9001
ORPort [::]:9001 # Binds to [::]:9001 (IPv6)
DirPort 9030 # Binds to 0.0.0.0:9030
```
**Internal (localhost-only) services:**
```
metrics-http binds to 127.0.0.1:9035
health API binds to 127.0.0.1:9036
dashboard binds to 127.0.0.1:9037
```
### Weekly Security Updates
To ensure ongoing hardening, CI automatically:
1. Pulls latest Alpine base.
2. Installs updated Tor.
3. Applies available patches.
4. Rebuilds and republishes to GHCR.
1. Pulls latest Alpine base
2. Installs updated Tor
3. Applies available patches
4. Rebuilds and republishes to GHCR
Enable automatic updates in Cosmos:
@@ -257,28 +521,26 @@ Enable automatic updates in Cosmos:
### Tor Network Participation
Running a Tor relay is legal in most countries, but:
* ⚠️ Check local laws and ISP terms of service.
* ⚠️ Understand exit vs. guard relay differences.
* ⚠️ Keep contact information accurate.
* ⚠️ Check local laws and ISP terms of service
* ⚠️ Understand exit vs. guard relay differences
* ⚠️ Keep contact information accurate
**This project runs GUARD relays (not exit relays) by default.**
### Data Handling
* Tor relays do **not** log traffic content.
* Relay fingerprints are public.
* Contact information and bandwidth statistics are public.
* Tor relays do **not** log traffic content
* Relay fingerprints are public
* Contact information and bandwidth statistics are public
### Abuse Handling
If you receive abuse complaints:
1. Verify its actually your relay.
2. Review Tor Project [abuse response templates](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/).
3. Respond professionally.
4. Consider your legal position.
5. Join [tor-relays mailing list](https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays) for help.
1. Verify it's actually your relay
2. Review Tor Project [abuse response templates](https://community.torproject.org/relay/community-resources/eff-tor-legal-faq/)
3. Respond professionally
4. Consider your legal position
5. Join [tor-relays mailing list](https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-relays) for help
---
@@ -303,9 +565,65 @@ If you receive abuse complaints:
---
## Network Security Audit
### Quick Security Checklist
```bash
#!/bin/bash
# security-audit.sh - Quick security audit for Tor Guard Relay
echo "🔒 Tor Guard Relay Security Audit"
echo "=================================="
# Check exposed ports
echo ""
echo "1. Checking exposed ports..."
docker ps --format "table {{.Names}}\t{{.Ports}}" | grep guard-relay
# Check internal service bindings
echo ""
echo "2. Checking internal service bindings..."
docker exec guard-relay netstat -tlnp 2>/dev/null | grep -E "9035|9036|9037" || echo "No internal services detected"
# Test external accessibility
echo ""
echo "3. Testing external port accessibility..."
PUBLIC_IP=$(curl -s https://icanhazip.com)
timeout 5 nc -zv $PUBLIC_IP 9001 && echo "✅ ORPort 9001 accessible" || echo "❌ ORPort 9001 not accessible"
timeout 5 nc -zv $PUBLIC_IP 9030 && echo "✅ DirPort 9030 accessible" || echo "⚠️ DirPort 9030 not accessible"
# Test metrics should NOT be externally accessible
echo ""
echo "4. Testing metrics port (should NOT be accessible externally)..."
timeout 5 curl -s http://$PUBLIC_IP:9035/metrics && echo "❌ SECURITY ISSUE: Metrics exposed!" || echo "✅ Metrics properly secured"
# Check file permissions
echo ""
echo "5. Checking critical file permissions..."
docker exec guard-relay ls -la /var/lib/tor | grep -E "keys|fingerprint"
# Check user
echo ""
echo "6. Checking process user..."
docker exec guard-relay ps aux | grep tor | head -1
# Check capabilities
echo ""
echo "7. Checking container capabilities..."
docker inspect guard-relay --format='{{.HostConfig.CapDrop}}' | grep -q "ALL" && echo "✅ All capabilities dropped" || echo "⚠️ Capabilities not fully restricted"
echo ""
echo "=================================="
echo "Audit complete!"
```
---
## Hall of Fame 🏆
Security researchers who responsibly disclose vulnerabilities will be listed here:
*No vulnerabilities reported yet.*
---
@@ -320,4 +638,6 @@ Security researchers who responsibly disclose vulnerabilities will be listed her
**Thank you for helping keep this project secure!** 🔒🧅
---
---
*Last Updated: 2025-11-05 | Version: 1.0.2*

View File

@@ -1,9 +1,9 @@
#!/bin/bash
#!/bin/sh
# docker-entrypoint.sh - Tor Guard Relay initialization and process management
# Handles startup sequence: preflight checks → configuration validation → health monitoring →
# metrics exposure → main Tor process, with proper signal handling and background process management
set -euo pipefail
set -e
# Configuration
readonly TOR_CONFIG="${TOR_CONFIG:-/etc/tor/torrc}"
@@ -15,17 +15,44 @@ readonly ENABLE_METRICS="${ENABLE_METRICS:-false}"
readonly ENABLE_HEALTH_CHECK="${ENABLE_HEALTH_CHECK:-true}"
readonly ENABLE_NET_CHECK="${ENABLE_NET_CHECK:-false}"
# Signal handlers for clean shutdown
trap 'on_sigterm' SIGTERM SIGINT
# 🔒 NEW: Global PID tracking for cleanup
TOR_PID=""
METRICS_PID=""
HEALTH_PID=""
on_sigterm() {
# 🔒 NEW: Improved signal handler with comprehensive cleanup
trap 'cleanup_and_exit' SIGTERM SIGINT
cleanup_and_exit() {
echo ""
echo "🛑 Shutdown signal received. Gracefully stopping Tor..."
if [ -n "${TOR_PID:-}" ]; then
echo "🛑 Shutdown signal received. Stopping all services..."
# Kill background services first (reverse order of startup)
if [ -n "$HEALTH_PID" ] && kill -0 "$HEALTH_PID" 2>/dev/null; then
echo " Stopping health monitor (PID: $HEALTH_PID)..."
kill -TERM "$HEALTH_PID" 2>/dev/null || true
# Give it a moment to exit gracefully
sleep 1
# Force kill if still running
kill -9 "$HEALTH_PID" 2>/dev/null || true
fi
if [ -n "$METRICS_PID" ] && kill -0 "$METRICS_PID" 2>/dev/null; then
echo " Stopping metrics service (PID: $METRICS_PID)..."
kill -TERM "$METRICS_PID" 2>/dev/null || true
sleep 1
kill -9 "$METRICS_PID" 2>/dev/null || true
fi
# Finally, stop Tor relay
if [ -n "$TOR_PID" ] && kill -0 "$TOR_PID" 2>/dev/null; then
echo " Stopping Tor relay (PID: $TOR_PID)..."
kill -TERM "$TOR_PID" 2>/dev/null || true
# Wait for Tor to shut down gracefully (up to 30 seconds)
wait "$TOR_PID" 2>/dev/null || true
fi
echo "✅ Tor relay shut down cleanly."
echo "✅ All services stopped cleanly."
exit 0
}
@@ -109,13 +136,13 @@ validation_phase() {
echo "🔍 Phase 5: Preflight Diagnostics"
echo " 🌐 Checking basic network connectivity..."
if ping -c1 -W2 1.1.1.1 >/dev/null 2>&1; then
if ping -c1 -W2 ipv4.icanhazip.com >/dev/null 2>&1; then
echo " ✓ IPv4 connectivity OK"
else
echo " ⚠️ IPv4 connectivity unavailable"
fi
if ping6 -c1 -W2 ipv6.google.com >/dev/null 2>&1; then
if ping6 -c1 -W2 ipv6.icanhazip.com >/dev/null 2>&1; then
echo " ✓ IPv6 connectivity OK"
else
echo " ⚠️ IPv6 connectivity unavailable"
@@ -134,9 +161,6 @@ validation_phase() {
echo " ⏭️ Skipping extended network diagnostics (ENABLE_NET_CHECK=false)"
fi
# NOTE: Health check skipped here intentionally.
# Tor is not yet started at this stage.
# Health monitoring begins later in start_health_service().
echo ""
}
@@ -162,7 +186,7 @@ buildinfo_phase() {
echo ""
}
# Metrics service (background)
# 🔒 IMPROVED: Metrics service with PID tracking
start_metrics_service() {
if [ "$ENABLE_METRICS" != "true" ]; then
echo "📊 Phase 7: Metrics Service disabled (ENABLE_METRICS=false)"
@@ -177,13 +201,22 @@ start_metrics_service() {
return 0
fi
# Start metrics service and capture PID
metrics-http "$METRICS_PORT" &
METRICS_PID=$!
echo " ✓ Metrics service active on port $METRICS_PORT (PID: $METRICS_PID)"
# Verify process started successfully
sleep 1
if kill -0 "$METRICS_PID" 2>/dev/null; then
echo " ✓ Metrics service active on port $METRICS_PORT (PID: $METRICS_PID)"
else
echo " ⚠️ Metrics service failed to start"
METRICS_PID=""
fi
echo ""
}
# Health check service (background)
# 🔒 IMPROVED: Health check service with PID tracking
start_health_service() {
if [ "$ENABLE_HEALTH_CHECK" != "true" ]; then
echo "💚 Phase 8: Health Check Service disabled (ENABLE_HEALTH_CHECK=false)"
@@ -192,6 +225,8 @@ start_health_service() {
fi
echo "💚 Phase 8: Starting Health Check Service"
# Start health monitor in background and capture PID
(
while true; do
sleep 30
@@ -207,7 +242,15 @@ start_health_service() {
done
) &
HEALTH_PID=$!
echo " ✓ Health monitor active (PID: $HEALTH_PID)"
# Verify process started successfully
sleep 1
if kill -0 "$HEALTH_PID" 2>/dev/null; then
echo " ✓ Health monitor active (PID: $HEALTH_PID)"
else
echo " ⚠️ Health monitor failed to start"
HEALTH_PID=""
fi
echo ""
}
@@ -230,9 +273,27 @@ startup_message() {
echo ""
}
# Main Tor process
# 🔒 IMPROVED: Tor process launcher with PID tracking
run_tor() {
exec "$@"
# Start Tor in background so we can track its PID
"$@" &
TOR_PID=$!
echo " ✓ Tor relay started (PID: $TOR_PID)"
echo ""
# Wait for Tor process to complete
# This blocks until Tor exits or signal is received
wait "$TOR_PID"
# If we reach here, Tor exited on its own (not from signal)
TOR_EXIT_CODE=$?
echo ""
echo "🛑 Tor process exited with code: $TOR_EXIT_CODE"
# Cleanup background services
cleanup_and_exit
}
# Main execution flow
@@ -246,4 +307,4 @@ main() {
run_tor "$@"
}
main "$@"
main "$@"

View File

@@ -1,6 +1,6 @@
#!/bin/bash
# integration-check.sh - Master integration test runner for Tor Guard Relay
# Validates all tools are present, executable, and produce correct output formats
# integration-check.sh - Master integration test runner for Tor Guard Relay v1.0.2
# Validates all tools, port security, and configuration compliance
# Returns: 0 on success, 1 on failure; outputs emoji-based summary
set -euo pipefail
@@ -10,12 +10,14 @@ readonly CONTAINER="${CONTAINER:-guard-relay}"
readonly TOOLS_DIR="/usr/local/bin"
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly TIMESTAMP=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
readonly VERSION="1.0.2"
# State tracking
PASS_COUNT=0
FAIL_COUNT=0
WARN_COUNT=0
declare -a RESULTS=()
declare -a SECURITY_ISSUES=()
# Colors for terminal output (safe in Alpine)
readonly RED='\033[0;31m'
@@ -23,6 +25,7 @@ readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly MAGENTA='\033[0;35m'
readonly NC='\033[0m'
# Output functions
@@ -58,6 +61,11 @@ log_info() {
echo -e "${BLUE}${NC} $1"
}
log_security() {
echo -e "${MAGENTA}🔒${NC} $1"
SECURITY_ISSUES+=("$1")
}
# Test functions
test_file_exists() {
local path=$1
@@ -130,42 +138,6 @@ test_text_contains() {
fi
}
test_tool_output_format() {
local tool_path=$1
local tool_name=$2
local expected_format=$3
if [ ! -f "$tool_path" ]; then
log_fail "$tool_name not found"
return 1
fi
local output
output=$("$tool_path" 2>&1 || true)
case "$expected_format" in
json)
test_json_valid "$output" "$tool_name JSON"
;;
text)
if [ -n "$output" ]; then
log_pass "$tool_name produces text output"
else
log_fail "$tool_name produces empty output"
return 1
fi
;;
html)
if echo "$output" | grep -q "<!DOCTYPE\|<html"; then
log_pass "$tool_name produces HTML output"
else
log_fail "$tool_name does not produce HTML"
return 1
fi
;;
esac
}
# Phase 1: File Existence & Permissions
phase_1_files() {
log_section "Phase 1: File Existence & Permissions"
@@ -178,6 +150,8 @@ phase_1_files() {
test_file_exists "$TOOLS_DIR/metrics" "metrics"
test_file_exists "$TOOLS_DIR/metrics-http" "metrics-http"
test_file_exists "$TOOLS_DIR/dashboard" "dashboard"
test_file_exists "$TOOLS_DIR/setup" "setup"
test_file_exists "$TOOLS_DIR/net-check" "net-check"
# Check docker-entrypoint.sh
test_file_exists "$TOOLS_DIR/docker-entrypoint.sh" "docker-entrypoint.sh"
@@ -199,6 +173,8 @@ phase_2_permissions() {
test_file_executable "$TOOLS_DIR/metrics" "metrics"
test_file_executable "$TOOLS_DIR/metrics-http" "metrics-http"
test_file_executable "$TOOLS_DIR/dashboard" "dashboard"
test_file_executable "$TOOLS_DIR/setup" "setup"
test_file_executable "$TOOLS_DIR/net-check" "net-check"
test_file_executable "$TOOLS_DIR/docker-entrypoint.sh" "docker-entrypoint.sh"
}
@@ -206,7 +182,7 @@ phase_2_permissions() {
phase_3_syntax() {
log_section "Phase 3: Shell Syntax Validation"
for tool in status fingerprint view-logs health metrics metrics-http dashboard docker-entrypoint.sh; do
for tool in status fingerprint view-logs health metrics metrics-http dashboard setup net-check docker-entrypoint.sh; do
if [ -f "$TOOLS_DIR/$tool" ]; then
test_shell_syntax "$TOOLS_DIR/$tool" "$tool"
fi
@@ -215,6 +191,10 @@ phase_3_syntax() {
if [ -f "$SCRIPT_DIR/integration-check.sh" ]; then
test_shell_syntax "$SCRIPT_DIR/integration-check.sh" "integration-check.sh"
fi
if [ -f "$SCRIPT_DIR/relay-status.sh" ]; then
test_shell_syntax "$SCRIPT_DIR/relay-status.sh" "relay-status.sh"
fi
}
# Phase 4: Directory Structure
@@ -230,6 +210,14 @@ phase_4_directories() {
if [ -d "/var/lib/tor" ]; then
log_pass "Tor data directory exists: /var/lib/tor"
# Check permissions
local perms=$(stat -c "%a" /var/lib/tor 2>/dev/null || echo "unknown")
if [ "$perms" = "700" ] || [ "$perms" = "750" ]; then
log_pass "Tor data directory has secure permissions: $perms"
else
log_warn "Tor data directory permissions: $perms (should be 700 or 750)"
fi
else
log_fail "Tor data directory missing: /var/lib/tor"
fi
@@ -247,9 +235,82 @@ phase_4_directories() {
fi
}
# Phase 5: Output Format Validation (requires execution)
phase_5_output_formats() {
log_section "Phase 5: Output Format Validation"
# Phase 5: Port Security Validation (CRITICAL for v1.0.2)
phase_5_port_security() {
log_section "Phase 5: Port Security Validation"
log_info "Validating port exposure policy (9001/9030 only)..."
# Check if metrics-http binds to localhost only
if [ -f "$TOOLS_DIR/metrics-http" ]; then
local bind_check=$(grep -E "127\.0\.0\.1|localhost" "$TOOLS_DIR/metrics-http" 2>/dev/null || echo "")
if [ -n "$bind_check" ]; then
log_pass "metrics-http configured for localhost binding"
else
log_security "SECURITY: metrics-http may not be localhost-only"
log_fail "metrics-http localhost binding not confirmed"
fi
fi
# Check if dashboard binds to localhost only
if [ -f "$TOOLS_DIR/dashboard" ]; then
local bind_check=$(grep -E "127\.0\.0\.1|localhost" "$TOOLS_DIR/dashboard" 2>/dev/null || echo "")
if [ -n "$bind_check" ]; then
log_pass "dashboard configured for localhost binding"
else
log_warn "dashboard localhost binding not confirmed"
fi
fi
# Check torrc for proper port configuration (if exists)
if [ -f "/etc/tor/torrc" ]; then
log_info "Checking torrc port configuration..."
# Check for ORPort 9001
if grep -q "^ORPort 9001" /etc/tor/torrc 2>/dev/null; then
log_pass "ORPort 9001 configured correctly"
else
log_warn "ORPort 9001 not found in torrc"
fi
# Check for DirPort 9030
if grep -q "^DirPort 9030" /etc/tor/torrc 2>/dev/null; then
log_pass "DirPort 9030 configured correctly"
else
log_info "DirPort 9030 not configured (optional)"
fi
# Check that SocksPort is disabled
if grep -q "^SocksPort 0" /etc/tor/torrc 2>/dev/null; then
log_pass "SocksPort properly disabled"
else
log_warn "SocksPort setting not confirmed"
fi
fi
# Check for any references to dangerous port exposure
log_info "Scanning for improper port exposure patterns..."
local dangerous_patterns=0
for tool in "$TOOLS_DIR"/*; do
if [ -f "$tool" ] && [ -x "$tool" ]; then
# Look for 0.0.0.0 bindings on non-Tor ports
if grep -qE "0\.0\.0\.0:903[5-9]|0\.0\.0\.0:904[0-9]" "$tool" 2>/dev/null; then
log_security "SECURITY: Found potential 0.0.0.0 binding in $(basename $tool)"
log_fail "$(basename $tool) may expose internal ports"
((dangerous_patterns++))
fi
fi
done
if [ $dangerous_patterns -eq 0 ]; then
log_pass "No dangerous port exposure patterns detected"
fi
}
# Phase 6: Output Format Validation
phase_6_output_formats() {
log_section "Phase 6: Output Format Validation"
# health (JSON)
if [ -f "$TOOLS_DIR/health" ]; then
@@ -302,11 +363,22 @@ phase_5_output_formats() {
log_warn "dashboard HTML validation not fully checked"
fi
fi
# net-check (text with emoji)
if [ -f "$TOOLS_DIR/net-check" ]; then
log_info "Testing net-check output format..."
NETCHECK_OUT=$("$TOOLS_DIR/net-check" 2>&1 || echo "Network check")
if echo "$NETCHECK_OUT" | grep -qE "🌐|Network|Diagnostics"; then
log_pass "net-check produces expected output"
else
log_warn "net-check output not fully validated"
fi
fi
}
# Phase 6: Environment Variables
phase_6_environment() {
log_section "Phase 6: Environment Variables"
# Phase 7: Environment Variables
phase_7_environment() {
log_section "Phase 7: Environment Variables"
if [ -n "${TOR_DATA_DIR:-}" ]; then
log_pass "TOR_DATA_DIR is set: $TOR_DATA_DIR"
@@ -327,6 +399,52 @@ phase_6_environment() {
log_fail "PATH missing /usr/local/bin: $PATH"
fi
fi
# Check for metrics-related env vars
if [ -n "${ENABLE_METRICS:-}" ]; then
log_info "ENABLE_METRICS is set: $ENABLE_METRICS"
fi
if [ -n "${METRICS_PORT:-}" ]; then
log_info "METRICS_PORT is set: $METRICS_PORT"
# Validate it's in the proper range
if [ "$METRICS_PORT" -ge 9035 ] && [ "$METRICS_PORT" -le 9099 ]; then
log_pass "METRICS_PORT in valid range: $METRICS_PORT"
else
log_warn "METRICS_PORT outside recommended range: $METRICS_PORT"
fi
fi
}
# Phase 8: Version Validation
phase_8_version() {
log_section "Phase 8: Version Validation"
log_info "Integration check version: $VERSION"
# Check if build-info.txt exists and contains version
if [ -f "/build-info.txt" ]; then
local build_version=$(grep "Version:" /build-info.txt 2>/dev/null | cut -d: -f2 | tr -d ' ' || echo "unknown")
log_info "Build version: $build_version"
if [ "$build_version" = "$VERSION" ] || [ "$build_version" = "v$VERSION" ]; then
log_pass "Build version matches integration check version"
else
log_warn "Build version mismatch (expected: $VERSION, found: $build_version)"
fi
else
log_info "No build-info.txt found (may be normal in development)"
fi
# Check relay-status.sh version if available
if [ -f "$SCRIPT_DIR/relay-status.sh" ]; then
local script_version=$(grep "^readonly VERSION=" "$SCRIPT_DIR/relay-status.sh" 2>/dev/null | cut -d'"' -f2 || echo "unknown")
if [ "$script_version" = "$VERSION" ]; then
log_pass "relay-status.sh version matches: $VERSION"
else
log_warn "relay-status.sh version mismatch (expected: $VERSION, found: $script_version)"
fi
fi
}
# Generate Summary Report
@@ -334,30 +452,44 @@ generate_summary() {
local total=$((PASS_COUNT + FAIL_COUNT + WARN_COUNT))
echo ""
log_header "🧅 Integration Test Summary"
log_header "🧅 Integration Test Summary (v$VERSION)"
echo ""
echo "Total Tests: $total"
echo -e "${GREEN}Passed: ${PASS_COUNT}${NC}"
echo -e "${GREEN}Passed: ${PASS_COUNT}${NC}"
if [ $WARN_COUNT -gt 0 ]; then
echo -e "${YELLOW}Warnings: ${WARN_COUNT}${NC}"
echo -e "${YELLOW}Warnings: ${WARN_COUNT}${NC}"
fi
if [ $FAIL_COUNT -gt 0 ]; then
echo -e "${RED}Failed: ${FAIL_COUNT}${NC}"
echo -e "${RED}Failed: ${FAIL_COUNT}${NC}"
fi
# Security issues summary
if [ ${#SECURITY_ISSUES[@]} -gt 0 ]; then
echo ""
echo -e "${MAGENTA}🔒 Security Issues Detected: ${#SECURITY_ISSUES[@]}${NC}"
for issue in "${SECURITY_ISSUES[@]}"; do
echo -e " ${MAGENTA}${NC} $issue"
done
fi
echo ""
echo "Results:"
echo "Detailed Results:"
for result in "${RESULTS[@]}"; do
echo " $result"
done
echo ""
if [ $FAIL_COUNT -eq 0 ]; then
if [ $FAIL_COUNT -eq 0 ] && [ ${#SECURITY_ISSUES[@]} -eq 0 ]; then
echo -e "${GREEN}✅ All integration checks passed!${NC}"
echo -e "${GREEN}✅ No security issues detected!${NC}"
return 0
elif [ $FAIL_COUNT -eq 0 ] && [ ${#SECURITY_ISSUES[@]} -gt 0 ]; then
echo -e "${YELLOW}⚠️ Integration checks passed with security warnings.${NC}"
echo -e "${YELLOW}⚠️ Please review security issues above.${NC}"
return 0
else
echo -e "${RED}❌ Some integration checks failed.${NC}"
@@ -367,9 +499,10 @@ generate_summary() {
# Main execution
main() {
log_header "🧅 Tor Guard Relay Integration Check v1.0"
log_header "🧅 Tor Guard Relay Integration Check v$VERSION"
log_info "Timestamp: $TIMESTAMP"
log_info "Container: $CONTAINER"
log_info "Target Release: v1.0.2"
echo ""
@@ -377,8 +510,10 @@ main() {
phase_2_permissions
phase_3_syntax
phase_4_directories
phase_5_output_formats
phase_6_environment
phase_5_port_security
phase_6_output_formats
phase_7_environment
phase_8_version
echo ""
generate_summary

View File

@@ -1,6 +1,7 @@
#!/bin/bash
#
# relay-status.sh — Tor relay/bridge status checker
# relay-status.sh — Tor relay/bridge status checker with security validation
# Version: 1.0.2
# Automatically detects Tor containers or uses specified container name
#
@@ -10,6 +11,7 @@ set -euo pipefail
CONTAINER="${1:-}" # Accept container name as first argument
readonly FINGERPRINT_PATH="/var/lib/tor/fingerprint"
readonly TORRC_PATH="/etc/tor/torrc"
readonly VERSION="1.0.2"
# Colors for output
readonly RED='\033[0;31m'
@@ -103,6 +105,70 @@ check_container() {
if [[ -n "${image}" ]]; then
echo -e " ${BLUE}Image:${NC} ${image}"
fi
# Check build info if available
local build_info
build_info=$(sudo docker exec "${CONTAINER}" cat /build-info.txt 2>/dev/null || echo "")
if [[ -n "${build_info}" ]]; then
echo -e " ${BLUE}Build:${NC}"
echo "${build_info}" | sed 's/^/ /'
fi
}
# Validate port security configuration
check_port_security() {
print_section "Port Security Validation"
# Check exposed ports
local exposed_ports
exposed_ports=$(sudo docker port "${CONTAINER}" 2>/dev/null || echo "")
if [[ -n "${exposed_ports}" ]]; then
echo -e " ${BLUE}Exposed ports:${NC}"
echo "${exposed_ports}" | sed 's/^/ /'
# Validate only 9001 and 9030 are exposed
if echo "${exposed_ports}" | grep -qE "^9001/tcp"; then
print_success "ORPort 9001 properly exposed"
else
print_warning "ORPort 9001 not exposed (may be using host network)"
fi
if echo "${exposed_ports}" | grep -qE "^9030/tcp"; then
print_success "DirPort 9030 properly exposed"
fi
# Check for improperly exposed internal ports
if echo "${exposed_ports}" | grep -qE "^903[5-9]/tcp"; then
print_error "SECURITY ISSUE: Internal metrics port exposed externally!"
echo -e " ${RED}Fix: Ensure metrics bind to 127.0.0.1 only${NC}"
fi
else
print_info "Using host network mode - checking port bindings..."
fi
# Check internal service bindings
local internal_bindings
internal_bindings=$(sudo docker exec "${CONTAINER}" netstat -tlnp 2>/dev/null | grep -E "9035|9036|9037" || echo "")
if [[ -n "${internal_bindings}" ]]; then
echo -e "\n ${BLUE}Internal services:${NC}"
# Validate localhost-only bindings
while IFS= read -r line; do
if echo "${line}" | grep -q "127.0.0.1"; then
local port
port=$(echo "${line}" | awk '{print $4}' | cut -d':' -f2)
print_success "Port ${port} properly bound to localhost"
else
local port
port=$(echo "${line}" | awk '{print $4}' | cut -d':' -f2)
print_error "SECURITY ISSUE: Port ${port} not bound to localhost!"
fi
done <<< "${internal_bindings}"
else
print_info "No internal service ports detected"
fi
}
# Display recent logs
@@ -177,6 +243,15 @@ show_orport() {
if [[ -n "${orport_config}" ]]; then
echo "${orport_config}" | sed 's/^/ /'
# Validate port numbers
if echo "${orport_config}" | grep -q "ORPort 9001"; then
print_success "ORPort configured correctly (9001)"
fi
if echo "${orport_config}" | grep -q "DirPort 9030"; then
print_success "DirPort configured correctly (9030)"
fi
else
print_warning "No ORPort configuration found"
fi
@@ -191,6 +266,13 @@ show_relay_info() {
if [[ -n "${relay_info}" ]]; then
echo "${relay_info}" | sed 's/^/ /'
# Validate relay type
if echo "${relay_info}" | grep -q "ExitRelay 0"; then
print_success "Configured as guard/middle relay (not exit)"
elif echo "${relay_info}" | grep -q "ExitRelay 1"; then
print_warning "Configured as EXIT relay (higher legal risk)"
fi
else
print_warning "No relay information found in config"
fi
@@ -224,10 +306,37 @@ show_resources() {
fi
}
# Show network diagnostics
show_network_diagnostics() {
print_section "Network Diagnostics"
# Check if net-check tool is available
if sudo docker exec "${CONTAINER}" command -v net-check &>/dev/null; then
print_info "Running comprehensive network check..."
sudo docker exec "${CONTAINER}" net-check 2>&1 | sed 's/^/ /'
else
print_info "Basic network connectivity check..."
# IPv4 check
if sudo docker exec "${CONTAINER}" curl -4 -s --max-time 5 https://icanhazip.com &>/dev/null; then
print_success "IPv4 connectivity OK"
else
print_warning "IPv4 connectivity issues"
fi
# IPv6 check
if sudo docker exec "${CONTAINER}" curl -6 -s --max-time 5 https://icanhazip.com &>/dev/null; then
print_success "IPv6 connectivity OK"
else
print_info "IPv6 not available or configured"
fi
fi
}
# Show quick help
show_help() {
cat << EOF
${BLUE}Tor Relay Status Checker${NC}
${BLUE}Tor Relay Status Checker v${VERSION}${NC}
Usage: $0 [container-name]
@@ -242,10 +351,23 @@ Examples:
Options:
-h, --help Show this help message
-v, --version Show version information
Security Checks:
- Port exposure validation (9001/9030 only)
- Internal service binding verification (127.0.0.1)
- Bootstrap and reachability status
- Error detection and reporting
EOF
}
# Show version
show_version() {
echo "relay-status.sh version ${VERSION}"
echo "Part of Tor Guard Relay v1.0.2"
}
# Main execution
main() {
# Check for help flag
@@ -254,14 +376,21 @@ main() {
exit 0
fi
# Check for version flag
if [[ "${1:-}" =~ ^(-v|--version)$ ]]; then
show_version
exit 0
fi
# Detect container if not specified
if [[ -z "${CONTAINER}" ]]; then
detect_tor_container
fi
print_header "🧅 Tor Relay Status Check: ${CONTAINER}"
print_header "🧅 Tor Relay Status Check: ${CONTAINER} (v${VERSION})"
check_container
check_port_security
show_relay_info
show_logs
show_bootstrap
@@ -270,11 +399,13 @@ main() {
show_orport
check_errors
show_resources
show_network_diagnostics
echo
print_header "✅ Status Check Complete"
echo
print_info "For live monitoring, use: sudo docker logs -f ${CONTAINER}"
print_info "For detailed diagnostics, use: sudo docker exec ${CONTAINER} status"
echo
}

View File

@@ -5,12 +5,22 @@
set -e
# Configuration
VERSION="1.1.0"
VERSION="1.1.1"
DASHBOARD_PORT="${DASHBOARD_PORT:-8080}"
DASHBOARD_BIND="${DASHBOARD_BIND:-0.0.0.0}"
DASHBOARD_BIND="${DASHBOARD_BIND:-127.0.0.1}" # ⚠️ CHANGED: Secure default
ENABLE_DASHBOARD="${ENABLE_DASHBOARD:-true}"
REFRESH_INTERVAL="${REFRESH_INTERVAL:-10}"
MULTI_RELAY="${MULTI_RELAY:-false}"
MAX_CONNECTIONS="${MAX_CONNECTIONS:-5}" # 🔒 NEW: Rate limiting
# Trap for clean exit
trap 'cleanup' INT TERM
cleanup() {
echo ""
echo "🛑 Dashboard shutting down..."
exit 0
}
# Parse arguments
for arg in "$@"; do
@@ -25,17 +35,26 @@ USAGE:
OPTIONS:
--port PORT Dashboard port (default: 8080)
--bind ADDR Bind address (default: 0.0.0.0)
--bind ADDR Bind address (default: 127.0.0.1)
--refresh SEC Auto-refresh interval (default: 10)
--multi Enable multi-relay support
--help, -h Show this help message
ENVIRONMENT VARIABLES:
DASHBOARD_PORT Port to listen on
DASHBOARD_BIND Address to bind
DASHBOARD_BIND Address to bind (default: 127.0.0.1)
ENABLE_DASHBOARD Enable dashboard (true/false)
REFRESH_INTERVAL Auto-refresh in seconds
MULTI_RELAY Multi-relay mode (true/false)
MAX_CONNECTIONS Max concurrent connections (default: 5)
⚠️ SECURITY NOTICE:
Default binding is 127.0.0.1 (localhost only).
To expose externally, explicitly set:
DASHBOARD_BIND=0.0.0.0
⚠️ WARNING: External exposure without authentication is NOT recommended!
Use a reverse proxy (nginx/caddy) with authentication for production.
FEATURES:
• Real-time relay status monitoring
@@ -53,6 +72,13 @@ ENDPOINTS:
http://localhost:8080/api/logs Recent logs
DOCKER INTEGRATION:
# For localhost access only (secure):
ports:
- "127.0.0.1:8080:8080"
# For external access (use with caution):
environment:
- DASHBOARD_BIND=0.0.0.0
ports:
- "8080:8080"
@@ -93,6 +119,14 @@ if [ "$ENABLE_DASHBOARD" != "true" ]; then
exit 0
fi
# Security warning for external binding
if [ "$DASHBOARD_BIND" = "0.0.0.0" ]; then
echo "⚠️ WARNING: Dashboard is bound to 0.0.0.0 (all interfaces)"
echo "⚠️ This exposes the dashboard without authentication!"
echo "⚠️ Consider using a reverse proxy with authentication."
echo ""
fi
# Check for netcat
if ! command -v nc > /dev/null 2>&1; then
echo "❌ Error: netcat (nc) is required"
@@ -100,6 +134,9 @@ if ! command -v nc > /dev/null 2>&1; then
exit 1
fi
# Connection counter (simple rate limiting)
CONNECTION_COUNT=0
# Function to generate dashboard HTML
generate_dashboard() {
# Get current status
@@ -531,4 +568,81 @@ handle_api() {
;;
"/api/metrics")
CONTENT=$(/usr/local/bin/metrics 2>/dev/null || echo "# Error generating metrics
CONTENT=$(/usr/local/bin/metrics 2>/dev/null || echo "# Error generating metrics")
echo "HTTP/1.1 200 OK"
echo "Content-Type: text/plain"
echo "Cache-Control: no-cache"
echo "Connection: close"
echo ""
echo "$CONTENT"
;;
"/api/logs")
CONTENT=$(/usr/local/bin/view-logs --json 2>/dev/null || echo '{"error":"Failed to get logs"}')
echo "HTTP/1.1 200 OK"
echo "Content-Type: application/json"
echo "Cache-Control: no-cache"
echo "Connection: close"
echo ""
echo "$CONTENT"
;;
"/")
HTML=$(generate_dashboard)
CONTENT_LENGTH=$(echo -n "$HTML" | wc -c)
echo "HTTP/1.1 200 OK"
echo "Content-Type: text/html"
echo "Content-Length: $CONTENT_LENGTH"
echo "Cache-Control: no-cache"
echo "Connection: close"
echo ""
echo "$HTML"
;;
*)
ERROR_MSG="404 - Not Found"
CONTENT_LENGTH=$(echo -n "$ERROR_MSG" | wc -c)
echo "HTTP/1.1 404 Not Found"
echo "Content-Type: text/plain"
echo "Content-Length: $CONTENT_LENGTH"
echo "Connection: close"
echo ""
echo "$ERROR_MSG"
;;
esac
}
# Start server
echo "🎨 Starting Tor Relay Dashboard v${VERSION}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🌐 Listening on: http://$DASHBOARD_BIND:$DASHBOARD_PORT"
echo "🔒 Max connections: $MAX_CONNECTIONS"
echo "💡 Press Ctrl+C to stop"
echo ""
# Main server loop with basic connection limiting
while true; do
# Simple connection limiting
if [ "$CONNECTION_COUNT" -ge "$MAX_CONNECTIONS" ]; then
sleep 1
CONNECTION_COUNT=0
fi
# Wait for connection and parse request
REQUEST=$(echo "" | nc -l -p "$DASHBOARD_PORT" -s "$DASHBOARD_BIND" -w 5 2>/dev/null | head -1)
if [ -n "$REQUEST" ]; then
CONNECTION_COUNT=$((CONNECTION_COUNT + 1))
# Extract path from request
REQUEST_PATH=$(echo "$REQUEST" | awk '{print $2}')
# Log request
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $REQUEST"
# Generate and send response in background to avoid blocking
(handle_api "$REQUEST_PATH" | nc -l -p "$DASHBOARD_PORT" -s "$DASHBOARD_BIND" -w 1 > /dev/null 2>&1) &
fi
done

View File

@@ -5,12 +5,22 @@
set -e
# Configuration
VERSION="1.1.0"
VERSION="1.1.1"
METRICS_PORT="${METRICS_PORT:-9052}"
METRICS_BIND="${METRICS_BIND:-0.0.0.0}"
METRICS_BIND="${METRICS_BIND:-127.0.0.1}" # ⚠️ CHANGED: Secure default
METRICS_PATH="${METRICS_PATH:-/metrics}"
ENABLE_METRICS="${ENABLE_METRICS:-true}"
RESPONSE_TIMEOUT="${RESPONSE_TIMEOUT:-10}"
MAX_CONNECTIONS="${MAX_CONNECTIONS:-10}" # 🔒 NEW: Rate limiting
# Trap for clean exit
trap 'cleanup' INT TERM
cleanup() {
echo ""
echo "🛑 Metrics HTTP server shutting down..."
exit 0
}
# Parse arguments
for arg in "$@"; do
@@ -25,17 +35,30 @@ USAGE:
OPTIONS:
--port PORT Listen port (default: 9052)
--bind ADDR Bind address (default: 0.0.0.0)
--bind ADDR Bind address (default: 127.0.0.1)
--path PATH Metrics path (default: /metrics)
--daemon Run as daemon
--help, -h Show this help message
ENVIRONMENT VARIABLES:
METRICS_PORT Port to listen on (default: 9052)
METRICS_BIND Address to bind (default: 0.0.0.0)
METRICS_BIND Address to bind (default: 127.0.0.1)
METRICS_PATH URL path for metrics (default: /metrics)
ENABLE_METRICS Enable metrics server (true/false)
RESPONSE_TIMEOUT Response timeout in seconds
MAX_CONNECTIONS Max concurrent connections (default: 10)
⚠️ SECURITY NOTICE:
Default binding is 127.0.0.1 (localhost only).
To expose externally for Prometheus scraping, explicitly set:
METRICS_BIND=0.0.0.0
⚠️ WARNING: Metrics may contain sensitive relay information!
Recommendations for production:
1. Use network-level access controls (firewall rules)
2. Deploy Prometheus in same network/VPN
3. Use TLS termination proxy (nginx with client certs)
4. Never expose directly to public internet
ENDPOINTS:
http://localhost:9052/metrics Prometheus metrics
@@ -51,7 +74,18 @@ PROMETHEUS CONFIG:
scrape_interval: 30s
DOCKER INTEGRATION:
# Expose in docker-compose.yml
# For localhost access only (secure):
ports:
- "127.0.0.1:9052:9052"
# For Prometheus in same Docker network:
networks:
- monitoring
# No port exposure needed!
# For external Prometheus (use with caution):
environment:
- METRICS_BIND=0.0.0.0
ports:
- "9052:9052"
@@ -92,6 +126,14 @@ if [ "$ENABLE_METRICS" != "true" ]; then
exit 0
fi
# Security warning for external binding
if [ "$METRICS_BIND" = "0.0.0.0" ]; then
echo "⚠️ WARNING: Metrics server is bound to 0.0.0.0 (all interfaces)"
echo "⚠️ Relay metrics may contain sensitive information!"
echo "⚠️ Ensure proper firewall rules or use a secure network."
echo ""
fi
# Check for netcat
if ! command -v nc > /dev/null 2>&1; then
echo "❌ Error: netcat (nc) is required but not installed"
@@ -99,6 +141,10 @@ if ! command -v nc > /dev/null 2>&1; then
exit 1
fi
# Connection counter for basic rate limiting
CONNECTION_COUNT=0
LAST_RESET=$(date +%s)
# Function to generate HTTP response
generate_response() {
REQUEST_PATH="$1"
@@ -115,6 +161,7 @@ Content-Type: text/plain; version=0.0.4
Content-Length: $CONTENT_LENGTH
Cache-Control: no-cache
Connection: close
X-Content-Type-Options: nosniff
$METRICS_OUTPUT
EOF
@@ -142,6 +189,8 @@ EOF
<html>
<head>
<title>Tor Relay Metrics</title>
<meta charset=\"utf-8\">
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">
<style>
body { font-family: sans-serif; margin: 40px; background: #f5f5f5; }
h1 { color: #7d4698; }
@@ -149,12 +198,17 @@ EOF
.endpoint { background: #f0f0f0; padding: 10px; margin: 10px 0; border-radius: 4px; }
a { color: #7d4698; text-decoration: none; }
a:hover { text-decoration: underline; }
.ok { color: green; }
.loading { color: orange; }
.warning { background: #fff3cd; border-left: 4px solid #ffc107; padding: 15px; margin: 20px 0; }
</style>
</head>
<body>
<h1>🧅 Tor Relay Metrics Server</h1>
<div class=\"warning\">
<strong>⚠️ Security Notice:</strong> This server exposes relay metrics.
Ensure it's only accessible from trusted networks (Prometheus, monitoring systems).
</div>
<div class=\"status\">
<h2>Available Endpoints:</h2>
<div class=\"endpoint\">
@@ -167,11 +221,25 @@ EOF
🏠 <a href=\"/\">/</a> - This status page
</div>
</div>
<div class=\"status\">
<h2>Configuration:</h2>
<p>Port: $METRICS_PORT</p>
<p>Bind: $METRICS_BIND</p>
<p>Version: $VERSION</p>
<p><strong>Bind Address:</strong> $METRICS_BIND</p>
<p><strong>Port:</strong> $METRICS_PORT</p>
<p><strong>Version:</strong> $VERSION</p>
<p><strong>Rate Limit:</strong> $MAX_CONNECTIONS connections/window</p>
</div>
<div class=\"status\">
<h2>Integration:</h2>
<p>Add to your <code>prometheus.yml</code>:</p>
<pre style=\"background: #f0f0f0; padding: 15px; border-radius: 4px; overflow-x: auto;\">
scrape_configs:
- job_name: 'tor-relay'
static_configs:
- targets: ['$METRICS_BIND:$METRICS_PORT']
metrics_path: '$METRICS_PATH'
scrape_interval: 30s</pre>
</div>
</body>
</html>"
@@ -180,7 +248,7 @@ EOF
cat << EOF
HTTP/1.1 200 OK
Content-Type: text/html
Content-Type: text/html; charset=utf-8
Content-Length: $CONTENT_LENGTH
Cache-Control: no-cache
Connection: close
@@ -206,46 +274,43 @@ EOF
esac
}
# Signal handler for clean shutdown
cleanup() {
echo ""
echo "🛑 Shutting down metrics HTTP server..."
exit 0
}
trap cleanup INT TERM
# Start server
echo "📊 Starting Tor Relay Metrics HTTP Server v${VERSION}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🌐 Listening on: http://$METRICS_BIND:$METRICS_PORT"
echo "📍 Metrics path: $METRICS_PATH"
echo "🔒 Max connections: $MAX_CONNECTIONS/window"
echo "💡 Press Ctrl+C to stop"
echo ""
# Main server loop
if [ "$DAEMON_MODE" = "true" ]; then
# Run in background
while true; do
echo -e "$(generate_response "$METRICS_PATH")" | nc -l -p "$METRICS_PORT" -w "$RESPONSE_TIMEOUT" > /dev/null 2>&1 &
wait
done &
echo "✅ Server running in daemon mode (PID: $!)"
else
# Run in foreground
while true; do
# Wait for connection and parse request
REQUEST=$(echo -e "HTTP/1.1 200 OK\r\n\r\n" | nc -l -p "$METRICS_PORT" -w "$RESPONSE_TIMEOUT" 2>/dev/null | head -1)
# Main server loop with connection limiting
while true; do
# Reset counter every 60 seconds
CURRENT_TIME=$(date +%s)
if [ $((CURRENT_TIME - LAST_RESET)) -ge 60 ]; then
CONNECTION_COUNT=0
LAST_RESET=$CURRENT_TIME
fi
# Basic rate limiting
if [ "$CONNECTION_COUNT" -ge "$MAX_CONNECTIONS" ]; then
sleep 1
continue
fi
# Wait for connection and parse request
REQUEST=$(echo "" | nc -l -p "$METRICS_PORT" -s "$METRICS_BIND" -w "$RESPONSE_TIMEOUT" 2>/dev/null | head -1)
if [ -n "$REQUEST" ]; then
CONNECTION_COUNT=$((CONNECTION_COUNT + 1))
if [ -n "$REQUEST" ]; then
# Extract path from request
REQUEST_PATH=$(echo "$REQUEST" | awk '{print $2}')
# Log request
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $REQUEST"
# Generate and send response
generate_response "$REQUEST_PATH" | nc -l -p "$METRICS_PORT" -w 1 > /dev/null 2>&1 &
fi
done
fi
# Extract path from request
REQUEST_PATH=$(echo "$REQUEST" | awk '{print $2}')
# Log request (without sensitive info)
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $REQUEST_PATH ($CONNECTION_COUNT/$MAX_CONNECTIONS)"
# Generate and send response in background
(generate_response "$REQUEST_PATH" | nc -l -p "$METRICS_PORT" -s "$METRICS_BIND" -w 1 > /dev/null 2>&1) &
fi
done

View File

@@ -5,7 +5,7 @@
set -e
# Configuration
VERSION="1.1.0"
VERSION="1.1.1"
CONFIG_FILE="${CONFIG_FILE:-/etc/tor/torrc}"
RELAY_TYPE="${RELAY_TYPE:-guard}"
AUTO_MODE="${AUTO_MODE:-false}"
@@ -14,6 +14,7 @@ DEFAULT_CONTACT="${DEFAULT_CONTACT:-admin@example.com}"
DEFAULT_ORPORT="${DEFAULT_ORPORT:-9001}"
DEFAULT_DIRPORT="${DEFAULT_DIRPORT:-9030}"
DEFAULT_BANDWIDTH="${DEFAULT_BANDWIDTH:-1024}"
CREATE_BACKUP="${CREATE_BACKUP:-true}" # 🔒 NEW: Backup control
# Colors for terminal output
RED='\033[0;31m'
@@ -23,6 +24,15 @@ BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# Trap for clean exit
trap 'cleanup' INT TERM
cleanup() {
echo ""
echo -e "${YELLOW}Setup cancelled by user${NC}"
exit 130
}
# Parse arguments
for arg in "$@"; do
case "$arg" in
@@ -38,6 +48,7 @@ OPTIONS:
--auto Use defaults for all prompts
--config FILE Config file path (default: /etc/tor/torrc)
--type TYPE Relay type: guard|exit|bridge
--no-backup Skip backup creation (not recommended)
--help, -h Show this help message
ENVIRONMENT VARIABLES:
@@ -49,12 +60,19 @@ ENVIRONMENT VARIABLES:
DEFAULT_DIRPORT Default DirPort
DEFAULT_BANDWIDTH Default bandwidth in KB/s
AUTO_MODE Skip prompts and use defaults
CREATE_BACKUP Create backup before overwriting (default: true)
RELAY TYPES:
guard Middle/Guard relay (recommended for beginners)
exit Exit relay (requires careful consideration)
bridge Bridge relay (helps censored users)
SAFETY FEATURES:
🔒 Automatic backup creation before overwriting existing config
🔒 Backup stored as: [config].backup.[timestamp]
🔒 Validation before writing
🔒 Safe cancellation with Ctrl+C
WIZARD STEPS:
1. Relay nickname selection
2. Contact information
@@ -67,6 +85,7 @@ EXAMPLES:
setup # Interactive wizard
setup --auto # Auto-configure with defaults
setup --type bridge # Configure as bridge relay
setup --no-backup # Skip backup (not recommended)
OUTPUT:
Creates a complete torrc configuration file ready
@@ -87,6 +106,7 @@ EOF
RELAY_TYPE="$1"
shift
;;
--no-backup) CREATE_BACKUP="false" ;;
-*)
echo "❌ Unknown option: $arg"
echo "💡 Use --help for usage information"
@@ -124,6 +144,47 @@ validate_bandwidth() {
[ "$1" -ge 256 ] 2>/dev/null
}
# 🔒 NEW: Backup function
create_config_backup() {
if [ -f "$CONFIG_FILE" ] && [ "$CREATE_BACKUP" = "true" ]; then
BACKUP_TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${CONFIG_FILE}.backup.${BACKUP_TIMESTAMP}"
echo -e "${BLUE}📦 Creating backup...${NC}"
if cp "$CONFIG_FILE" "$BACKUP_FILE" 2>/dev/null; then
echo -e "${GREEN}✅ Backup created: $BACKUP_FILE${NC}"
# Keep only last 5 backups
BACKUP_COUNT=$(ls -1 "${CONFIG_FILE}.backup."* 2>/dev/null | wc -l)
if [ "$BACKUP_COUNT" -gt 5 ]; then
echo -e "${YELLOW}🧹 Cleaning old backups (keeping last 5)...${NC}"
ls -1t "${CONFIG_FILE}.backup."* | tail -n +6 | xargs rm -f 2>/dev/null || true
fi
return 0
else
echo -e "${YELLOW}⚠️ Warning: Could not create backup${NC}"
echo -e "${YELLOW} Proceeding anyway...${NC}"
return 1
fi
fi
}
# 🔒 NEW: Restore function (if setup fails)
restore_from_backup() {
LATEST_BACKUP=$(ls -1t "${CONFIG_FILE}.backup."* 2>/dev/null | head -1)
if [ -n "$LATEST_BACKUP" ]; then
echo ""
echo -e "${YELLOW}❌ Setup failed. Restoring from backup...${NC}"
if cp "$LATEST_BACKUP" "$CONFIG_FILE" 2>/dev/null; then
echo -e "${GREEN}✅ Configuration restored from: $LATEST_BACKUP${NC}"
else
echo -e "${RED}❌ Failed to restore backup${NC}"
fi
fi
}
# Main setup wizard
clear
cat << EOF
@@ -138,9 +199,33 @@ ${PURPLE}╔══════════════════════
This wizard will help you configure a Tor relay with optimal
settings for your network and preferences.
Press Ctrl+C at any time to cancel.
Press Ctrl+C at any time to cancel safely.
EOF
# Check if config exists
if [ -f "$CONFIG_FILE" ]; then
echo ""
echo -e "${YELLOW}⚠️ Existing configuration found at:${NC}"
echo -e "${YELLOW} $CONFIG_FILE${NC}"
echo ""
if [ "$CREATE_BACKUP" = "true" ]; then
echo -e "${GREEN}🔒 A backup will be created before making changes.${NC}"
else
echo -e "${RED}⚠️ Backup creation is disabled!${NC}"
fi
if [ "$AUTO_MODE" != "true" ]; then
echo ""
printf "Continue and overwrite existing config? [y/N]: "
read CONFIRM
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
echo -e "${YELLOW}Setup cancelled.${NC}"
exit 0
fi
fi
fi
# Step 1: Nickname
print_header "Step 1: Relay Nickname"
print_step "1" "Choose a nickname for your relay"
@@ -297,8 +382,11 @@ print_header "Step 6: Generating Configuration"
print_step "6" "Creating torrc file"
echo ""
# 🔒 Create backup before overwriting
create_config_backup
# Create configuration
cat > "$CONFIG_FILE" << EOF
if ! cat > "$CONFIG_FILE" << EOF
# Tor Relay Configuration
# Generated by Tor-Guard-Relay Setup Wizard v${VERSION}
# Date: $(date '+%Y-%m-%d %H:%M:%S')
@@ -313,76 +401,4 @@ DirPort $DIRPORT
# Bandwidth Limits
RelayBandwidthRate $BANDWIDTH KB
RelayBandwidthBurst $((BANDWIDTH * 2)) KB
# Relay Type Configuration
EOF
case "$RELAY_TYPE" in
exit)
cat >> "$CONFIG_FILE" << EOF
ExitRelay 1
ExitPolicy accept *:80 # HTTP
ExitPolicy accept *:443 # HTTPS
ExitPolicy accept *:6667 # IRC
ExitPolicy accept *:22 # SSH
ExitPolicy reject *:* # Reject everything else
EOF
;;
bridge)
cat >> "$CONFIG_FILE" << EOF
BridgeRelay 1
PublishServerDescriptor bridge
ExitRelay 0
EOF
;;
*)
cat >> "$CONFIG_FILE" << EOF
ExitRelay 0
ExitPolicy reject *:*
EOF
;;
esac
# Add common settings
cat >> "$CONFIG_FILE" << EOF
# Logging
Log notice file /var/log/tor/notices.log
Log notice syslog
# Data Directory
DataDirectory /var/lib/tor
# Performance
NumCPUs 0 # Use all available CPUs
HardwareAccel 1
# Security
NoExec 1
EOF
# Validate configuration
echo -e "${GREEN}✓${NC} Configuration generated successfully!"
echo ""
echo "📋 Configuration Summary:"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Nickname: $NICKNAME"
echo " Contact: $CONTACT"
echo " ORPort: $ORPORT"
echo " DirPort: $DIRPORT"
echo " Bandwidth: $BANDWIDTH KB/s"
echo " Type: $RELAY_TYPE"
echo " Config: $CONFIG_FILE"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo -e "${GREEN}✅ Setup complete!${NC}"
echo ""
echo "Next steps:"
echo " 1. Review the configuration: cat $CONFIG_FILE"
echo " 2. Start your relay: tor -f $CONFIG_FILE"
echo " 3. Monitor status: /usr/local/bin/status"
echo " 4. Check metrics: /usr/local/bin/metrics"
echo ""
echo "🌐 Your relay will appear on Tor Metrics after ~3 hours:"
echo " https://metrics.torproject.org/rs.html"
RelayBandwidthBurst $((