Feeling generous? Fund my lavish lifestyle 💅.

🔑 445F 8079 96F7 0586 B715 C7B8 A138 06B1 FA2A 676B / RSS

A Blog by Expatriotic

Dojo: Ashigaru Wallet Server

dojo-final

Dojo is the wallet backend for the Ashigaru wallet (formerly Samourai). It stores your extended public keys, handles BIP47 payment codes, and answers your wallet's questions about balances and history. Run it yourself and no third party ever sees your wallet's metadata.

This guide takes you from a standard Ubuntu machine to a working Dojo. Every command is given in full. Every step shows what the screen should look like when it works, and what to do when it does not. You do not need server experience. You do need patience: the first chain sync takes days.

If you are brand new to the terminal, read these two short guides of mine first: terminal basics and the nano editor.

There are two ways to build this, and you pick once, up front:

Either way you end at the same place: a Dojo your wallets pair to over Tor.

What you need before starting

Hardware:

Software: Ubuntu 26.04 LTS. A refurbished Optiplex, EliteDesk, or ThinkCentre is ideal. See my hardware guide.

Path B only: Bitcoin Core (with txindex=1) and Fulcrum already installed, synced, and running as services on this same machine. If that sentence means nothing to you yet, you want Path A.

How to read this guide:

One thing to know before anything else: sudo means "run this as administrator." The first time, it asks for your password. While you type it, the screen shows nothing. That is normal. Keep typing and press Enter.

Part 1: Prepare the machine

Update the system and install the tools we need:

cd ~/
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gnupg-agent software-properties-common unzip torsocks

torsocks is in that list because the download in Part 2 is done over Tor.

Now Docker. Skip this block if docker run hello-world already works on this machine.

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
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER

That last line adds your user to the docker group, so you will not need sudo for every docker command. It only takes effect after you log out and log back in. Do that now, then verify:

docker run hello-world

Healthy output starts with Hello from Docker!. If you do not see it, reboot once and try again before looking for deeper problems.

code

Part 2: Download and verify Dojo

This is money software, so we do not trust the download. We check two things: that the file came from the real developer (a PGP signature), and that it is the exact file released (a SHA256 hash). The full reasoning is in my guide on verifying software.

At the time of writing, the newest release is 1.29.3. Check the releases page of the Dojo-Open-Source-Project/samourai-dojo repository on GitHub. If a newer version exists, use that number everywhere you see 1.29.3 below.

cd ~/
DOJO_VER=1.29.3

That line creates a variable holding the version number, so the rest of the commands can reuse it.

Fetch the developer's signing key and the release itself, all over Tor:

torsocks wget https://keys.openpgp.org/vks/v1/by-fingerprint/E53AD419B242822F19E23C6D3033D463D6E544F6
gpg --import E53AD419B242822F19E23C6D3033D463D6E544F6
torsocks wget -O samourai-dojo-$DOJO_VER.zip https://github.com/Dojo-Open-Source-Project/samourai-dojo/archive/refs/tags/v$DOJO_VER.zip
torsocks wget https://github.com/Dojo-Open-Source-Project/samourai-dojo/releases/download/v$DOJO_VER/samourai-dojo-$DOJO_VER-fingerprints.txt
torsocks wget https://github.com/Dojo-Open-Source-Project/samourai-dojo/releases/download/v$DOJO_VER/samourai-dojo-$DOJO_VER-fingerprints.txt.sig

Check the signature:

gpg --verify samourai-dojo-$DOJO_VER-fingerprints.txt.sig

Healthy output looks like this (dates and names will differ):

gpg: Signature made Tue 01 Sep 22:28:00 2026 UTC
gpg: Good signature from "Developer Name" [unknown]

WARNING lines below that are normal and safe to ignore. The words that matter are Good signature. Anything else, like BAD signature, means stop. Delete everything and start Part 2 again.

Check the file itself:

sha256sum samourai-dojo-$DOJO_VER.zip
cat samourai-dojo-$DOJO_VER-fingerprints.txt

The first command prints one long string of letters and numbers, which is the fingerprint of your downloaded file. The second prints the official list of fingerprints. Find the line for the zip file in that list and compare the two strings, character for character. They must match exactly. If they do not, delete the zip and download it again.

Unpack:

