Anonymous Ethereum RPC access through Tor with MEV protection
Features β’ Quick Start β’ Installation β’ Usage β’ Security
TorPC provides a privacy-preserving gateway to interact with Ethereum nodes through the Tor network. It acts as a reverse proxy that:
- Routes all RPC calls through Tor for complete anonymity
- Protects against MEV by routing transactions through Flashbots
- Filters dangerous RPC methods to prevent wallet exposure
- Rate limits requests per Tor circuit to prevent abuse
- Provides a simple web interface for testing
User β Tor Network β .onion address β TorPC Proxy β Geth Node
β
Flashbots Relay
- β Linux (Ubuntu 20.04+, Debian 11+, Fedora 35+)
- β macOS (10.15 Catalina or later)
- β Windows (via WSL2)
- Rust 1.70 or later
- Geth (go-ethereum) 1.10+
- Tor 0.4.5+
- Foundry (for testing) - latest version
- RAM: 4GB minimum (8GB recommended)
- Storage: 10GB free space
- Network: Stable internet connection
curl -sSL https://raw.githubusercontent.com/yourusername/torpc/main/install.sh | bash
# 1. Clone the repository
git clone https://github.com/yourusername/torpc.git
cd torpc
# 2. Check prerequisites
./scripts/check-prerequisites.sh
# 3. Build the project
cargo build --release
# 4. Start all services
./scripts/start-all-dev.sh
# This script automatically starts:
# - Geth development node
# - Tor hidden service
# - TorPC proxy server
# No need to run 'cargo run' separately!
# 5. Get your .onion address
cat data/tor/torpc/hostname
Your anonymous RPC endpoint will be available at: http://YOUR-ONION-ADDRESS.onion/rpc
The start-all-dev.sh
script is a convenient way to start all services with one command. It:
- Starts Geth in development mode with a pre-funded account
- Generates test blockchain data (if needed) including:
- Funded test accounts
- Deployed smart contracts
- Sample transactions
- Starts Tor and waits for the .onion address generation
- Builds TorPC (if needed) in release mode
- Starts TorPC proxy server on port 8080
After running this script, all services are running in the background. You can:
- Access the web interface at
http://localhost:8080
- View logs with the commands shown at the end of the script output
- Stop everything with
./scripts/stop-all.sh
# Install rustup (Rust installer)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Add Rust to PATH
source $HOME/.cargo/env
# Verify installation
rustc --version
cargo --version
Ubuntu/Debian:
sudo add-apt-repository -y ppa:ethereum/ethereum
sudo apt-get update
sudo apt-get install ethereum
macOS:
brew tap ethereum/ethereum
brew install ethereum
Fedora:
sudo dnf install ethereum
# Download latest Geth
wget https://gethstore.blob.core.windows.net/builds/geth-linux-amd64-1.13.5-916d6a44.tar.gz
# Extract
tar -xvf geth-linux-amd64-*.tar.gz
# Move to PATH
sudo mv geth-linux-amd64-*/geth /usr/local/bin/
# Verify
geth version
Ubuntu/Debian:
sudo apt update
sudo apt install tor
macOS:
brew install tor
Fedora:
sudo dnf install tor
# Install Foundry
curl -L https://foundry.paradigm.xyz | bash
# Follow the instructions to add foundryup to your PATH, then:
foundryup
# Verify installation
cast --version
forge --version
Important: The scripts require bash. Either make them executable or run with bash:
# Make scripts executable (one-time setup)
chmod +x scripts/*.sh
# Then run directly:
./scripts/start-all-dev.sh
# OR run with bash explicitly:
bash scripts/start-all-dev.sh
# Start with verbose logging
bash scripts/start-all-dev.sh --verbose
# Start with full debug mode
bash scripts/start-all-dev.sh --debug
# Or start services individually:
bash scripts/start-geth-dev.sh # Start Geth in development mode
bash scripts/start-tor.sh # Start Tor hidden service
cargo run --release # Start TorPC proxy
Note: Do NOT use sh scripts/start-all-dev.sh
as it will use the wrong shell interpreter.
# Create data directory
mkdir -p data/geth-dev
# Start Geth
geth --dev \
--http \
--http.addr 127.0.0.1 \
--http.port 8545 \
--http.api eth,net,web3,personal,miner,txpool,debug \
--http.corsdomain "*" \
--datadir ./data/geth-dev \
--mine
# Create Tor data directory
mkdir -p data/tor/torpc
chmod 700 data/tor/torpc
# Start Tor with our configuration
tor -f configs/torrc
Note: If you used
./scripts/start-all-dev.sh
, TorPC is already running! The script automatically builds and starts TorPC for you. Only run the commands below if you're starting services manually.
# Build and run TorPC (only if not using start-all-dev.sh)
cargo build --release
./target/release/torpc
# Or with custom settings:
GETH_URL=http://127.0.0.1:8545 \
BIND_ADDR=127.0.0.1:8080 \
RUST_LOG=info \
./target/release/torpc
# Build Docker image
docker build -t torpc .
# Run with Docker Compose
docker-compose up -d
# View logs
docker-compose logs -f
# Install service files
sudo cp services/*.service /etc/systemd/system/
# Enable services
sudo systemctl enable torpc-geth torpc-tor torpc-proxy
# Start all services
sudo systemctl start torpc-geth torpc-tor torpc-proxy
# Check status
sudo systemctl status torpc-*
# Stop all services gracefully (waits for processes to terminate)
./scripts/stop-all.sh
# Stop with custom timeout (default is 30 seconds)
./scripts/stop-all.sh --timeout 60
# Immediately kill all processes (use if graceful shutdown fails)
./scripts/stop-all.sh --force
# Check for running processes
pgrep -f "geth.*--dev"
pgrep -f "tor -f configs/torrc"
pgrep -f "target/release/torpc"
# Kill specific processes manually
kill -9 <PID>
# Check if ports are freed
lsof -ti:8545 # Geth RPC port
lsof -ti:8546 # Geth WebSocket port
The enhanced stop script will:
- β Wait for processes to terminate gracefully
- β Use force kill if graceful shutdown fails
- β Verify all processes are actually terminated
- β Check that ports are freed
- β Report accurate success/failure status
- β Handle multiple Geth instances properly
π§ Understanding Tor Hidden Services
- Automatic .onion Address Generation: When Tor starts, it automatically generates a unique .onion address
- Private Key Storage: The private key is stored in
data/tor/torpc/
- No DNS Required: .onion addresses work without any DNS configuration
- End-to-End Encryption: All traffic is encrypted through the Tor network
# After starting Tor, get your address:
cat data/tor/torpc/hostname
# Example output:
# 3g2upl4pq6kufc4m7v5jzvfncqvhv5bak6d2nprpz7hgbc6jvdnq5jqd.onion
Generate a custom .onion address starting with specific characters:
# Install mkp224o
git clone https://github.com/cathugger/mkp224o.git
cd mkp224o
./autogen.sh
./configure
make
# Generate address starting with "torpc"
./mkp224o torpc
# Copy generated keys to TorPC
cp -r generated_address/* ../data/tor/torpc/
# Test using torsocks and curl
torsocks curl http://YOUR-ONION-ADDRESS.onion/
# Test RPC endpoint
torsocks curl -X POST http://YOUR-ONION-ADDRESS.onion/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# Run the test data generation script
./scripts/generate-test-data.sh
# Run with verbose output
./scripts/generate-test-data.sh --verbose
# Run with debug mode for troubleshooting
./scripts/generate-test-data.sh --debug
# This will:
# - Create test accounts with ETH
# - Deploy smart contracts
# - Generate 100+ blocks with transactions
# - Output test account details
- Open your browser (regular or Tor Browser)
- Navigate to
http://localhost:8080
orhttp://YOUR-ONION-ADDRESS.onion
- Use the interactive interface to test RPC calls
# Test local endpoint
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# Test through Tor
torsocks curl -X POST http://YOUR-ONION-ADDRESS.onion/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0x742d35Cc6634C0532925a3b844Bc9e7595f7777","latest"],"id":1}'
# Test MEV protection endpoint
torsocks curl -X POST http://YOUR-ONION-ADDRESS.onion/rpc/flashbots \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0xRAW_TX_HEX"],"id":1}'
# Set RPC URL
export ETH_RPC_URL=http://localhost:8080/rpc
# Get latest block
cast block-number
# Get account balance
cast balance 0x742d35Cc6634C0532925a3b844Bc9e7595f7777
# Send transaction (will route through Flashbots)
cast send --private-key $PRIVATE_KEY --value 0.1ether $TO_ADDRESS --rpc-url http://localhost:8080/rpc/flashbots
# Run all tests
cargo test
# Run specific test suites
cargo test --test integration
cargo test whitelist
cargo test proxy
# Run with verbose output
RUST_LOG=debug cargo test -- --nocapture
# Geth connection
GETH_URL=http://127.0.0.1:8545 # Geth RPC endpoint
FLASHBOTS_URL=https://relay.flashbots.net # Flashbots relay
# Server settings
BIND_ADDR=127.0.0.1:8080 # Proxy bind address
RUST_LOG=info # Log level (trace/debug/info/warn/error)
# Rate limiting
RATE_LIMIT_REQUESTS=60 # Max requests per window
RATE_LIMIT_WINDOW=60 # Window duration in seconds
# Security settings
MAX_REQUEST_SIZE=524288 # Max request body size (default: 512KB)
REQUEST_TIMEOUT=30 # Request timeout in seconds
STRICT_SECURITY_HEADERS=false # Enable strict security (no CORS)
# Tor settings (if using SOCKS)
TOR_SOCKS_PROXY=127.0.0.1:9050 # Tor SOCKS proxy address
# Hidden service settings
HiddenServiceDir ./data/tor/torpc/
HiddenServicePort 80 127.0.0.1:8080
HiddenServiceVersion 3
# Performance
HiddenServiceMaxStreams 100
HiddenServiceMaxStreamsCloseCircuit 1
# Security
SocksPort 0 # Disable SOCKS if only using hidden service
# Logging
Log notice file ./data/tor/tor.log
DataDirectory ./data/tor
Edit src/rate_limit.rs
to adjust rate limiting:
pub struct RateLimitConfig {
pub max_requests: u32, // Default: 60
pub window_duration: Duration, // Default: 60 seconds
}
# Get current block number
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}'
# Get account balance
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"eth_getBalance",
"params":["0x742d35Cc6634C0532925a3b844Bc9e7595f7777", "latest"],
"id":1
}'
# Estimate gas
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"eth_estimateGas",
"params":[{
"from": "0x742d35Cc6634C0532925a3b844Bc9e7595f7777",
"to": "0x742d35Cc6634C0532925a3b844Bc9e7595f8888",
"value": "0x9184e72a"
}],
"id":1
}'
# Send transaction through Flashbots
curl -X POST http://localhost:8080/rpc/flashbots \
-H "Content-Type: application/json" \
-d '{
"jsonrpc":"2.0",
"method":"eth_sendRawTransaction",
"params":["0xf86c0185..."], # Your signed transaction
"id":1
}'
# Send multiple requests in one call
curl -X POST http://localhost:8080/rpc \
-H "Content-Type: application/json" \
-d '[
{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1},
{"jsonrpc":"2.0","method":"net_version","params":[],"id":2},
{"jsonrpc":"2.0","method":"eth_gasPrice","params":[],"id":3}
]'
TorPC implements comprehensive security headers to protect against common web attacks:
# Security headers applied to all responses:
# - X-Content-Type-Options: nosniff (prevents MIME type sniffing)
# - X-Frame-Options: DENY (prevents clickjacking)
# - X-XSS-Protection: 0 (disables legacy XSS filter)
# - Referrer-Policy: no-referrer (prevents onion address leaks)
# - Content-Security-Policy: default-src 'none' (strict CSP for API)
# - Cache-Control: no-store, no-cache, must-revalidate
# - Server header sanitized to prevent fingerprinting
Protection against DoS attacks through configurable request size limits:
# Default: 512KB (sufficient for most Ethereum RPC requests)
export MAX_REQUEST_SIZE=524288
# For batch operations: 2MB
export MAX_REQUEST_SIZE=2097152
# Request timeout (default: 30 seconds)
export REQUEST_TIMEOUT=30
# Strict security headers (disables CORS)
export STRICT_SECURITY_HEADERS=true
By default, TorPC allows CORS for maximum compatibility:
# Standard mode (with CORS - default)
export STRICT_SECURITY_HEADERS=false
# Strict mode (no CORS - recommended for production)
export STRICT_SECURITY_HEADERS=true
# Block external access to Geth and TorPC
sudo ufw deny 8545/tcp # Block Geth
sudo ufw deny 8080/tcp # Block TorPC direct access
# Allow only localhost connections
sudo iptables -A INPUT -p tcp --dport 8545 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8545 -j DROP
sudo iptables -A INPUT -p tcp --dport 8080 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 8080 -j DROP
Each connection through Tor uses a separate circuit, ensuring:
- No correlation between different users
- Isolated rate limiting per circuit
- Enhanced privacy
# Secure Tor keys
chmod 700 data/tor/torpc
chmod 600 data/tor/torpc/hs_ed25519_secret_key
# Backup your keys securely
cp -r data/tor/torpc /secure/backup/location/
- β DO: Always use Tor Browser or torsocks for anonymous access
- β DO: Regularly update all components
- β DO: Monitor logs for suspicious activity
- β DON'T: Share your .onion address publicly unless intended
- β DON'T: Run on a VPS that requires KYC
- β DON'T: Use the same .onion for multiple services
# Check if port is already in use
lsof -i :8545
# Kill existing process
kill -9 $(lsof -t -i:8545)
# Check Geth logs
tail -f data/geth-dev/geth.log
# Check Tor status
systemctl status tor
# Check Tor logs
tail -f data/tor/tor.log
# Verify torrc syntax
tor --verify-config -f configs/torrc
# Check permissions
ls -la data/tor/torpc/
# Update Rust
rustup update
# Clean and rebuild
cargo clean
cargo build --release
# Check dependencies
cargo tree
# Increase rate limits
export RATE_LIMIT_REQUESTS=120
export RATE_LIMIT_WINDOW=60
# Or modify in code and rebuild
# Enable debug logging
RUST_LOG=debug ./target/release/torpc
# Enable Tor debug logs
echo "Log debug file ./data/tor/debug.log" >> configs/torrc
-
Slow Responses:
- Check Geth sync status:
cast block-number
- Verify Tor circuit health
- Consider increasing rate limits
- Check Geth sync status:
-
High Memory Usage:
- Limit Geth cache:
--cache 1024
- Reduce Tor MaxStreams
- Limit Geth cache:
-
Connection Drops:
- Check firewall rules
- Verify Tor is running
- Monitor system resources
Edit src/whitelist.rs
to modify allowed methods:
const ALLOWED_METHODS: &[&str] = &[
// Add your custom methods here
"eth_blockNumber",
"eth_getBalance",
// ...
];
The /rpc/flashbots
endpoint automatically routes transactions to prevent MEV:
eth_sendRawTransaction
β Flashbots Relay- Other methods β Local Geth node
To add Flashbots authentication:
// In src/proxy.rs
headers.insert("X-Flashbots-Signature", signature);
# Add Prometheus metrics (coming soon)
cargo add prometheus
# Export metrics endpoint
METRICS_ADDR=127.0.0.1:9090
# Dockerfile
FROM rust:1.70 as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bullseye-slim
RUN apt-get update && apt-get install -y tor geth
COPY --from=builder /app/target/release/torpc /usr/local/bin/
COPY configs /etc/torpc/
CMD ["torpc"]
# docker-compose.yml
version: '3.8'
services:
geth:
image: ethereum/client-go:latest
command: --dev --http --http.addr 0.0.0.0
volumes:
- geth-data:/data
tor:
image: osminogin/tor-simple
volumes:
- tor-data:/var/lib/tor
- ./configs/torrc:/etc/tor/torrc
torpc:
build: .
depends_on:
- geth
- tor
environment:
- GETH_URL=http://geth:8545
ports:
- "8080:8080"
volumes:
geth-data:
tor-data:
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# Fork and clone
git clone https://github.com/yourusername/torpc.git
cd torpc
# Create feature branch
git checkout -b feature/your-feature
# Install dev dependencies
cargo install cargo-watch cargo-audit
# Run in watch mode
cargo watch -x run
# Run tests on change
cargo watch -x test
This project is licensed under the MIT License - see LICENSE for details.
- Tor Project for anonymous networking
- Ethereum Foundation for the blockchain
- Flashbots for MEV protection
- Rust Community for the amazing ecosystem
Built with π¦ Rust and π§ Tor for a more private Ethereum