Bitcoind Secure Connections
Bitcoind Secure Connections
When you point a wallet or script at bitcoind’s JSON-RPC from anywhere other than the same machine, you’re handling the keys to a vault.
By default, the RPC interface is plain HTTP using Basic authentication—which is just Base64 of user:pass, not encryption.
Anyone on-path can read your credentials, alter your requests, and replay them later. This post explains why you should
never expose RPC directly to the internet and shows four secure ways to wrap it in an encrypted, authenticated channel.
Why an encrypted tunnel is mandatory
- Basic auth isn’t encryption. It’s trivially reversible if intercepted.
- No integrity on the wire. A man-in-the-middle can modify requests/responses (e.g., change address or amount).
- Replay risk. Static credentials can be reused after capture.
- High-value target. Attackers constantly scan for exposed
:8332.
localhost and reach it only through an encrypted, authenticated tunnel.
Safe patterns (pick one)
1) SSH local port-forward (simple, battle-tested)
On your client machine:
ssh -N -L 8332:127.0.0.1:8332 bitcoin@your-server.example
Then call RPC locally through the encrypted tunnel:
curl --user rpcuser:rpcpassword \
-H 'content-type: text/plain' \
--data-binary '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \
http://127.0.0.1:8332/
Pros: Zero extra services; strong crypto; easy to audit.
Cons: Requires an interactive SSH channel or a managed tunnel process.
2) WireGuard (always-on private network)
Create a WireGuard interface so your client reaches the node over a private subnet (e.g., 10.8.0.0/24). Keep bitcoind bound to 127.0.0.1 and expose it to WG with a loopback proxy.
Sketch:
- Server:
wg0on10.8.0.1 - Client:
wg0on10.8.0.2 - Expose localhost RPC to WG only (server):
socat TCP-LISTEN:8332,bind=10.8.0.1,fork TCP:127.0.0.1:8332
Pros: Always-on, low-latency; great for fleets.
Cons: Slightly more setup; secure key distribution needed.
3) TLS reverse proxy with mutual TLS (mTLS)
Terminate TLS at nginx/haproxy/Caddy and proxy to 127.0.0.1:8332. Require a client certificate so only holders of your CA-issued certs can connect.
server {
listen 8332 ssl;
ssl_certificate /etc/ssl/certs/server.crt;
ssl_certificate_key /etc/ssl/private/server.key;
# mTLS
ssl_client_certificate /etc/ssl/certs/ca.crt;
ssl_verify_client on;
# Hardening (sample)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:8332;
proxy_set_header Host $host;
proxy_http_version 1.1;
}
}
Client call:
curl --cert client.crt --key client.key --cacert ca.crt \
--user rpcuser:rpcpassword \
-H 'content-type: text/plain' \
--data-binary '{"jsonrpc":"1.0","id":"curl","method":"getwalletinfo","params":[]}' \
https://your-server.example:8332/
Pros: First-class TLS, revocable client creds, works through corporate egress.
Cons: You must operate a small PKI (CA, issuance, rotation).
4) Tor onion service (encrypted + optional endpoint auth)
Expose RPC as a Tor onion service and (optionally) require client authorization. Keep RPC on localhost; Tor provides encryption and reachability.
Pros: No public IP; encryption built-in; good for remote admin.
Cons: Higher latency; extra operational surface if new to Tor.
bitcoind RPC hardening (do this regardless)
In bitcoin.conf:
# 1) Never bind RPC to the public interface
rpcbind=127.0.0.1
rpcallowip=127.0.0.1
# 2) Use rpcauth (salted verifier) instead of plain rpcuser/rpcpassword
# Generate with contrib/rpcauth tool
rpcauth=alice:1c2f...$7b3c...
# 3) Least-privilege: turn off wallet RPC if not needed
disablewallet=1
# 4) Optional: keep logs minimal on production nodes
# debug=0
rpcauthprotects the stored secret, but the wire still carries Basic auth → you still need encryption.- For same-host automation, prefer the random per-run
.cookiefile. - Host firewall: allow only SSH/WireGuard/TLS from trusted sources; drop everything else.
What not to do
- Don’t expose
:8332to the public internet. - Don’t treat
rpcallowipas “security”—it’s access control, not encryption. - Don’t reuse weak or shared credentials; rotate on any suspicion of exposure.
- Don’t skip cert revocation when staff or machines churn (for mTLS).
Quick decision guide
- Single admin, occasional access: SSH port-forward.
- Team / multiple devices, always-on: WireGuard.
- Enterprise with cert lifecycle: TLS + mTLS.
- Privacy-sensitive remote ops: Tor onion service.
Minimal, secure setup in 3 commands (SSH method)
- Ensure RPC is local-only:
# bitcoin.conf rpcbind=127.0.0.1 rpcallowip=127.0.0.1 rpcauth=alice:... - Open a tunnel from your laptop:
ssh -N -L 8332:127.0.0.1:8332 bitcoin@your-server.example - Use RPC safely over the tunnel:
curl --user alice:yourpassword \ -H 'content-type: text/plain' \ --data-binary '{"jsonrpc":"1.0","id":"curl","method":"getblockchaininfo","params":[]}' \ http://127.0.0.1:8332/
You now have confidentiality, integrity, and strong endpoint authentication—exactly what the default RPC transport lacks.
Leave a Reply