feat(docker): add home node and exit node compose files
Some checks are pending
Build & Release / Linux x86_64 (push) Waiting to run
Build & Release / macOS ARM64 (push) Waiting to run
Build & Release / Create Release (push) Blocked by required conditions

docker-compose.node.yml — minimal chain node + wallet with PoS staking.
Home users run this to support the network and earn staking rewards.

docker-compose.exit.yml — full VPN exit node with WireGuard.
Home users run this to provide bandwidth via the Lethean dVPN and earn
LTHN. Includes chain node, wallet, WireGuard server, and a controller
that manages gateway peering and status reporting.

.env.example updated with exit node settings (public IP, name, max peers).

Co-Authored-By: Charon <charon@lethean.io>
This commit is contained in:
Claude 2026-04-03 12:14:05 +01:00
parent 1261d0d94e
commit 7af620e7f6
No known key found for this signature in database
GPG key ID: AF404715446AEB41
3 changed files with 285 additions and 0 deletions

View file

@ -36,3 +36,17 @@ DAEMON_LOG_LEVEL=1
# POOL_API_PORT=2117 # POOL_API_PORT=2117
# LNS_HTTP_PORT=5553 # LNS_HTTP_PORT=5553
# LNS_DNS_PORT=5354 # LNS_DNS_PORT=5354
# === Exit Node Settings (docker-compose.exit.yml) ===
# Your public IP address (required for VPN exit node)
# EXIT_PUBLIC_IP=auto
# Exit node name (registered as on-chain alias)
# EXIT_NAME=my-exit-node
# Maximum VPN peers (WireGuard clients)
# EXIT_MAX_PEERS=25
# Timezone
# TZ=Europe/London

View file

