PoS mining requires this flag when the daemon has no peers. Without it, the daemon's get_pos_mining_details RPC returns DISCONNECTED status and the wallet refuses to mint. First PoS blocks minted on testnet at height 12,382. Co-Authored-By: Charon <charon@lethean.io>
186 lines
5.9 KiB
YAML
186 lines
5.9 KiB
YAML
# 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
|
|
- --rpc-ignore-offline
|
|
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:
|