Mempool Space

Mempool is a self-hosted Bitcoin blockchain and mempool visualizer/explorer. Look up your onchain transactions and estimate transaction fees without any privacy leaks.

Mempool Space preview

Preparations

Transaction indexing

For the Mempool Space to work, you need your full node to index all transactions.

  • If you followed this guide, the transaction index parameter is already enabled (txindex=1), and you can skip to the next section.
  • If this is not the case, you need to set the txindex=1 parameter in your Bitcoin client configuration file (bitcoin.conf): Bitcoin node configuration.
  • After adding the parameter, restart Bitcoin client, which will now index the whole blockchain
$SU rc-service bitcoind restart

Please note that reindexing can take more than a day. You can follow the progress using

tail -f /var/log/bitcoind/debug.log

Install dependencies

  • Install Node.js using the apk package manager.

These are build dependencies (safe to remove after installation, if you want)

$SU apk add --virtual .build-deps cargo git gnupg npm rsync

These are runtime dependencies

$SU apk add mariadb mariadb-client nodejs-current

Create the mempool user/group

$SU addgroup -S mempool
$SU adduser \
    -S \
    -D \
    -H \
    -h /dev/null \
    -s /sbin/nologin \
    -G mempool \
    -g mempool \
    mempool

Add mempool user to the bitcoin group

$SU adduser mempool bitcoin

Add satoshi user to the mempool group

$SU adduser satoshi mempool && exec su -l satoshi

Reverse proxy

In the Security section, we set up a reverse proxy. Now we can add the Mempool Space configuration.

  • Enable the reverse proxy to route external encrypted HTTPS traffic internally to the Mempool Space
