How to Configure Bitcoin Core for Tor and I2P Privacy Networks

Bitcoin Core routes peer-to-peer traffic through Tor and I2P using SOCKS5 proxies and SAM bridges, while optionally exposing ephemeral hidden services via the -listenonion and -i2pacceptincoming options.

The bitcoin/bitcoin repository implements privacy network support in its networking layer (src/net.cpp), Tor controller (src/torcontrol.cpp), and address management (src/netaddress.cpp). This allows nodes to operate without revealing public IP addresses, preventing traffic correlation attacks while maintaining full participation in the Bitcoin network.

Tor Configuration Basics

Bitcoin Core connects to the Tor anonymity network through a local SOCKS5 proxy and optionally creates a Version 3 onion service (hidden service) for inbound connections.

Outbound Connections via SOCKS5

Configure your node to route all traffic through Tor’s SOCKS port by setting the proxy address in bitcoin.conf:

proxy=127.0.0.1:9050

The InitProxy() function in src/net.cpp parses this setting and establishes the SOCKS5 connection. When IsolateSOCKSAuth is enabled (default), Bitcoin Core forces a new Tor circuit for each outbound connection, preventing peers from correlating your traffic streams.

Creating an Ephemeral Onion Service

To make your node reachable as a hidden service, enable the Tor control port and activate onion listening:

onion=127.0.0.1:9051
listenonion=1

The TorController class in src/torcontrol.cpp opens a non-blocking socket to the control port, authenticates using the Tor cookie file, and issues the ADD_ONION command. This creates an ephemeral v3 service without manual configuration files. The private key is automatically persisted to onion_v3_private_key in your data directory, allowing the service identity to survive restarts.

I2P Configuration Setup

I2P support utilizes the SAM (Simple Anonymous Messaging) bridge to create encrypted tunnels through the I2P overlay network.

Connecting to the SAM Bridge

Enable I2P by pointing Bitcoin Core to your local SAM service:

i2psam=127.0.0.1:7656
i2pacceptincoming=1

When CreateI2PSession() in src/net.cpp executes, it establishes a TCP connection to the SAM bridge, creates a stream session, and obtains your node’s base-32 .b32.i2p address. The I2P address is treated as a distinct network type (NET_I2P) throughout the codebase, separate from IPv4, IPv6, or Tor.

Address Advertisement

Both Tor and I2P addresses propagate via the addrv2 protocol (BIP 155). When you enable listening, your node advertises its .onion or .b32.i2p address to peers using 33-byte serialized public keys for Tor v3 or the corresponding I2P destination format, ensuring discoverability without IP exposure.

Network Isolation and Security

Restrict your node to privacy-only connections to prevent accidental clearnet leaks:

onlynet=onion

# OR

onlynet=i2p

# OR both

onlynet=onion,i2p

The CNetPermissions system in src/net_processing.cpp validates each peer’s network type against your -onlynet list. Peers matching excluded network types are discarded before connection establishment, ensuring no IPv4/IPv6 traffic occurs.

For authenticated SOCKS proxies (useful when running multiple services through Tor), add credentials:

proxyuser=your_username
proxypassword=your_password

Internal Implementation Details

The privacy networking stack operates through several key components:

Proxy Management – The CConnman class manages proxy configurations separately for generic SOCKS (-proxy), Tor-specific (-onion), and I2P SAM (-i2psam). Each proxy type is stored as a CService object used during outbound connection attempts.

Tor Control Protocol – When -listenonion is active, src/torcontrol.cpp handles the full lifecycle:

  1. Authenticates via CookieAuthFile
  2. Issues ADD_ONION with flags Flags=Detach,DiscardPK,BasicAuth
  3. Parses the ServiceID response to extract the onion address
  4. Writes the private key to disk using WriteFile() in the data directory

I2P Session Handling – The SAM protocol implementation sends SESSION CREATE commands with STYLE=STREAM, then parses the DESTINATION field to extract the public key used for your .b32.i2p address.

Debugging and Verification

Enable verbose logging to audit privacy network activity:

debug=tor
debug=i2p

These flags activate the BCLog::TOR and BCLog::I2P categories, emitting detailed logs about circuit creation, proxy handshakes, SAM session establishment, and connection failures. Check your debug log for entries like Created Tor hidden service or I2P SAM session established to confirm proper initialization.

Verify your configuration using the getnetworkinfo RPC command, which displays separate sections for tor and i2p networks, showing whether they are reachable and whether the service is private (inbound capable).

Summary

  • Tor integration requires a SOCKS5 proxy (proxy=) for outbound traffic and the control port (onion=) with listenonion=1 to create ephemeral hidden services.
  • I2P integration uses the SAM bridge (i2psam=) with i2pacceptincoming=1 to establish anonymous inbound and outbound streams.
  • Network isolation via onlynet=onion,i2p prevents clearnet connections, enforced by CNetPermissions in the networking stack.
  • Key files involved include src/torcontrol.cpp (hidden service management), src/net.cpp (proxy and I2P sessions), and src/netaddress.cpp (address serialization for BIP 155).
  • Persistent identity for Tor onion services is stored in onion_v3_private_key in your Bitcoin data directory.

Frequently Asked Questions

How do I verify that Bitcoin Core is actually using Tor for all connections?

Run the getnetworkinfo RPC command and check the networks array. The tor entry should show "reachable": true, and if you have listenonion=1 enabled, you should see a localaddresses section containing your .onion address. Additionally, enable debug=tor and look for SOCKS5 connecting messages in the debug log, which confirm traffic is routing through the proxy.

What is the difference between -proxy and -onion configuration options?

The -proxy setting applies to all outbound connections across all network types, while -onion specifically targets Tor hidden service connections and control port communication. If you specify only -proxy, Bitcoin Core will route onion connections through that generic proxy but cannot create inbound hidden services. Use -onion when you need to authenticate with the Tor ControlPort to create ephemeral onion services via the ADD_ONION command.

Can I run Bitcoin Core as both a Tor hidden service and an I2P eepsite simultaneously?

Yes, configure both networks in your bitcoin.conf by setting listenonion=1 with a Tor control port and i2pacceptincoming=1 with a SAM bridge address. Your node will advertise both addresses via the addrv2 protocol, allowing peers to connect through either network. Use onlynet=onion,i2p to restrict all traffic to these privacy networks exclusively.

Where does Bitcoin Core store the private key for my Tor onion service?

The private key for ephemeral v3 onion services is persisted in a file named onion_v3_private_key located in your Bitcoin data directory. This file is created by the TorController::add_onion_cb function in src/torcontrol.cpp when the hidden service is first established, ensuring your onion address remains consistent across restarts without requiring manual Tor configuration files.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →