pull down to refresh

Original post found at expatriotic.me
Browse the preceding "Node" guides from my blog
  1. Ubuntu
  2. Bitcoin Core
  3. Fulcrum 2.0 (Fast and stable electrum server)

Why Run Your Own Mempool?

When you use a public block explorer like mempool.space, you are broadcasting your interest in specific transactions and addresses to the server's operator. This leaks your IP address and links it to your on-chain activity, a significant privacy gap.
The only sovereign solution is to run your own instance.
Mempool.space is not a single program but a multi-service stack, requiring a web frontend, a backend API, and a database. Attempting a "bare metal" install is complex. The official and most robust method is using Docker.
Think of Docker as a system for running pre-packaged, isolated "apps." We will simply provide a docker-compose.yml "blueprint" file that tells Docker how to connect these apps to your existing Bitcoin Core and Fulcrum nodes.

Prerequisites: Your Foundation

This guide assumes you have an Ubuntu server with the following already installed, fully synced, and running.
  1. A Synced Bitcoin Core Node:
    • Your bitcoin.conf file must have txindex=1 and ZMQ enabled.
    • Your bitcoin.conf must be configured to bind to both localhost (for Fulcrum) and the Docker host network, and it must allow RPC connections from two different Docker networks.
    Example: /home/satoshis/.bitcoin/bitcoin.conf
    
    # [For a node serving Fulcrum, Ashigaru and Mempool via Docker]
    
    # Network
    server=1
    txindex=1
    
    # RPC
    rpcbind=127.0.0.1
    rpcbind=172.17.0.1
    rpcport=8332
    rpcuser=YOUR_USER_NAME #CHANGE THIS!!!!!!
    rpcpassword=YOUR_VERY_STRONG_PASSWORD #CHANGE THIS!!!!!!
    
    # Allow connections from the Docker network
    rpcallowip=172.17.0.0/16
    # Allow connections from the Mempool container network
    rpcallowip=172.18.0.0/16
    
    # ZMQ (ZeroMQ)
    zmqpubrawblock=tcp://127.0.0.1:28332
    zmqpubrawtx=tcp://127.0.0.1:28333
    
    # Disable the wallet
    disablewallet=1
    
    # Use a large cache (in MB) to speed up IBD
    dbcache=4096
    
    
  2. A Synced Fulcrum Electrum Server:
    • Your Fulcrum node must be configured to listen for wallet connections. This guide uses the unencrypted tcp port, which is perfectly secure on an internal network (like Docker's or your LAN).
    Example: /home/satoshis/fulcrum/fulcrum.conf
    # --- Fulcrum Config ---
    # This is the main database directory.
    # It MUST be on your NVMe.
    datadir = /home/satoshis/fulcrum_db
    
    # --- Bitcoin Core Connection ---
    # Point to your bitcoind service
    bitcoind = 127.0.0.1:8332
    
    # These MUST match your bitcoin.conf
    rpcuser = YOUR_USER_NAME # CHANGE THIS!!!
    rpcpassword = YOUR_VERY_STRONG_PASSWORD # CHANGE THIS!!!!
    
    # --- Server Ports ---
    # Allow other computers on your network (like your desktop)
    # to connect over an encrypted channel.
    ssl = 0.0.0.0:50002
    tcp = 0.0.0.0:50001
    # Point to the SSL certs we just made
    cert = /home/satoshis/fulcrum/cert.pem
    key = /home/satoshis/fulcrum/key.pem
    
    # Optional: Uncomment and set a banner file
    banner = /home/satoshis/fulcrum/banner.txt
    
    # --- Performance & Privacy ---
    # We have 24GB RAM. bitcoind is using 4GB.
    # Let's give Fulcrum 5GB (5120MB).
    db_mem = 5120
    
    # We are a private node, no need to peer.
    peering = false 
    
    

Phase 1: Install the Docker Engine

First, we install the Docker engine that will run our containers.

1. Add Docker's Security Key

This verifies the authenticity of the software we're about to install.
# Update your package list and install prerequisites
sudo apt-get update
sudo apt-get install ca-certificates curl
# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

2. Add the Docker Repository

This tells your system's package manager (apt) where to find the Docker packages.
# This is one single command, broken up with \ for readability
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

3. Install Docker

Now we install the engine, command-line tools (CLI), and the docker-compose plugin, which reads our blueprint file.
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

4. (CRITICAL) Add Your User to the docker Group

This is the most common failure point. The Docker "daemon" (the service) runs as root. By default, only the root user can interact with it. This step adds your user to the special docker group, granting you permission.
# Replace 'satoshis' with your own username
sudo usermod -aG docker satoshis
IMPORTANT: This permission change only applies to new terminal sessions. For the change to take effect, you MUST log out of your SSH session and log back in before proceeding.
exit

Phase 2: Prepare the Mempool Environment

After logging back in, we'll download the docker-compose.yml blueprint from the official Mempool project.
# Go to your home directory
cd ~
# Clone the project from GitHub
git clone https://github.com/mempool/mempool.git
# Move into the new docker directory
cd mempool/docker
You are now in the directory with the blueprint file we need to edit.

Phase 3: Find Your Host's "Secret Passageway" IP

This is a vital concept. Your new Mempool container is an isolated box. When it thinks of 127.0.0.1 (localhost), it's talking to itself, not to your main server.
To talk to your Bitcoin and Fulcrum nodes (which are on the "host" server), the container needs the host's IP address on the internal Docker network, known as docker0.
Run this command on your node to find it:
ip addr show docker0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1
The output will almost certainly be 172.17.0.1. This is the "secret passageway" from the container back to your main server.

Phase 4: Configure the docker-compose.yml Blueprint

It's time to write our blueprint. The default file is complex; we'll use a cleaner version tailored for our setup.
1. Back up the original file (just in case):
cp docker-compose.yml docker-compose.original.yml
2. Open the file for editing:
nano docker-compose.yml
3. Delete everything in that file and paste in this entire new configuration. I have commented every line to explain what it does. See my nano guide for help, or just follow the 3 commands below.
  1. ctrl + 6 marks the beginning of text to be cut
  2. ctrl + / + 999 jumps to the end whilst marking
  3. ctrl + k cuts the selected text
You must edit the CORE_RPC_USERNAME and CORE_RPC_PASSWORD to match your bitcoin.conf.
# This is the blueprint for our Mempool stack
# We removed 'version: "3.7"' as it's obsolete and causes a warning.

services:
  # 1. The Web Frontend (what you see)
  web:
    image: mempool/frontend:latest # Use the latest official image
    container_name: mempool-web
    restart: unless-stopped
    ports:
      # This connects your server's port 8080 to the container's port 8080
      # You will access your instance at http://YOUR_NODE_IP:8080
      - "8080:8080"
    environment:
      FRONTEND_HTTP_PORT: "8080"
      BACKEND_MAINNET_HTTP_HOST: "api" # Tells the frontend to get data from the 'api' container
    depends_on:
      - api # Won't start until the 'api' is running

  # 2. The Backend API (the brain)
  api:
    image: mempool/backend:latest
    container_name: mempool-api
    restart: unless-stopped
    depends_on:
      - db # Won't start until the 'db' is running
    volumes:
      - ./data:/data # Saves mempool's cache to your server's disk
    environment:
      # --- Connection to Fulcrum (Electrum) ---
      MEMPOOL_BACKEND: "electrum"
      ELECTRUM_HOST: "172.17.0.1"     # [REPLACE IF YOURS WAS DIFFERENT] The 'docker0' IP from Phase 3
      ELECTRUM_PORT: "50001"          # Your Fulcrum's unencrypted TCP port
      ELECTRUM_TLS_ENABLED: "false"

      # --- Connection to Bitcoin Core ---
      CORE_RPC_HOST: "172.17.0.1"     # [REPLACE IF YOURS WAS DIFFERENT] The 'docker0' IP from Phase 3
      CORE_RPC_PORT: "8332"
      
      # [REPLACE THESE VALUES]
      # These MUST match your bitcoin.conf
      CORE_RPC_USERNAME: "YOUR_USER_NAME"
      CORE_RPC_PASSWORD: "YOUR_VERY_STRONG_PASSWORD"

      # --- Connection to the Database ---
      DATABASE_HOST: "db"             # Tells the API to find the 'db' container
      DATABASE_DATABASE: "mempool"
      DATABASE_USERNAME: "mempool"
      DATABASE_PASSWORD: "mempool"

  # 3. The Database (the memory)
  db:
    image: mariadb:10.5               # A MariaDB (MySQL) database
    container_name: mempool-db
    restart: unless-stopped
    environment:
      MYSQL_DATABASE: "mempool"
      MYSQL_USER: "mempool"
      MYSQL_PASSWORD: "mempool"
      MYSQL_ROOT_PASSWORD: "admin"    # Internal password, you don't need to change this
    volumes:
      - ./mysql/data:/var/lib/mysql  # Saves the database to your server's disk
4. Save and Exit: Press Ctrl+X, then Y, then Enter.

Phase 5: Launch and Secure

The blueprint is written. This single command tells Docker to build, connect, and run all three containers in the background.
docker compose up -d
Common Sticking Point: "Permission Denied"
If you immediately get a permission denied while trying to connect to the Docker daemon socket error, it means you did not log out and log back in after Phase 1, Step 4.
The Fix:
  1. Log out: exit
  2. Log back in: ssh satoshis@node
  3. Go back to the directory: cd ~/mempool/docker
  4. Run the command again: docker compose up -d
Docker will now download the images. This may take a few minutes.

Let's fix the server's firewall settings.

# Open your server's firewall to allow access to the web frontend from your LAN.
sudo ufw allow 8080/tcp

# Allow the Docker host network
sudo ufw allow from 172.17.0.0/16 to any port 8332

# Allow the Docker Compose network
sudo ufw allow from 172.18.0.0/16 to any port 8332
sudo ufw reload

Phase 6: Access Your Private Mempool

You're done. You can check that all three containers are running with:
docker compose ps
You should see mempool-web, mempool-api, and mempool-db all in an "up" or "running" state.
Open a web browser on your desktop computer (not the server) and navigate to your node's IP address on port 8080.
  • If you are on your local network: http://192.168.8.50:8080 (Replace with your node's LAN IP)
  • If you are connecting via Tailscale (from anywhere): http://100.111.61.50:8080 (Replace with your node's Tailscale IP)
You will see your own private, self-hosted Mempool.space instance. It may take 5-10 minutes to populate its graphs and sync with your node, but you are now fully self-sovereign.

Maintenance: How to Stop and Update

  • To stop your Mempool instance:
    # Navigate to the blueprint directory
    cd ~/mempool/docker
    # Tell Docker to take the stack "down"
    docker compose down
    
  • To update to the latest version:
    cd ~/mempool/docker
    docker compose pull  # Downloads the latest images
    docker compose up -d # Restarts the stack with the new images
    
This is fantastic and v timely. Wish I would have found it before burning a day getting electrs installed. Thanks :)
reply
reply
40 sats \ 1 reply \ @Akg10s3 6h
Wow! Even though I still don't understand some of the terms, I saved the link to this guide in my LogSeq bookmarks because it's so comprehensive! And just by reading it, I learned something new today! It's great!
Thanks for posting it!
reply
you're welcome
reply
How stable is Fulcrum really? I read people complaining about database corruption.
edit: Just answered my own question by looking at the Fulcrum 2.0 release notes:
Fulcrum 2.x series will no longer suffer from this problem and the process can be killed at any time (including abrupt powerloss), without any database corruption. At worst the last few blocks worth of data is rolled-back and Fulcrum will re-synch from the rollback point.
reply
or you can run trezor's blockbook for the same result, which is in Go and not in dreadful javascript
reply