$SU $EDITOR /etc/caddy/sites/mempool-space.caddy
/etc/caddy/sites/mempool-space.caddy
:4081 {
    import tls
    root /var/www/mempool/browser
 
    handle /api/v1/* {
        reverse_proxy 127.0.0.1:8999
    }
 
    handle /api/* {
        uri replace /api/ /api/v1/
        reverse_proxy 127.0.0.1:8999
    }
 
    handle {
        map {header.accept-language} {header_lang} {
            default "en-US"
            ~^ar "ar"
            ~^cs "cs"
            ~^da "da"
            ~^de "de"
            ~^en "en-US"
            ~^es "es"
            ~^fa "fa"
            ~^fi "fi"
            ~^fr "fr"
            ~^he "he"
            ~^hi "hi"
            ~^hr "hr"
            ~^hu "hu"
            ~^it "it"
            ~^ja "ja"
            ~^ka "ka"
            ~^ko "ko"
            ~^lt "lt"
            ~^mk "mk"
            ~^nb "nb"
            ~^ne "ne"
            ~^nl "nl"
            ~^pl "pl"
            ~^pt "pt"
            ~^ro "ro"
            ~^ru "ru"
            ~^sl "sl"
            ~^sv "sv"
            ~^th "th"
            ~^tr "tr"
            ~^uk "uk"
            ~^vi "vi"
            ~^zh "zh"
        }
 
        map {cookie.lang} {lang} {
            default {header_lang}
            ar "ar"
            cs "cs"
            da "da"
            de "de"
            en "en-US"
            es "es"
            fa "fa"
            fi "fi"
            fr "fr"
            he "he"
            hi "hi"
            hr "hr"
            hu "hu"
            it "it"
            ja "ja"
            ka "ka"
            ko "ko"
            lt "lt"
            mk "mk"
            nb "nb"
            ne "ne"
            nl "nl"
            pl "pl"
            pt "pt"
            ro "ro"
            ru "ru"
            sl "sl"
            sv "sv"
            th "th"
            tr "tr"
            uk "uk"
            vi "vi"
            zh "zh"
        }
 
        header {
            Cache-Control "public, no-transform, max-age=1800"
            Vary "Accept-Language, Cookie"
        }
 
        @lang-override path_regexp ^/([a-z]{2})/
        handle @lang-override {
            try_files {path} /{re.lang-override.1}/index.html /en-US{path} /en-US/index.html
        }
 
        handle {
            try_files {path} /{lang}{path} /en-US{path} /{lang}/index.html /en-US/index.html
        }
 
        file_server
    }
}
  • Reload Caddy
$SU rc-service caddy reload

Firewall

  • Configure the firewall to allow incoming HTTPS requests
$SU $EDITOR /etc/awall/optional/mempool.json
/etc/awall/optional/mempool.json
{
  "description": "Allow Mempool Space SSL",
 
  "filter": [
    {
      "in": "internet",
      "out": "_fw",
      "service": { "proto": "tcp", "port": 4081 },
      "action": "accept",
      "conn-limit": { "count": 10, "interval": 60 }
    }
  ]
}
  • Enable it
$SU awall enable mempool
$SU awall activate

Installation

Download source code

We get the latest release of the Mempool Space source code and install it.

  • Download the source code for the latest Mempool Space release. You can check the release page to see if a newer release is available. Other releases might not have been properly tested with the rest of the Microbolt configuration, though.
cd /tmp
VERSION=3.0.0
git clone --branch v$VERSION https://github.com/mempool/mempool.git && cd mempool

Signature check

  • To avoid using bad source code, verify that the release has been properly signed at least by one of the main developer wiz.
wget -qO- https://github.com/wiz.gpg | gpg --import
git verify-tag v$VERSION

MariaDB

MariaDB is an open source relational database.

  • First need to create initial databases and start the service
$SU rc-service mariadb setup
$SU rc-service mariadb start
  • These commands allow you to create a mempool database and grant privileges to mempool user directly from the command line
$SU mysql -e "create database mempool;"
$SU mysql -e "grant all privileges on mempool.* to 'mempool'@'localhost' identified via unix_socket;"

Backend

  • Install the backend dependencies and build the project
cd /tmp/mempool/backend
npm ci --omit=dev --omit=optional

Installation can take some time. There might be a lot of confusing output, but if you see something similar to the following, the installation was successful:

output
3 high severity vulnerabilities

To address all issues, run:
  npm audit fix

Run `npm audit` for details.
⚠️

At 2024-08-31 there is at least 3 high severity vulnerabilities not addressable without breaking changes

npm audit fix
  • Make it a global permanent installation
npm run package
mkdir ./package/bin
printf "%s\n" \
    "#!/bin/sh" \
    "node /var/lib/mempool/index.js" \
    > ./package/bin/cli.sh
chmod +x ./package/bin/cli.sh
$SU install -D -m 0660 -o mempool -g mempool ./mempool-config.sample.json /etc/mempool/mempool-config.json
$SU mv -f /tmp/mempool/backend/package /var/lib/mempool
$SU ln -s /var/lib/mempool /usr/lib/node_modules/mempool
$SU ln -s ../lib/node_modules/mempool/bin/cli.sh /usr/bin/mempool

Frontend

  • Install the frontend dependencies and build the project
cd /tmp/mempool/frontend
npm ci --omit=dev --omit=optional

Installation can take some time. There might be a lot of confusing output, but if you see something similar to the following, the installation was successful:

output
16 vulnerabilities (2 low, 4 moderate, 10 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.
⚠️

At 2024-08-31 there is at least 16 vulnerabilities not addressable without breaking changes

npm audit fix --force
  • Make it a global permanent installation
npm run build
$SU mv -f ./dist/mempool /var/www/

Cleanup

cd
rm -rf /tmp/mempool
$SU apk del .build-deps

Configuration

  • Check the configuration file and change highlighted values
$SU $EDITOR /etc/mempool/mempool-config.json
/etc/mempool/mempool-config.json
[...]
    "INDEXING_BLOCKS_AMOUNT": 52560,
[...]
    "STDOUT_LOG_MIN_PRIORITY": "info",
[...]
  "CORE_RPC": {
[...]
    "USERNAME": "",
    "PASSWORD": "",
[...]
    "COOKIE": true,
    "COOKIE_PATH": "/var/lib/bitcoind/.cookie"
  },
  "ESPLORA": {
    "REST_API_URL": "",
    "UNIX_SOCKET_PATH": "",
[...]
  "SECOND_CORE_RPC": {
    "HOST": "",
[...]
  "DATABASE": {
[...]
    "SOCKET": "/var/run/mysqld/mysqld.sock",
[...]
    "PASSWORD": "",
[...]
  "SOCKS5PROXY": {
    "ENABLED": true,
[...]
Redis

To use Redis caching, you need to install the redis package and configure the Mempool Space configuration file.

$SU apk add redis
/etc/mempool/mempool-config.json
[...]
  "REDIS": {
    "ENABLED": true,
    "UNIX_SOCKET_PATH": "/var/run/redis/redis.sock",
[...]
Remote access over Tor

To use your blockchain explorer when you’re on the go, you can easily create a Tor hidden service on the Microbolt and accessing the Mempool Space with the Tor browser from any device.

  • Add the following three lines in the “location-hidden services” section in the torrc file.
$SU $EDITOR /etc/tor/torrc
/etc/tor/torrc
# Hidden Service Mempool Space
HiddenServiceDir /var/lib/tor/mempool/
HiddenServiceVersion 3
HiddenServicePoWDefensesEnabled 1
HiddenServicePort 443 127.0.0.1:4081
  • Reload Tor configuration and get your connection address.
$SU rc-service tor reload
$SU cat /var/lib/tor/mempool/hostname
output
abcdefg..............xyz.onion
  • You should now be able to connect to your Mempool Space remotely via Tor using your hostname

Autostart on boot

Now we’ll make sure our blockchain explorer starts as a service on the computer so that it’s always running.

  • Create the Mempool Space init.d unit and copy/paste the following configuration. Save and exit.
$SU $EDITOR /etc/init.d/mempool
/etc/init.d/mempool
#!/sbin/openrc-run
 
: ${MEMPOOL_CONFIGFILE:=/etc/mempool/mempool-config.json}
: ${MEMPOOL_DATADIR:=/var/lib/mempool}
: ${MEMPOOL_LOGDIR:=/var/log/mempool}
: ${MEMPOOL_USER:=mempool}
: ${MEMPOOL_GROUP:=mempool}
: ${MEMPOOL_BIN:=/usr/bin/mempool}
: ${MEMPOOL_OPTS=${MEMPOOL_OPTS}}
: ${MEMPOOL_SIGTERM_TIMEOUT:=600}
 
MEMPOOL_PIDDIR="/run/mempool"
 
name="Mempool Space"
description="A self-hosted Bitcoin blockchain and mempool visualizer/explorer"
 
directory="${MEMPOOL_DATADIR}"
required_files="${MEMPOOL_CONFIGFILE}"
pidfile="${MEMPOOL_PIDDIR}/${SVCNAME}.pid"
retry="${MEMPOOL_SIGTERM_TIMEOUT}"
 
command="${MEMPOOL_BIN}"
command_args="${MEMPOOL_OPTS}"
command_user="${MEMPOOL_USER}:${MEMPOOL_GROUP}"
command_background="true"
 
start_stop_daemon_args="--env MEMPOOL_CONFIG_FILE=${MEMPOOL_CONFIGFILE}
                        --stdout ${MEMPOOL_LOGDIR}/debug.log
                        --stderr ${MEMPOOL_LOGDIR}/debug.log"
 
depend() {
    need bitcoind
    need mariadb
    checkdepend REDIS redis
 
    if service_started fulcrum; then
        need fulcrum
    elif service_started electrs; then
        need electrs
    else
        if service_exists fulcrum; then
            need fulcrum
        elif service_exists electrs; then
            need electrs
        else
            eerror "Neither fulcrum nor electrs is installed or started"
            return 1
        fi
    fi
}
 
checkdepend() {
    if sed -n '/^[[:space:]]*"'${1}'": {/,/^[[:space:]]*}/p' "${MEMPOOL_CONFIGFILE}" | grep -qs '"ENABLED": true'; then
        need "${2:-$1}"
    fi
}
 
service_exists() {
    rc-service --list | grep -q "^$1$"
}
 
start_pre() {
    checkpath --file      --mode 0660 --owner "${command_user}" "${MEMPOOL_CONFIGFILE}"
    checkpath --directory --mode 0750 --owner "${command_user}" "${MEMPOOL_DATADIR}"
    checkpath --directory --mode 0755 --owner "${command_user}" "${MEMPOOL_LOGDIR}"
    checkpath --directory --mode 0755 --owner "${command_user}" "${MEMPOOL_PIDDIR}"
}
 
stop() {
    ebegin "Stopping ${SVCNAME}"
    pkill -TERM -P "$(cat ${pidfile})" > /dev/null 2>&1
    start-stop-daemon \
        --stop \
        --pidfile="${pidfile}" \
        --retry="${MEMPOOL_SIGTERM_TIMEOUT}" \
        --exec="${MEMPOOL_BIN}"
    eend $?
}
  • Enable execution permission
$SU chmod +x /etc/init.d/mempool

Enable logrotate

  • Enter the complete next configuration. Save and exit
$SU $EDITOR /etc/logrotate.d/mempool
/etc/logrotate.d/mempool
/var/log/mempool/*.log {
    weekly
    missingok
    rotate 104
    compress
    delaycompress
    notifempty
    create 0640 mempool mempool
    sharedscripts
    postrotate
        kill -HUP `cat /run/mempool/mempool.pid`
    endscript
}
  • Test
$SU logrotate /etc/logrotate.d/mempool --debug

Enable and start Mempool Space

$SU rc-update add mempool
$SU rc-service mempool start
  • Check the log to see Mempool Space output. Exit with Ctrl-C
tail -f /var/log/mempool/debug.log
  • You can now access your own Mempool Space from within your local network by browsing to https://nakamoto01:4081 (or your equivalent IP address).

For the future: Mempool Space update

Follow again Mempool Space page replacing the environment variable VERSION=x.xx value for the latest if it has not been already changed in this guide.

  • Update the Mempool Space configuration if necessary (see release notes)
$SU $EDITOR /etc/mempool/mempool-config.json
  • Restart the service to apply the changes
$SU rc-service mempool restart