@ -0,0 +1,185 @@
# Lethean Exit Node
# Run a VPN exit node and earn LTHN by providing bandwidth to the network.
# Peers with Lethean gateways which route encrypted VPN traffic through your node.
#
# Usage:
# cp .env.example .env
# # Set WALLET_PASSWORD, EXIT_PUBLIC_IP, and EXIT_NAME
# docker compose -f docker-compose.exit.yml up -d
#
# What it does:
# - Runs a full chain node (syncs blockchain)
# - Runs a wallet with PoS staking
# - Runs a WireGuard VPN server
# - Registers as an exit node on-chain via alias
# - Peers with gateway nodes for traffic routing
# - Earns LTHN for bandwidth provided
#
# Requirements:
# - Public IP address (or port forwarding on router)
# - Open ports: 46942 (P2P), 51820/udp (WireGuard)
# - Linux with Docker (WireGuard kernel module)
#
# Ports:
# 46942 — P2P (chain peering)
# 51820 — WireGuard VPN (UDP)
# 8124 — Exit node management API (local only)
services:
# --- Chain Node ---
daemon:
image: lthn/chain:testnet
container_name: lthn-exit-daemon
restart: unless-stopped
ports:
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
networks:
exit-net:
# --- Wallet (PoS staking + payment receipt) ---
wallet:
image: lthn/chain:testnet
container_name: lthn-exit-wallet
restart: unless-stopped
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/exit.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/exit.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/exit.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
networks:
exit-net:
# --- WireGuard VPN Exit ---
wireguard:
image: lscr.io/linuxserver/wireguard:latest
container_name: lthn-exit-wireguard
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
environment:
PUID: 1000
PGID: 1000
TZ: ${TZ:-Europe/London}
SERVERURL: ${EXIT_PUBLIC_IP:-auto}
SERVERPORT: 51820
PEERS: ${EXIT_MAX_PEERS:-25}
PEERDNS: 1.1.1.1,1.0.0.1
INTERNAL_SUBNET: 10.13.13.0
ALLOWEDIPS: 0.0.0.0/0,::/0
LOG_CONFS: "false"
ports:
- "51820:51820/udp"
volumes:
- wireguard-config:/config
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
networks:
exit-net:
# --- Exit Node Controller ---
# Manages gateway peering, alias registration, and payment verification
controller:
image: lthn/chain:testnet
container_name: lthn-exit-controller
restart: unless-stopped
volumes:
- controller-data:/data
entrypoint:
- sh
- -c
command:
- |
echo "Lethean Exit Node Controller"
echo "Waiting for daemon and wallet..."
# Wait for daemon
until curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "Daemon ready"
# Wait for wallet
until curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json' > /dev/null 2>&1; do
sleep 5
done
echo "Wallet ready"
# Get wallet address
ADDR=$$(curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getaddress"}' -H 'Content-Type: application/json' | grep -oP '"address":"[^"]+' | cut -d'"' -f4)
echo "Exit node wallet: $$ADDR"
# Get chain height
HEIGHT=$$(curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' | grep -oP '"height":[0-9]+' | cut -d: -f2)
echo "Chain height: $$HEIGHT"
# Register alias if EXIT_NAME is set and we have balance
if [ -n "${EXIT_NAME:-}" ]; then
echo "Exit node name: ${EXIT_NAME}"
echo "To register on-chain: send 1 LTHN to this wallet, then alias will auto-register"
echo "Alias comment: v=lthn1;type=exit;cap=vpn,proxy;ip=${EXIT_PUBLIC_IP:-auto}"
fi
# Status loop
while true; do
BALANCE=$$(curl -sf http://wallet:36944/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getbalance"}' -H 'Content-Type: application/json' | grep -oP '"balance":[0-9]+' | cut -d: -f2)
HEIGHT=$$(curl -sf http://daemon:36941/json_rpc -d '{"jsonrpc":"2.0","id":"0","method":"getinfo"}' -H 'Content-Type: application/json' | grep -oP '"height":[0-9]+' | cut -d: -f2)
WG_PEERS=$$(curl -sf http://wireguard:51820 2>/dev/null | wc -l || echo 0)
echo "$$(date +%H:%M:%S) height=$$HEIGHT balance=$$(echo "scale=4; $$BALANCE/1000000000000" | bc 2>/dev/null || echo $$BALANCE) peers=$$WG_PEERS"
sleep 60
done
depends_on:
daemon:
condition: service_healthy
networks:
exit-net:
networks:
exit-net:
driver: bridge
volumes:
chain-data:
wallet-data:
wireguard-config:
controller-data:

View file

@ -0,0 +1,86 @@
# Lethean Home Node
# A self-contained chain node for home users who want to support the network.
# Syncs the chain, runs a wallet with PoS staking, and exposes P2P for peering.
#
# Usage:
# cp .env.example .env # edit WALLET_PASSWORD at minimum
# docker compose -f docker-compose.node.yml up -d
#
# What it does:
# - Syncs and validates the Lethean blockchain
# - Peers with other nodes (P2P port 46942)
# - Runs a wallet that stakes automatically (PoS mining)
# - Optionally mines with ProgPoWZ (connect external GPU miner)
#
# Earnings:
# - PoS staking rewards (proportional to balance)
# - PoW block rewards if mining
#
# Ports:
# 46941 — Daemon RPC (local tools)
# 46942 — P2P (open this on your router for full node)
# 46944 — Wallet RPC (local tools)
services:
daemon:
image: lthn/chain:testnet
container_name: lthn-node
restart: unless-stopped
ports:
- "${DAEMON_RPC_PORT:-46941}:36941"
- "${DAEMON_P2P_PORT:-46942}:36942"
volumes:
- chain-data:/data
entrypoint:
- lethean-chain-node
command:
- --data-dir
- /data
- --rpc-bind-ip
- "0.0.0.0"
- --rpc-bind-port
- "36941"
- --p2p-bind-port
- "36942"
- --rpc-enable-admin-api
- --allow-local-ip
- --log-level
- "${DAEMON_LOG_LEVEL:-1}"
- --disable-upnp
healthcheck:
test: ["CMD-SHELL", "curl -sf http://localhost:36941/json_rpc -d '{\"jsonrpc\":\"2.0\",\"id\":\"0\",\"method\":\"getinfo\"}' -H 'Content-Type: application/json' | grep -q OK"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
wallet:
image: lthn/chain:testnet
container_name: lthn-wallet
restart: unless-stopped
ports:
- "${WALLET_RPC_PORT:-46944}:36944"
volumes:
- wallet-data:/wallet
entrypoint:
- sh
- -c
command:
- |
if [ ! -f /wallet/node.wallet ]; then
echo '${WALLET_PASSWORD:-}' | lethean-wallet-cli --generate-new-wallet /wallet/node.wallet --password '${WALLET_PASSWORD:-}' --daemon-address daemon:36941 --command exit;
fi;
lethean-wallet-cli \
--wallet-file /wallet/node.wallet \
--password '${WALLET_PASSWORD:-}' \
--daemon-address daemon:36941 \
--rpc-bind-port 36944 \
--rpc-bind-ip 0.0.0.0 \
--do-pos-mining
depends_on:
daemon:
condition: service_healthy
volumes:
chain-data:
wallet-data: