Deploying Namecoin Core + ElectrumX on Debian: A Verified Setup Guide
Deploying Namecoin Core + ElectrumX on Debian
Running your own Namecoin full node and ElectrumX server strengthens the network and gives you sovereign access to name resolution. This guide covers automated deployment of both on Debian, with proper binary verification.
The full guide and script are part of PR #749 to the Namecoin docs site.
What Gets Deployed
- Namecoin Core 28.0 — full node with
txindex=1for ElectrumX compatibility - Namecoin ElectrumX on the
protocol-1.4.3-v1branch (with WebSocket fix)
┌──────────────────────────────────────────────────────────┐
│ Your Debian Server │
│ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ Namecoin Core │ RPC │ ElectrumX │ │
│ │ (namecoind) │◄─────►│ (protocol-1.4.3-v1) │ │
│ │ │:8336 │ │ │
│ │ txindex=1 │ │ COIN=Namecoin │ │
│ │ Full blockchain │ │ │ │
│ └─────────────────┘ └──────┬───────┬────────────┘ │
│ │ │ │
│ :50001│ :50002│ :50003│ :50004│ │
│ TCP │ SSL │ WS │ WSS │ │
└──────────────────────────────┼───────┼───────┼───────┼────────┘
│ │ │ │
┌──────┴───────┴───────┴───────┴──┐
│ Electrum-NMC / Web browsers │
│ (remote clients) │
└──────────────────────────────────┘
Binary Verification: Guix Signatures
The script doesn’t just download and run binaries. It clones namecoin/guix.sigs and performs three verification steps:
1. Reproducibility check — Multiple independent builders compile Namecoin Core from source using Guix (a deterministic build system). Each builder publishes a noncodesigned.SHA256SUMS file listing the SHA-256 hash of every build artifact. The script diffs all of these against each other. If they’re byte-identical, the build is reproducible: independent people got the exact same binary output from the same source.
2. GPG signature verification — Each builder signs their SHA256SUMS with their personal GPG key. The script verifies each .asc detached signature. If you haven’t imported the builder’s key, it tells you the fingerprint so you can:
gpg --keyserver hkps://keys.openpgp.org --recv-keys <FINGERPRINT>
3. SHA-256 hash match — The downloaded tarball is hashed and compared against the attested value. A match means your binary is identical to what the builders independently compiled.
This is the gold standard for verifying open-source binaries. You’re not trusting the download server — you’re trusting the reproducible build process and the builders’ GPG identities.
The Deployment Script
Usage:
chmod +x deploy-namecoin-electrumx.sh
sudo ./deploy-namecoin-electrumx.sh [--skip-core] [--skip-electrumx] [--testnet] [--tor]
#!/usr/bin/env bash
# deploy-namecoin-electrumx.sh
#
# Deploys a verified Namecoin Core 28.0 node + Namecoin ElectrumX (protocol-1.4.3-v1)
# accessible to Electrum-NMC clients over the internet on Debian.
#
# Usage:
# sudo ./deploy-namecoin-electrumx.sh [--skip-core] [--skip-electrumx] [--testnet]
#
# Prerequisites:
# - Debian 12 (bookworm) or later, freshly installed
# - Root or sudo access
# - At least 20GB free disk (SSD strongly recommended)
# - At least 4GB RAM (8GB recommended)
#
# What this script does:
# Phase 1: Downloads Namecoin Core 28.0 binary for your architecture
# Phase 2: Verifies it against guix.sigs (GPG + SHA256 + reproducibility diff)
# Phase 3: Installs and configures Namecoin Core as a systemd service
# Phase 4: Clones, installs, and configures Namecoin ElectrumX (protocol-1.4.3-v1)
# Phase 5: Generates a self-signed SSL cert and opens firewall ports
# Phase 6: Optionally configures a Tor hidden service
#
# After running, Namecoin Core will begin syncing the blockchain. ElectrumX will
# start indexing once the daemon is caught up. Full sync takes hours to days
# depending on hardware.
set -euo pipefail
export LC_ALL=C
# ─────────────────────────────────────────────
# Configuration — edit these before running
# ─────────────────────────────────────────────
NMC_VERSION="28.0"
NMC_DOWNLOAD_BASE="https://www.namecoin.org/files/namecoin-core/namecoin-core-${NMC_VERSION}"
GUIX_SIGS_REPO="https://github.com/namecoin/guix.sigs.git"
ELECTRUMX_REPO="https://github.com/namecoin/electrumx.git"
ELECTRUMX_BRANCH="protocol-1.4.3-v1"
# RPC credentials — CHANGE THESE
RPC_USER="nmcrpc"
RPC_PASS="$(head -c 32 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 32)"
# Network
NET="mainnet"
ELECTRUMX_TCP_PORT=50001
ELECTRUMX_SSL_PORT=50002
ELECTRUMX_WS_PORT=50003
ELECTRUMX_WSS_PORT=50004
# Directories
NMC_DATADIR="/home/namecoin/.namecoin"
ELECTRUMX_DBDIR="/home/electrumx/db"
# Parse arguments
SKIP_CORE=0
SKIP_ELECTRUMX=0
SETUP_TOR=0
for arg in "$@"; do
case "$arg" in
--skip-core) SKIP_CORE=1 ;;
--skip-electrumx) SKIP_ELECTRUMX=1 ;;
--testnet) NET="testnet" ;;
--tor) SETUP_TOR=1 ;;
--help|-h)
echo "Usage: sudo $0 [--skip-core] [--skip-electrumx] [--testnet] [--tor]"
exit 0
;;
esac
done
# ─────────────────────────────────────────────
# Helper functions
# ─────────────────────────────────────────────
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
info() { echo -e "${BLUE}[INFO]${NC} $*"; }
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
check_root() {
if [[ $EUID -ne 0 ]]; then
fail "This script must be run as root (use sudo)"
fi
}
detect_arch() {
local machine
machine="$(uname -m)"
case "$machine" in
x86_64) ARCH="x86_64-linux-gnu" ;;
aarch64) ARCH="aarch64-linux-gnu" ;;
armv7l) ARCH="arm-linux-gnueabihf" ;;
riscv64) ARCH="riscv64-linux-gnu" ;;
ppc64) ARCH="powerpc64-linux-gnu" ;;
*) fail "Unsupported architecture: $machine" ;;
esac
NMC_TARBALL="namecoin-${NMC_VERSION}-${ARCH}.tar.gz"
NMC_URL="${NMC_DOWNLOAD_BASE}/${NMC_TARBALL}"
info "Detected architecture: $ARCH"
}
# ─────────────────────────────────────────────
# Phase 0: Install system dependencies
# ─────────────────────────────────────────────
install_deps() {
info "Installing system dependencies..."
apt-get update -qq
apt-get install -y -qq \
gnupg curl wget git \
python3 python3-pip python3-dev python3-venv \
build-essential libleveldb-dev libssl-dev \
openssl \
> /dev/null 2>&1
ok "System dependencies installed"
}
# ─────────────────────────────────────────────
# Phase 1: Download Namecoin Core binary
# ─────────────────────────────────────────────
download_core() {
local workdir="/tmp/namecoin-deploy"
mkdir -p "$workdir"
cd "$workdir"
if [[ -f "$NMC_TARBALL" ]]; then
info "Tarball already exists: $NMC_TARBALL"
else
info "Downloading Namecoin Core ${NMC_VERSION} for ${ARCH}..."
wget -q --show-progress "$NMC_URL" -O "$NMC_TARBALL" \
|| fail "Download failed. Check your architecture and network."
ok "Downloaded $NMC_TARBALL"
fi
}
# ─────────────────────────────────────────────
# Phase 2: Verify against guix.sigs
# ─────────────────────────────────────────────
verify_guix_sigs() {
local workdir="/tmp/namecoin-deploy"
cd "$workdir"
info "Cloning guix.sigs repository..."
if [[ -d guix.sigs ]]; then
cd guix.sigs && git pull -q && cd ..
else
git clone -q "$GUIX_SIGS_REPO"
fi
local sigdir="guix.sigs/${NMC_VERSION}"
if [[ ! -d "$sigdir" ]]; then
fail "No guix.sigs found for version ${NMC_VERSION}"
fi
# Collect all signers
local signers=()
for d in "$sigdir"/*/; do
[[ -d "$d" ]] && signers+=("$(basename "$d")")
done
if [[ ${#signers[@]} -eq 0 ]]; then
fail "No attestations found in $sigdir"
fi
info "Found ${#signers[@]} attestation(s): ${signers[*]}"
# ── Step 1: Reproducibility check ──
# All signers' SHA256SUMS files must be byte-identical.
# This proves the build is reproducible: independent builders got the same output.
info "Checking reproducibility (all attestations must be identical)..."
local reference="${sigdir}/${signers[0]}/noncodesigned.SHA256SUMS"
local repro_ok=1
for signer in "${signers[@]:1}"; do
local current="${sigdir}/${signer}/noncodesigned.SHA256SUMS"
if ! diff -q "$reference" "$current" > /dev/null 2>&1; then
warn "MISMATCH: ${signers[0]} vs $signer — SHA256SUMS files differ!"
repro_ok=0
fi
done
if [[ $repro_ok -eq 1 ]]; then
ok "Reproducibility check passed: all ${#signers[@]} attestations are identical"
else
fail "Reproducibility check FAILED — builds are not identical across signers"
fi
# ── Step 2: GPG signature verification ──
# Each signer's .asc is a detached GPG signature over their SHA256SUMS.
# We try to verify each one. If the public key isn't in our keyring,
# we warn but don't fail — the user may only trust specific signers.
info "Verifying GPG signatures..."
local gpg_good=0
local gpg_unknown=0
for signer in "${signers[@]}"; do
local sums="${sigdir}/${signer}/noncodesigned.SHA256SUMS"
local sig="${sums}.asc"
if [[ ! -f "$sig" ]]; then
warn "No .asc for signer '$signer', skipping"
continue
fi
# Try to verify; capture output
local gpg_out
if gpg_out=$(gpg --batch --verify "$sig" "$sums" 2>&1); then
ok "GPG signature VALID for signer: $signer"
gpg_good=$((gpg_good + 1))
else
if echo "$gpg_out" | grep -q "No public key"; then
warn "GPG key not in keyring for signer: $signer"
warn " Fingerprint from signature:"
echo "$gpg_out" | grep -oP 'RSA key \K[A-F0-9]+' | head -1 | sed 's/^/ /'
warn " Import with: gpg --keyserver hkps://keys.openpgp.org --recv-keys <FINGERPRINT>"
gpg_unknown=$((gpg_unknown + 1))
else
warn "GPG signature FAILED for signer: $signer"
echo "$gpg_out" | sed 's/^/ /'
fi
fi
done
if [[ $gpg_good -eq 0 && $gpg_unknown -eq ${#signers[@]} ]]; then
warn "No GPG keys in keyring — cannot verify signatures."
warn "The SHA256 hashes still match across all signers (reproducibility OK)."
warn "For full verification, import at least one signer's GPG key and re-run."
echo ""
echo " Signers who attested to this build:"
for signer in "${signers[@]}"; do
local sig="${sigdir}/${signer}/noncodesigned.SHA256SUMS.asc"
local fpr
fpr=$(gpg --batch --verify "$sig" "${sig%.asc}" 2>&1 | grep -oP 'RSA key \K[A-F0-9]+' | head -1 || true)
echo " $signer (key: ${fpr:-unknown})"
done
echo ""
read -rp "Continue anyway with SHA256 verification only? [y/N] " reply
[[ "$reply" =~ ^[Yy]$ ]] || fail "Aborted by user"
elif [[ $gpg_good -gt 0 ]]; then
ok "GPG verification: $gpg_good valid signature(s)"
fi
# ── Step 3: SHA256 hash verification ──
# Check the downloaded binary against the attested hashes.
info "Verifying SHA256 hash of downloaded binary..."
local expected_hash
expected_hash=$(grep "$NMC_TARBALL" "$reference" | awk '{print $1}')
if [[ -z "$expected_hash" ]]; then
fail "Binary '$NMC_TARBALL' not found in SHA256SUMS"
fi
local actual_hash
actual_hash=$(sha256sum "$workdir/$NMC_TARBALL" | awk '{print $1}')
if [[ "$expected_hash" == "$actual_hash" ]]; then
ok "SHA256 match: $actual_hash"
ok "Binary verification PASSED"
else
fail "SHA256 MISMATCH!\n Expected: $expected_hash\n Got: $actual_hash"
fi
}
# ─────────────────────────────────────────────
# Phase 3: Install and configure Namecoin Core
# ─────────────────────────────────────────────
install_core() {
local workdir="/tmp/namecoin-deploy"
cd "$workdir"
info "Installing Namecoin Core ${NMC_VERSION}..."
# Extract
tar xzf "$NMC_TARBALL"
local extracted="namecoin-${NMC_VERSION}"
# Install binaries
install -m 0755 -o root -g root \
"${extracted}/bin/namecoind" \
"${extracted}/bin/namecoin-cli" \
"${extracted}/bin/namecoin-tx" \
/usr/local/bin/
# Also install namecoin-qt if present (headless servers won't use it)
if [[ -f "${extracted}/bin/namecoin-qt" ]]; then
install -m 0755 -o root -g root "${extracted}/bin/namecoin-qt" /usr/local/bin/
fi
ok "Binaries installed to /usr/local/bin/"
# Create user
if ! id -u namecoin &>/dev/null; then
adduser --disabled-password --gecos "" namecoin
ok "Created user: namecoin"
fi
# Configure
mkdir -p "$NMC_DATADIR"
local rpc_port=8336
local p2p_port=8334
local nmc_conf="${NMC_DATADIR}/namecoin.conf"
if [[ "$NET" == "testnet" ]]; then
rpc_port=18336
p2p_port=18334
fi
cat > "$nmc_conf" <<NMCCONF
# Namecoin Core ${NMC_VERSION} configuration
# Generated by deploy-namecoin-electrumx.sh
# Network
$([ "$NET" == "testnet" ] && echo "testnet=1" || echo "# mainnet")
server=1
listen=1
txindex=1
# RPC
rpcuser=${RPC_USER}
rpcpassword=${RPC_PASS}
rpcallowip=127.0.0.1
rpcbind=127.0.0.1
# Performance
dbcache=450
maxmempool=300
# Logging
printtoconsole=0
NMCCONF
chown -R namecoin:namecoin "$NMC_DATADIR"
chmod 600 "$nmc_conf"
ok "Configuration written to $nmc_conf"
# Store RPC credentials for ElectrumX to read later
echo "${RPC_USER}:${RPC_PASS}:${rpc_port}" > /tmp/namecoin-deploy/rpc-creds
chmod 600 /tmp/namecoin-deploy/rpc-creds
# systemd service
cat > /etc/systemd/system/namecoind.service <<NMCSVC
[Unit]
Description=Namecoin Core Daemon
After=network-online.target
Wants=network-online.target
[Service]
Type=forking
User=namecoin
Group=namecoin
ExecStart=/usr/local/bin/namecoind -daemon -conf=${nmc_conf} -datadir=${NMC_DATADIR}
ExecStop=/usr/local/bin/namecoin-cli -conf=${nmc_conf} -datadir=${NMC_DATADIR} stop
TimeoutStopSec=600
Restart=on-failure
RestartSec=30
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
NMCSVC
systemctl daemon-reload
systemctl enable namecoind
systemctl start namecoind
ok "Namecoin Core started and enabled"
# Wait briefly and check
sleep 3
if systemctl is-active --quiet namecoind; then
local blockcount
blockcount=$(su - namecoin -c "namecoin-cli -conf=${nmc_conf} getblockcount" 2>/dev/null || echo "connecting...")
ok "Namecoin Core is running (blocks: $blockcount)"
else
warn "Namecoin Core may still be starting up — check: journalctl -fu namecoind"
fi
}
# ─────────────────────────────────────────────
# Phase 4: Install and configure ElectrumX
# ─────────────────────────────────────────────
install_electrumx() {
info "Installing Namecoin ElectrumX (${ELECTRUMX_BRANCH})..."
# Read RPC creds
local rpc_creds
if [[ -f /tmp/namecoin-deploy/rpc-creds ]]; then
rpc_creds=$(cat /tmp/namecoin-deploy/rpc-creds)
else
# Fallback: ask
echo "RPC credentials file not found."
read -rp "RPC user: " RPC_USER
read -rsp "RPC password: " RPC_PASS; echo
read -rp "RPC port [8336]: " rpc_port_input
rpc_creds="${RPC_USER}:${RPC_PASS}:${rpc_port_input:-8336}"
fi
local rpc_user rpc_pass rpc_port
IFS=: read -r rpc_user rpc_pass rpc_port <<< "$rpc_creds"
# Create user
if ! id -u electrumx &>/dev/null; then
adduser --disabled-password --gecos "" electrumx
ok "Created user: electrumx"
fi
# Clone repo on the correct branch
local exdir="/home/electrumx/electrumx"
if [[ -d "$exdir" ]]; then
cd "$exdir"
git fetch -q origin
git checkout -q "$ELECTRUMX_BRANCH"
git pull -q origin "$ELECTRUMX_BRANCH"
else
su - electrumx -s /bin/bash -c \
"git clone -b ${ELECTRUMX_BRANCH} ${ELECTRUMX_REPO} ${exdir}"
fi
ok "Cloned ElectrumX on branch: $ELECTRUMX_BRANCH"
# Python venv and install
info "Setting up Python virtual environment..."
su - electrumx -s /bin/bash -c "
cd ${exdir}
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip > /dev/null 2>&1
pip install . > /dev/null 2>&1
"
ok "ElectrumX installed in venv"
# Pin websockets<11 — required for WS/WSS transport
# websockets >=11 removed the legacy WebSocketServerProtocol API that
# aiorpcX depends on, causing immediate 1011 close on any WS connection.
# See: https://github.com/namecoin/electrumx/pull/1
info "Pinning websockets<11 for WebSocket transport compatibility..."
su - electrumx -s /bin/bash -c "
cd ${exdir}
source venv/bin/activate
pip install 'websockets>=6.0,<11' > /dev/null 2>&1
"
ok "websockets pinned (<11) — WS/WSS transport enabled"
# Create DB directory
mkdir -p "$ELECTRUMX_DBDIR"
chown electrumx:electrumx "$ELECTRUMX_DBDIR"
# Generate self-signed SSL certificate for Electrum-NMC clients
info "Generating self-signed SSL certificate..."
local ssl_dir="/home/electrumx/ssl"
mkdir -p "$ssl_dir"
openssl req -newkey rsa:2048 -sha256 -nodes \
-x509 -days 3650 \
-keyout "${ssl_dir}/server.key" \
-out "${ssl_dir}/server.crt" \
-subj "/CN=namecoin-electrumx" \
2>/dev/null
chown -R electrumx:electrumx "$ssl_dir"
chmod 600 "${ssl_dir}/server.key"
ok "SSL certificate generated"
# ElectrumX configuration
local daemon_url="http://${rpc_user}:${rpc_pass}@127.0.0.1:${rpc_port}/"
cat > /etc/electrumx.conf <<EXCONF
# Namecoin ElectrumX configuration
# Generated by deploy-namecoin-electrumx.sh
#
# Branch: ${ELECTRUMX_BRANCH}
COIN=Namecoin
NET=${NET}
DB_DIRECTORY=${ELECTRUMX_DBDIR}
DB_ENGINE=leveldb
DAEMON_URL=${daemon_url}
# Services — accessible from the internet
# tcp: plaintext Electrum protocol (port ${ELECTRUMX_TCP_PORT})
# ssl: encrypted Electrum protocol (port ${ELECTRUMX_SSL_PORT})
# ws: WebSocket (port ${ELECTRUMX_WS_PORT}) — for browser clients
# wss: WebSocket over TLS (port ${ELECTRUMX_WSS_PORT}) — for browser clients
# rpc: local admin RPC
SERVICES=tcp://:${ELECTRUMX_TCP_PORT},ssl://:${ELECTRUMX_SSL_PORT},ws://:${ELECTRUMX_WS_PORT},wss://:${ELECTRUMX_WSS_PORT},rpc://
# SSL
SSL_CERTFILE=${ssl_dir}/server.crt
SSL_KEYFILE=${ssl_dir}/server.key
# Advertise to peer discovery (edit with your public hostname/IP)
# REPORT_SERVICES=tcp://YOUR_PUBLIC_IP:${ELECTRUMX_TCP_PORT},ssl://YOUR_PUBLIC_IP:${ELECTRUMX_SSL_PORT}
# REPORT_HOST=YOUR_PUBLIC_IP
# Performance
CACHE_MB=1200
# EVENT_LOOP_POLICY=uvloop
# Rate limiting — set to 0 for private use, or leave defaults for public
COST_SOFT_LIMIT=0
COST_HARD_LIMIT=0
# Logging
LOG_LEVEL=info
EXCONF
chmod 600 /etc/electrumx.conf
ok "ElectrumX configuration written to /etc/electrumx.conf"
# Increase file descriptor limits
if ! grep -q "electrumx" /etc/security/limits.conf 2>/dev/null; then
echo "electrumx soft nofile 8192" >> /etc/security/limits.conf
echo "electrumx hard nofile 65536" >> /etc/security/limits.conf
fi
# systemd service
cat > /etc/systemd/system/electrumx.service <<EXSVC
[Unit]
Description=Namecoin ElectrumX Server (protocol-1.4.3-v1)
After=network.target namecoind.service
Requires=namecoind.service
[Service]
EnvironmentFile=/etc/electrumx.conf
ExecStart=${exdir}/venv/bin/python3 ${exdir}/electrumx_server
User=electrumx
Group=electrumx
LimitNOFILE=8192
TimeoutStopSec=30min
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target
EXSVC
systemctl daemon-reload
systemctl enable electrumx
systemctl start electrumx
ok "ElectrumX started and enabled"
sleep 3
if systemctl is-active --quiet electrumx; then
ok "ElectrumX is running"
else
warn "ElectrumX may be waiting for Namecoin Core to sync — check: journalctl -fu electrumx"
fi
}
# ─────────────────────────────────────────────
# Phase 5: Firewall
# ─────────────────────────────────────────────
configure_firewall() {
info "Configuring firewall..."
# Namecoin P2P
local p2p_port=8334
[[ "$NET" == "testnet" ]] && p2p_port=18334
if command -v ufw &>/dev/null; then
ufw allow "$p2p_port"/tcp comment "Namecoin P2P" > /dev/null 2>&1 || true
ufw allow "$ELECTRUMX_TCP_PORT"/tcp comment "ElectrumX TCP" > /dev/null 2>&1 || true
ufw allow "$ELECTRUMX_SSL_PORT"/tcp comment "ElectrumX SSL" > /dev/null 2>&1 || true
ufw allow "$ELECTRUMX_WS_PORT"/tcp comment "ElectrumX WS" > /dev/null 2>&1 || true
ufw allow "$ELECTRUMX_WSS_PORT"/tcp comment "ElectrumX WSS" > /dev/null 2>&1 || true
ok "UFW rules added"
elif command -v iptables &>/dev/null; then
iptables -A INPUT -p tcp --dport "$p2p_port" -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport "$ELECTRUMX_TCP_PORT" -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport "$ELECTRUMX_SSL_PORT" -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport "$ELECTRUMX_WS_PORT" -j ACCEPT 2>/dev/null || true
iptables -A INPUT -p tcp --dport "$ELECTRUMX_WSS_PORT" -j ACCEPT 2>/dev/null || true
ok "iptables rules added (not persisted — install iptables-persistent to save)"
else
warn "No firewall tool found — manually open ports $p2p_port, $ELECTRUMX_TCP_PORT, $ELECTRUMX_SSL_PORT, $ELECTRUMX_WS_PORT, $ELECTRUMX_WSS_PORT"
fi
}
# ─────────────────────────────────────────────
# Phase 6: Optional Tor hidden service
# ─────────────────────────────────────────────
setup_tor() {
info "Setting up Tor hidden service..."
apt-get install -y -qq tor > /dev/null 2>&1
# Add hidden service config if not already present
if ! grep -q "electrumx" /etc/tor/torrc 2>/dev/null; then
cat >> /etc/tor/torrc <<TORCONF
# Namecoin ElectrumX hidden service
HiddenServiceDir /var/lib/tor/electrumx/
HiddenServicePort ${ELECTRUMX_TCP_PORT} 127.0.0.1:${ELECTRUMX_TCP_PORT}
HiddenServicePort ${ELECTRUMX_SSL_PORT} 127.0.0.1:${ELECTRUMX_SSL_PORT}
HiddenServicePort ${ELECTRUMX_WS_PORT} 127.0.0.1:${ELECTRUMX_WS_PORT}
HiddenServicePort ${ELECTRUMX_WSS_PORT} 127.0.0.1:${ELECTRUMX_WSS_PORT}
TORCONF
systemctl restart tor
sleep 5
fi
local onion_file="/var/lib/tor/electrumx/hostname"
if [[ -f "$onion_file" ]]; then
local onion
onion=$(cat "$onion_file")
ok "Tor hidden service: $onion"
echo ""
echo " Add to /etc/electrumx.conf:"
echo " REPORT_HOST_TOR=${onion}"
echo " REPORT_TCP_PORT_TOR=${ELECTRUMX_TCP_PORT}"
echo " REPORT_SSL_PORT_TOR=${ELECTRUMX_SSL_PORT}"
else
warn "Tor hostname file not yet created — check: sudo systemctl status tor"
fi
}
# ─────────────────────────────────────────────
# Phase 7: Summary
# ─────────────────────────────────────────────
print_summary() {
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo -e " ${GREEN}Deployment complete${NC}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo " Namecoin Core ${NMC_VERSION}"
echo " Config: ${NMC_DATADIR}/namecoin.conf"
echo " Data: ${NMC_DATADIR}"
echo " Service: systemctl status namecoind"
echo " Logs: journalctl -fu namecoind"
echo " CLI: su - namecoin -c 'namecoin-cli getblockchaininfo'"
echo ""
echo " ElectrumX (${ELECTRUMX_BRANCH})"
echo " Config: /etc/electrumx.conf"
echo " Database: ${ELECTRUMX_DBDIR}"
echo " Service: systemctl status electrumx"
echo " Logs: journalctl -fu electrumx"
echo " TCP: port ${ELECTRUMX_TCP_PORT}"
echo " SSL: port ${ELECTRUMX_SSL_PORT}"
echo " WS: port ${ELECTRUMX_WS_PORT}"
echo " WSS: port ${ELECTRUMX_WSS_PORT}"
echo " SSL cert: /home/electrumx/ssl/server.crt"
echo ""
echo " RPC credentials (saved to /etc/electrumx.conf):"
echo " User: ${RPC_USER}"
echo " Password: (see /etc/electrumx.conf or ${NMC_DATADIR}/namecoin.conf)"
echo ""
echo " ┌─────────────────────────────────────────────────┐"
echo " │ IMPORTANT: Namecoin Core must fully sync │"
echo " │ before ElectrumX can index. This takes hours │"
echo " │ to days. Monitor with: │"
echo " │ │"
echo " │ journalctl -fu namecoind │"
echo " │ journalctl -fu electrumx │"
echo " │ │"
echo " │ Once synced, Electrum-NMC clients can connect: │"
echo " │ electrum-nmc --oneserver \\ │"
echo " │ --server YOUR_IP:${ELECTRUMX_SSL_PORT}:s │"
echo " └─────────────────────────────────────────────────┘"
echo ""
# Edit REPORT_SERVICES reminder
echo " To advertise your server for peer discovery, edit /etc/electrumx.conf:"
echo " REPORT_SERVICES=tcp://YOUR_IP:${ELECTRUMX_TCP_PORT},ssl://YOUR_IP:${ELECTRUMX_SSL_PORT},ws://YOUR_IP:${ELECTRUMX_WS_PORT},wss://YOUR_IP:${ELECTRUMX_WSS_PORT}"
echo " REPORT_HOST=YOUR_IP"
echo " Then: systemctl restart electrumx"
echo ""
# Cleanup
rm -f /tmp/namecoin-deploy/rpc-creds
}
# ─────────────────────────────────────────────
# Main
# ─────────────────────────────────────────────
main() {
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Namecoin Core + ElectrumX Deployment Script"
echo " Core: nc${NMC_VERSION} (from namecoin.org)"
echo " ElectrumX: ${ELECTRUMX_BRANCH}"
echo " Network: ${NET}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
check_root
detect_arch
install_deps
if [[ $SKIP_CORE -eq 0 ]]; then
download_core
verify_guix_sigs
install_core
else
info "Skipping Namecoin Core (--skip-core)"
fi
if [[ $SKIP_ELECTRUMX -eq 0 ]]; then
install_electrumx
configure_firewall
else
info "Skipping ElectrumX (--skip-electrumx)"
fi
if [[ $SETUP_TOR -eq 1 ]]; then
setup_tor
fi
print_summary
}
main "$@"
Flags:
| Flag | Effect |
|---|---|
--skip-core |
Skip Namecoin Core install (use existing daemon) |
--skip-electrumx |
Skip ElectrumX install (including WS/WSS) |
--testnet |
Deploy on testnet instead of mainnet |
--tor |
Configure a Tor hidden service |
What happens under the hood
- Phase 0 — Installs system dependencies (gnupg, python3, libleveldb-dev, etc.)
- Phase 1 — Auto-detects CPU architecture, downloads the matching Namecoin Core 28.0 tarball
- Phase 2 — Guix signature verification (reproducibility + GPG + SHA-256)
- Phase 3 — Installs
namecoind/namecoin-clito/usr/local/bin/, creates anamecoinsystem user, writesnamecoin.confwith random RPC credentials, starts systemd service - Phase 4 — Clones namecoin/electrumx on
protocol-1.4.3-v1, installs in a Python venv, configures as systemd service - Phase 5 — Generates a self-signed SSL certificate, opens firewall ports (50001 TCP, 50002 SSL, 50003 WS, 50004 WSS)
- Phase 6 — Optional Tor hidden service setup
Post-Deployment
After the script finishes, Namecoin Core begins syncing the blockchain. Once caught up, ElectrumX starts indexing.
Monitor progress:
# Namecoin Core sync
su - namecoin -c 'namecoin-cli getblockchaininfo' | grep -E 'blocks|verificationprogress'
# ElectrumX indexing
journalctl -fu electrumx
Test WebSocket from browser or CLI:
# WSS (recommended for production)
echo '{"jsonrpc":"2.0","method":"server.version","params":["test","1.4"],"id":1}' | \
websocat --insecure wss://YOUR_IP:50004
Connect from Electrum-NMC:
# SSL (recommended)
electrum-nmc --oneserver --server YOUR_IP:50002:s
# Via Tor
electrum-nmc --oneserver --server YOUR_ONION:50001:t --proxy socks5:127.0.0.1:9050
WebSocket Transport (WS/WSS)
WebSocket is the only Electrum transport available to browser-based clients — browsers cannot open raw TCP/TLS sockets. If you want web applications to query your ElectrumX server directly (for example, noStrudel resolving .bit Namecoin NIP-05 identities), WS/WSS must work.
The websockets version fix
The protocol-1.4.3-v1 branch declares aiorpcX[ws]>=0.18.3,<0.19 which pulls in the websockets Python package. However, neither aiorpcX nor ElectrumX pins an upper bound on websockets. A fresh pip install resolves to websockets 15.x, which completely rewrote the server handler API — the legacy WebSocketServerProtocol coroutine-based handler that aiorpcX uses was removed in websockets 11.0.
Result: WS/WSS connections upgrade successfully (HTTP 101) but immediately close with code 1011 (internal error) on any JSON-RPC frame. TCP and TLS work fine — only WebSocket is broken.
Fix: Pin websockets>=6.0,<11. The deployment script does this automatically. If you installed manually:
cd /home/electrumx/electrumx
source venv/bin/activate
pip install 'websockets>=6.0,<11'
sudo systemctl restart electrumx
See namecoin/electrumx PR #1 for the full analysis.
Verify WebSocket connectivity
# Test WS (plaintext)
echo '{"jsonrpc":"2.0","method":"server.version","params":["test","1.4"],"id":1}' | \
websocat ws://localhost:50003
# Test WSS (encrypted) — skip cert verify for self-signed
echo '{"jsonrpc":"2.0","method":"server.version","params":["test","1.4"],"id":1}' | \
websocat --insecure wss://localhost:50004
Requirements
- Debian 12+ (Ubuntu 22.04+ also works)
- 20 GB free disk (SSD strongly recommended)
- 4 GB RAM minimum (8 GB recommended)
- Root access
Supported architectures: x86_64, aarch64, armv7l, riscv64, ppc64.
Links
- PR: namecoin/namecoin.org#749
- Deployment script: deploy-namecoin-electrumx.sh
- Namecoin Core: namecoin.org/download
- Namecoin ElectrumX: github.com/namecoin/electrumx (branch:
protocol-1.4.3-v1) - WebSocket fix: namecoin/electrumx PR #1 — pin
websockets<11for WS/WSS transport - Browser use case: noStrudel PR #352 — Namecoin NIP-05 resolution in browser
- Guix signatures: github.com/namecoin/guix.sigs
Run your own infrastructure. Verify your own binaries. Trust the math, not the server.