unzip samourai-dojo-$DOJO_VER.zip -d .
mkdir -p ~/dojo-app
mv ~/samourai-dojo-$DOJO_VER/* ~/dojo-app/
rm -r samourai-dojo-$DOJO_VER samourai-dojo-$DOJO_VER.zip samourai-dojo-$DOJO_VER-fingerprints.txt samourai-dojo-$DOJO_VER-fingerprints.txt.sig E53AD419B242822F19E23C6D3033D463D6E544F6

You now have a folder called ~/dojo-app. Everything Dojo-related lives in there from now on.

Part 3: Generate your secrets

Dojo needs eight passwords before it will install. Make each one in your password manager (Bitwarden, KeePassXC, anything with a generator).

Settings for all eight:

Secret Goes in What it is for
BITCOIND_RPC_USER docker-bitcoind.conf.tpl Username for bitcoind's remote control
BITCOIND_RPC_PASS docker-bitcoind.conf.tpl Password for that username
MYSQL_ROOT_PASSWORD docker-mysql.conf.tpl Master password for the database
MYSQL_USER docker-mysql.conf.tpl Database account name
MYSQL_PASSWORD docker-mysql.conf.tpl Password for that account
NODE_API_KEY docker-node.conf.tpl Key wallets use to talk to Dojo
NODE_ADMIN_KEY docker-node.conf.tpl Your login for the Dojo dashboard
NODE_JWT_SECRET docker-node.conf.tpl Used to sign login sessions

One note: some releases name the bitcoind password line BITCOIND_RPC_PASSWORD instead of BITCOIND_RPC_PASS. Use whichever line already exists in your file.

Generate all eight now and keep the list open. After the install, the only one you need to keep in your password manager forever is NODE_ADMIN_KEY, because it is your dashboard login. The others live inside the config files and can be looked up there later.

About the config files: Dojo reads settings from template files that end in .tpl. You put your values into those, and the installer generates the real .conf files from them. Two rules:

The files live in ~/dojo-app/docker/my-dojo/conf/. Open one like this:

cd ~/dojo-app/docker/my-dojo/conf/
nano docker-mysql.conf.tpl

In nano, the text editor:

You will repeat that open, edit, save cycle for every file in Parts 5A and 5B.

Part 4: Find your numbers (the worksheet)

Machines on a network have addresses, like houses on a street. Docker builds its own private street inside your machine, and the addresses there are different from the ones on your home network. They also differ from person to person, so this guide cannot print yours. You will discover them now and write them on paper.

Run each command, compare with the sample output, and write your value into the worksheet at the end.

Your Docker host address. This is the address of the machine itself, as seen from inside Docker:

ip -4 addr show docker0

Sample output:

4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 ...
    inet 172.17.0.1/16 ...

Find the line that starts with inet. The number before the slash is your value. In the sample it is 172.17.0.1. Write it in as MY-DOCKER-IP.

Dojo's container network. The file you unpacked defines the private street's address range:

grep 'subnet:' ~/dojo-app/docker/my-dojo/docker-compose.yaml

Sample output:

        - subnet: 172.22.0.0/16
        - subnet: 172.23.0.0/16

The first line is the network called dojonet, where the Dojo containers live. Write the whole thing, slash included, as MY-DOJET-SUBNET. In the sample that is 172.22.0.0/16. The /16 means "this entire range of addresses," so keep it. Do not trim it down to a single address.

Your LAN address. This is the machine's address on your home network:

ip -4 addr show scope global

Find the block belonging to your wired network card (its name usually starts with enp or eth) and its inet line. Write the number before the slash as MY-LAN-IP. Ignore blocks for docker0, tailscale0, or anything starting with veth.

Your Tailscale address, if you run Tailscale:

tailscale ip -4

It will look like 100.something.something.something. Write it in as MY-TAILSCALE-IP. Skip this if you do not use Tailscale.

The worksheet. Copy this onto paper and fill it in:

MY-DOCKER-IP:        ______________________
MY-DOJONET-SUBNET:   ______________________
MY-LAN-IP:           ______________________
MY-TAILSCALE-IP:     ______________________

For reference, a typical machine might have 172.17.0.1, 172.22.0.0/16, 192.168.8.20, and 100.101.102.103. Yours will differ. Trust only what your own terminal printed.

If you run Tailscale, one rule keeps everything simple: Docker containers always reach the machine's services at MY-DOCKER-IP. They never use the 100.x address. Your other devices, like your laptop and phone, use MY-LAN-IP or MY-TAILSCALE-IP. Later, one config line asks which address wallets should use to reach your electrum service. That is a wallet question, not a Docker question: use MY-LAN-IP if the device connects over your Wi-Fi, MY-TAILSCALE-IP if it connects through the tailnet.

Part 5A: Path A, everything in Docker

Four files to edit, then one command. Move into the config folder:

cd ~/dojo-app/docker/my-dojo/conf/

File 1: bitcoind settings

nano docker-bitcoind.conf.tpl

Set BITCOIND_RPC_USER and BITCOIND_RPC_PASS to your first two secrets. If the machine has 16 GB of RAM or more, also set BITCOIND_DB_CACHE=2048, which speeds up the sync. Leave BITCOIND_INSTALL=on, which is the default. Save and exit.

File 2: database settings

nano docker-mysql.conf.tpl

Set MYSQL_ROOT_PASSWORD, MYSQL_USER, and MYSQL_PASSWORD. If your machine has only 8 GB of RAM, also set MYSQL_CONF_PROFILE=low_mem to keep the database frugal. Save and exit.

File 3: indexer settings

nano docker-indexer.conf.tpl

Set these lines:

INDEXER_INSTALL=on
INDEXER_TYPE=fulcrum
INDEXER_BATCH_SUPPORT=active
INDEXER_EXTERNAL=on
INDEXER_EXTERNAL_IP=<MY-LAN-IP>

The last line tells wallets where to find the electrum service. Use your MY-LAN-IP if other devices (your phone, your laptop) will use it. If everything that matters runs on this one machine, leave whatever default value is already in the file. Save and exit.

File 4: Dojo settings

nano docker-node.conf.tpl

Set NODE_API_KEY, NODE_ADMIN_KEY, and NODE_JWT_SECRET. Also set NODE_ACTIVE_INDEXER=local_indexer. Save and exit.

Install

cd ~/dojo-app/docker/my-dojo
if grep -q 'node:20-alpine' node/Dockerfile; then
  sed -i 's/node:20-alpine3.20/node:24-alpine3.22/g' node/Dockerfile
fi
./dojo.sh install

About that patch block: release 1.29.x ships with a packaging bug. The nodejs image is built on an old version of Node while the Dojo code needs a newer one, and without the fix the dashboard crashes after install. The check looks for the old version line and swaps in the new one. If a later release fixes the bug, the check finds nothing and changes nothing. It is safe on any version.

The installer asks whether you wish to continue. Type y and press Enter. It then builds the images. Expect 10 to 30 minutes of scrolling text.

When it finishes, the chain download starts on its own. Nothing to babysit. Check on it:

./dojo.sh logs bitcoind

Healthy output while downloading:

IBD progress = 0.051000 (5.1%)

Watch that percentage climb. Done is shown as progress = 1.000000. Press ctrl+c to stop watching. This only closes your view of the logs; the download keeps running. Then check the indexer:

./dojo.sh logs fulcrum

Fulcrum waits for bitcoind to finish, then builds its index. Look for a percentage climbing to 100. After both are done, the Dojo tracker catches up on wallet data, usually within a few hours.

Total time from install to fully green: 2 to 7 days, depending mostly on your internet. Leave the machine on. When you are done waiting, continue at Part 6.

Part 5B: Path B, borrow your existing node

The single line that matters in this path is BITCOIND_INSTALL=off. It tells the installer: do not download another copy of the chain, one already exists here. Everything else in this part is plumbing that lets the Docker containers reach your existing services.

Sanity check first:

sudo systemctl status bitcoind
sudo systemctl status fulcrum

Both must say active (running). If not, fix that before continuing.

5B.1: Let bitcoind accept visitors from Docker

bitcoind has a remote-control interface called RPC. By default it only accepts knocks from the machine itself. Containers knock from their own separate network, so we tell bitcoind two things: where to listen, and which visitors to trust.

nano /home/satoshis/.bitcoin/bitcoin.conf

(If your username is not satoshis, use your own in the path.) Add or change these lines. Leave everything else in the file alone:

rpcuser=satoshis
rpcpassword=Your40CharacterAlphanumericPassword
rpcbind=<MY-DOCKER-IP>
rpcallowip=127.0.0.1
rpcallowip=<MY-DOJONET-SUBNET>

zmqpubrawtx=tcp://<MY-DOCKER-IP>:28333
zmqpubhashblock=tcp://<MY-DOCKER-IP>:28334

Line by line:

If other software on this machine talks to bitcoind with the old RPC password, such as a block explorer, update its config with the new password too.

Restart and check:

sudo systemctl restart bitcoind
ss -ltnp | grep 8332

Healthy output: one line containing LISTEN and your MY-DOCKER-IP followed by :8332. If nothing prints, bitcoind did not load the new config. Run sudo systemctl status bitcoind and read the last few log lines for the reason.

5B.2: Open the firewall

If you use UFW, the default Ubuntu firewall, it blocks the containers' knocks. Allow the container range to reach three specific doors:

sudo ufw allow from <MY-DOJONET-SUBNET> to any port 8332 proto tcp comment 'Dojo to bitcoind RPC'
sudo ufw allow from <MY-DOJONET-SUBNET> to any port 28332:28334 proto tcp comment 'Dojo to bitcoind ZMQ'
sudo ufw allow from <MY-DOJONET-SUBNET> to any port 50001 proto tcp comment 'Dojo to Fulcrum'

The doors: 8332 is bitcoind's remote control, 28332 to 28334 are the announcement wires, 50001 is Fulcrum's electrum service. If you do not use UFW, skip this. If you run Tailscale and want tailnet devices to reach this machine:

sudo ufw allow in on tailscale0

Never forward any of these ports from your router to the internet. They are for your machine and your containers only.

5B.3: Configure the templates

Move into the config folder:

cd ~/dojo-app/docker/my-dojo/conf/

File 1, docker-bitcoind.conf.tpl:

BITCOIND_INSTALL=off
BITCOIND_IP=<MY-DOCKER-IP>
BITCOIND_RPC_PORT=8332
BITCOIND_ZMQ_RAWTXS=28333
BITCOIND_ZMQ_BLK_HASH=28334
BITCOIND_RPC_USER=satoshis
BITCOIND_RPC_PASS=Your40CharacterAlphanumericPassword

BITCOIND_INSTALL=off is the line that prevents the 700 GB re-download. BITCOIND_IP is where the containers knock, the same MY-DOCKER-IP as in 5B.1. The user and password must match your bitcoin.conf exactly.

Everything in this file under the headings about onion addresses, bloom filters, and exposing RPC switches itself off when BITCOIND_INSTALL=off. Do not spend time on those sections.

File 2, docker-indexer.conf.tpl:

INDEXER_INSTALL=off
INDEXER_TYPE=fulcrum
INDEXER_IP=<MY-DOCKER-IP>
INDEXER_RPC_PORT=50001
INDEXER_BATCH_SUPPORT=active
INDEXER_PROTOCOL=tcp
INDEXER_EXTERNAL=on
INDEXER_EXTERNAL_IP=<MY-LAN-IP>

INDEXER_INSTALL=off keeps Fulcrum on the metal. INDEXER_IP is where the containers find it. For the last line, choose by how your wallets reach this machine: MY-LAN-IP if they are on your Wi-Fi, MY-TAILSCALE-IP if they come through the tailnet.

File 3, docker-explorer.conf.tpl: set EXPLORER_INSTALL=off if you already run a block explorer such as mempool.space on this machine, because a second one is redundant. Otherwise leave it on and enjoy the built-in BTC-RPC Explorer.

File 4 and 5, docker-mysql.conf.tpl and docker-node.conf.tpl: the same secrets as Part 3, and in the node file set NODE_ACTIVE_INDEXER=local_indexer. The word "local" here means reachable, not containerized, so it stays correct on this path.

5B.4: Install

Same as Path A. Run the patch check and the installer:

cd ~/dojo-app/docker/my-dojo
if grep -q 'node:20-alpine' node/Dockerfile; then
  sed -i 's/node:20-alpine3.20/node:24-alpine3.22/g' node/Dockerfile
fi
./dojo.sh install

No chain download this time, because your node is already synced. The Dojo tracker reads your existing Fulcrum index and catches up, usually within hours.

Confirm what is running:

docker compose ps

Healthy output lists exactly four containers: db, nodejs, nginx, and tor. If bitcoind or fulcrum show up as containers, one of your INSTALL flags is still on; recheck 5B.3. If fewer than four show up, run ./dojo.sh logs and read the errors.

Part 6: Verify it works

Watch the logs:

./dojo.sh logs -f

Healthy signs within the first few minutes:

Importer : Successfully connected to indexer
Tracker : Processing active Mempool

Block heights should climb to the current tip. Press ctrl+c when you have seen enough; this only closes your view.

Bad signs, with fixes in Part 9: Bitcoind RPC : API is still unreachable, or connect ECONNREFUSED.

The dashboard. Dojo ships with a control panel called the Dojo Maintenance Tool, and it is reachable only through Tor. Get your address:

./dojo.sh onion

Sample output:

Dojo Maintenance Tool : abcdef...onion
Dojo API : ghijkl...onion

Take the Maintenance Tool line. In Tor Browser, which you can get from torproject.org, set the security level to Standard or Safer, because the page needs JavaScript. Paste that address into the address bar, add /admin to the end, and press Enter. The page asks for your admin key: paste NODE_ADMIN_KEY from your password manager and click CONNECT.

If the status page shows green checks next to Full Node, Indexer, Tracker, and Dojo DB, your Dojo is live. Orange checks during a first sync are normal and mean work in progress. Red crosses mean Part 9.

Part 7: Pair your wallets

In the Maintenance Tool, open the Pairing tab. A QR code appears. In the Ashigaru app, go to Settings, choose to connect to your own server, and scan that code. From then on, the wallet talks to your Dojo, over Tor, end to end.

Sparrow Wallet can use your stack too. Add the Dojo as a server in Sparrow, or skip Dojo entirely and point Sparrow's electrum server setting straight at Fulcrum: host MY-LAN-IP (or MY-TAILSCALE-IP), port 50001.

Part 8: Everyday use and updates

Commands you will actually use, run from ~/dojo-app/docker/my-dojo:

Command What it does
./dojo.sh logs Watch all logs; ctrl+c to exit the view
./dojo.sh stop Shut everything down cleanly
./dojo.sh start Start it again
./dojo.sh restart Stop, then start
./dojo.sh onion Show your Tor addresses again
./dojo.sh version Show the installed version
./dojo.sh help List every available command

Three rules that prevent pain:

Updating to a new release: repeat Part 2's download and verification with the new version number, then:

cd ~/dojo-app/docker/my-dojo
./dojo.sh stop
cp -a ~/samourai-dojo-$DOJO_VER/. ~/dojo-app/
grep DOJO_VERSION_TAG .env
./dojo.sh upgrade -y

That grep line is a check. It must print the new version number. If it still shows the old one, open .env in nano and change DOJO_VERSION_TAG by hand, or the upgrade will reinstall the version you already have. After any upgrade, run the patch check from Part 5A again, because the new files can bring the old bug back with them.

Part 9: Troubleshooting

Symptom What it means Fix
connect ECONNREFUSED, ending in :8332 bitcoind is not listening where Docker expects Check 5B.1: rpcbind must be MY-DOCKER-IP, and ss -ltnp must show LISTEN on it
Bitcoind RPC : API is still unreachable bitcoind heard the knock but does not trust the visitor rpcallowip must be the whole dojonet subnet. Run docker network inspect my-dojo_dojonet and match your rule to what it prints
Dashboard blank, or the nodejs container keeps restarting the Node version bug from Part 5A Apply the patch, then run docker compose build --no-cache node, then ./dojo.sh restart
Onion address will not load tor container is wedged docker restart tor
Fulcrum database corrupt after a power cut the machine lost power without ./dojo.sh stop Path A only: ./dojo.sh stop, docker container rm fulcrum, docker volume rm my-dojo_data-fulcrum, then ./dojo.sh upgrade. Expect 1 to 2 days of reindexing. On Path B, Fulcrum is a host service, so rebuild its database there
Fulcrum stuck for hours during an upgrade database migration to a new format Wait. Interrupting it corrupts the database

If nothing here matches your problem, copy the exact error line plus the ten lines around it from ./dojo.sh logs, and ask in the Ashigaru community with that paste.

Don't trust. Verify.

#bitcoin #guides #node #privacy #self-custody #self-hosting