en

Rust Actix-Web Server as Tor Hidden Service

Rust with Actix-web delivers the highest performance-per-memory-MB of any web framework, making it an excellent choice for Tor hidden service hosting where server resources are at a premium. A compiled Rust binary with Actix-web handles tens of thousands of requests per second on minimal hardware with single-digit millisecond response times - Tor's inherent latency makes this headroom valuable. This guide covers deploying a Rust Actix-web application as a Tor hidden service with production-grade configuration.

Need this done for your project?

We implement, you ship. Async, documented, done in days.

Start a Brief

Binding Actix-web to Localhost for Onion Isolation

Configure Actix-web to bind exclusively to localhost. The standard Actix-web server setup uses HttpServer::new().bind('127.0.0.1:8080') rather than '0.0.0.0:8080'. This single configuration choice ensures the application is completely invisible to clearnet network scanners. For production Actix-web applications, also configure the number of workers: HttpServer::new().workers(4) sets 4 worker threads (match to available CPU cores). Actix-web uses a multi-threaded executor - each worker thread handles I/O independently, enabling high concurrency without additional configuration. The Tor hidden service maps an .onion address port to this localhost:8080 address. Optional nginx layer: for complex routing, TLS termination (if desired), or serving static files, add nginx as a reverse proxy between Tor and Actix. For simple API services, direct Tor-to-Actix binding (without nginx) reduces latency and complexity.

Async Database Access and Connection Pooling

Actix-web's async architecture requires async database clients. Use SQLx for PostgreSQL/MySQL/SQLite with async support. Configure SQLx with a connection pool: PgPoolOptions::new().max_connections(20).connect('postgres://user:pass@127.0.0.1:5432/mydb'). The database binds to localhost, so this connection does not traverse Tor - it goes directly to the local PostgreSQL socket. For remote database connections over Tor: use a SOCKS5-aware connection wrapper. SQLx does not natively support SOCKS5 proxies, so you need a localhost TCP proxy that forwards traffic through Tor (using redsocks or a custom tokio SOCKS5 implementation) and point SQLx at the local proxy port. For most .onion service deployments, colocating the database on the same server (same machine, local connection) is the simplest and most performant approach - no Tor routing needed for the database connection.

Request Logging and Privacy Considerations

Actix-web's default Logger middleware logs IP addresses, URLs, response codes, and timing. In a Tor hidden service context, the 'IP address' logged is always 127.0.0.1 (Tor delivers connections locally), so IP logging is not useful for client identification. Disable detailed logging or configure a custom log format that omits IP addresses (since they're meaningless) and focuses on status codes, request paths, and response times for performance monitoring. Use the tracing crate with tracing-subscriber for structured logging: log levels (ERROR, WARN, INFO, DEBUG) and span context. For privacy-sensitive deployments, set log level to ERROR in production (logs only errors, not access patterns). Log to local files only (not remote log aggregation services). Implement request ID middleware (use uuid to generate per-request IDs) for correlating logs without exposing user-identifying information.

Building and Distributing Rust Binaries for .onion Servers

Cross-compile Rust binaries for the target server architecture. For a Linux x86_64 server, compile on any machine with: cargo build --release --target x86_64-unknown-linux-gnu. The resulting binary in target/x86_64-unknown-linux-gnu/release/ is a self-contained static binary (with musl target: cargo build --release --target x86_64-unknown-linux-musl for maximum portability with no glibc dependency). Transfer via SCP over Tor: scp -o ProxyCommand='nc -x 127.0.0.1:9050 %h %p' binary user@server.onion:/opt/myapp/. Create a systemd service unit with Type=simple, ExecStart=/opt/myapp/binary, Restart=on-failure, and RestartSec=5. Strip debug symbols from release builds: in Cargo.toml add [profile.release] strip = true and lto = true for maximum binary size reduction and performance. A typical Actix-web API binary strips to 2-10 MB. Memory usage at idle is 5-20 MB for simple applications, making Rust an excellent choice for resource-constrained .onion hosting scenarios.

Error Handling Without Information Disclosure

Actix-web's default error handlers return detailed error information including stack traces in development mode. For production .onion services, implement custom error handlers that return minimal information. Use actix-web's ErrorHandlerData and custom ErrorResponse types. The error handler should log the full error internally (with tracing or log crate) and return a generic JSON response to clients: { 'error': 'internal server error', 'request_id': 'uuid' }. The request_id allows correlating client-reported errors with server logs without exposing server-side details. For database errors: never expose SQL error messages to clients (they reveal table names, column names, and query structure). Catch sqlx::Error and return a generic 500 response. For validation errors (form input, JSON parsing): return specific validation messages to clients since these are expected user errors with actionable messages (e.g., 'email field is required'), not server-side information disclosure.

Why Anubiz Host

100% async — no calls, no meetings
Delivered in days, not weeks
Full documentation included
Production-grade from day one
Security-first approach
Post-delivery support included

Ready to get started?

Skip the research. Tell us what you need, and we'll scope it, implement it, and hand it back — fully documented and production-ready.

Anubiz Chat AI

Online