diff --git a/docker/.env.example b/docker/.env.example index ab5ca0fe..1bb75153 100644 --- a/docker/.env.example +++ b/docker/.env.example @@ -36,3 +36,17 @@ DAEMON_LOG_LEVEL=1 # POOL_API_PORT=2117 # LNS_HTTP_PORT=5553 # 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 diff --git a/docker/docker-compose.exit.yml b/docker/docker-compose.exit.yml new file mode 100644 index 00000000..b5962c6c --- /dev/null +++ b/docker/docker-compose.exit.yml @@ -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: diff --git a/docker/docker-compose.node.yml b/docker/docker-compose.node.yml new file mode 100644 index 00000000..a6613a21 --- /dev/null +++ b/docker/docker-compose.node.yml @@ -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: