This repository provides a Docker-based setup for running Bitcoin Knots and electrs, with an optional Tor hidden service for remote Electrum access.
Current Bitcoin Knots Version: 29.3.knots20260508 Source: URLs pulled from https://bitcoinknots.org/
-
Clone this repository
-
Copy the example environment file and customize it:
cp .env.example .envEdit .env to set your desired paths and configuration. For development, the defaults are fine.
-
Create a
bitcoin.conffile in the repository root directory. This file will be copied into the container during the build process. -
Create your data directories (if using default paths):
mkdir bitcoin-data electrs-dataOptionally create a tor-data directory if you plan to enable Tor (see Tor section below).
- Build and start the containers:
docker compose up --build- If you see an error from electrs saying it can't find the cookie file, make sure in your bitcoin.conf you're allowing the proper docker subnet IP. You can find this by running:
# Find the docker network name that these containers are on
docker network ls
# Find the subnet of the docker network
docker network inspect <network name> | grep Subnet
# update the bitcoin.conf file with the subnetWhen you run docker-compose up --build, the following happens:
The Dockerfile implements a robust security verification process to ensure the authenticity of Bitcoin Knots binaries:
- Multi-stage build: Uses a separate builder stage to download and verify binaries before copying to the runtime container
- Cryptographic verification:
- Downloads Bitcoin Knots binaries, SHA256SUMS, and SHA256SUMS.asc files
- Imports trusted builder keys from the official Bitcoin Knots guix.sigs repository
- Verifies the GPG signature on SHA256SUMS using these trusted keys
- Validates the binary checksum against the signed SHA256SUMS file
- Clean runtime: Only verified binaries are copied to the final runtime container
- bitcoind container: Runs Bitcoin Knots with user/group ID matching your host system to avoid permission issues
- electrs container: Provides an Electrum server interface to the Bitcoin node
- tor container (optional): Exposes electrs as a Tor hidden service so you can connect from remote wallets like Sparrow via Tor
- Containers communicate over a Docker network, with electrs connecting to bitcoind's RPC interface, and tor connecting to electrs
Development/Testing: By default, data is stored in local directories (./bitcoin-data, ./electrs-data, and ./tor-data)
Production: For production deployments, you should use external storage volumes (like dedicated SSDs) mounted to your host system:
-
Mount your external storage (e.g., SSD) to your host system:
# Example: mount external SSD to /mnt/bitcoin-storage sudo mount /dev/sdX1 /mnt/bitcoin-storage sudo mkdir -p /mnt/bitcoin-storage/bitcoin-data sudo mkdir -p /mnt/bitcoin-storage/electrs-data -
Update your .env file to use the mounted paths:
# Production paths in .env BITCOIN_DATA_PATH=/mnt/bitcoin-storage/bitcoin-data ELECTRS_DATA_PATH=/mnt/bitcoin-storage/electrs-data ELECTRS_SERVER_BANNER=Production Bitcoin Node
This approach provides better performance, dedicated storage space, and easier backup/migration capabilities. Make sure to set proper ownership and permissions on the mounted directories to match your container user IDs.
Tor Hidden Service (Remote Access)
The tor container creates a Tor hidden service that exposes electrs's Electrum port (50001) as a .onion address. This lets you connect to your node remotely from wallets that support Tor (like Sparrow Wallet).
- The tor container builds from
tor/Dockerfile(Alpine + Tor) tor/torrcconfigures a hidden service mapping port 50001 toelectrs:50001- On startup,
tor/entrypoint.shwaits for Tor to generate the hostname and prints the.onionaddress to the container logs - The onion address and its private key persist in
./tor-data/(the mounted volume), so the address stays the same across restarts
Tor is disabled by default — the tor container only starts when you activate it.
-
Uncomment the profile line in your
.envfile:COMPOSE_PROFILES=torThis tells Docker Compose to include the
torprofile on everydocker compose up. -
Create the Tor data directory (stores the
.onionprivate key so the address is stable):mkdir tor-data
-
Make sure
TOR_DATA_PATHis set —.env.examplealready includesTOR_DATA_PATH=./tor-data. If you copied.env.exampleto.envbefore this change, add it manually:TOR_DATA_PATH=./tor-data
That's it. Next docker compose up will build and start the tor container automatically.
To disable it again, just comment out or remove COMPOSE_PROFILES=tor from .env.
After starting the containers, read it from the tor container logs:
docker compose logs torYou'll see output like:
tor | Waiting for Tor hidden service to be ready...
tor | ==========================================
tor | Tor Hidden Service: xyzabc123def456.onion
tor | Connect with Sparrow Wallet:
tor | Server: xyzabc123def456.onion
tor | Port: 50001
tor | Protocol: TCP (SSL disabled)
tor | ==========================================
You can also read the hostname file directly from the host:
cat ./tor-data/hostname- Open Sparrow → Preferences → Connection
- Set Server Type to "Electrum Server"
- Set URL to your
.onionaddress (e.g.,xyzabc123def456.onion:50001) - Make sure Sparrow has Tor enabled in its settings (Tools → Restart in Tor mode, or configure the Tor SOCKS proxy under Preferences → Connection → Use Tor)
- Click "Test Connection"
- Privacy: The
.onionaddress is public by design — it's how other nodes reach your service. The private key (in./tor-data/private_key) is what keeps it secure. Protect the tor-data directory. - Back up
./tor-data/— losing the private key means getting a new.onionaddress and reconfiguring all connected wallets. - Only electrs is exposed via the hidden service. The bitcoind RPC and P2P ports are not routed through Tor — they remain local.
- The tor container is disabled by default via Docker Compose profiles. It only starts if
COMPOSE_PROFILES=toris set in your.envfile. To disable an existing setup, just comment out that line.