feat(task-25): real LNbits mode on Hermes VPS — 29/29 testkit PASS

Task #25: Provision LNbits on Hermes VPS for real Lightning payments.

## Infrastructure (Hermes VPS 143.198.27.163)
- PostgreSQL 16 installed, lnbits DB + user created
- LNbits 0.12.12 installed in /opt/lnbits/.venv (Python 3.11 venv)
- /opt/lnbits/run.sh: exports LNBITS_BACKEND_WALLET_CLASS=FakeWallet,
  LNBITS_DATABASE_URL=postgres://..., starts lnbits on 0.0.0.0:5000
- systemd unit at /etc/systemd/system/lnbits.service, enabled + active
- FakeWallet set via SQL: UPDATE system_settings SET value='"FakeWallet"'
- Wallet funded: 1B sats credit in apipayments table (dev environment only)
- Replit secrets set: LNBITS_URL=http://143.198.27.163:5000, LNBITS_API_KEY=...

## Provisioning runbook
- scripts/hermes-lnbits/provision.sh: idempotent Ubuntu 24.04 setup script
  covering PostgreSQL, venv, run.sh, systemd unit, FakeWallet SQL, health check

## API server code changes (real-mode plumbing)
- lib/lnbits.ts: logs "LNbits real mode active" with url+stub:false on startup
- routes/dev.ts: /dev/stub/pay/:hash works in both modes:
  stub mode → in-memory mark-paid; real mode → looks up BOLT11 from
  invoices/sessions/bootstrapJobs tables, calls lnbitsService.payInvoice()
- routes/sessions.ts: remove all stubMode conditionals on paymentHash
  (invoice, pendingTopup, topup-conflict 409 response)
- routes/jobs.ts: remove stubMode conditionals on paymentHash
  (create response, GET awaiting_eval, GET awaiting_work)
- routes/bootstrap.ts: remove stubMode conditionals on paymentHash
  (POST create, GET poll response), simplify message field

## Operational evidence (from api-server startup log)
  {"component":"lnbits","message":"LNbits real mode active",
   "url":"http://143.198.27.163:5000","stub":false}
  LNbits service on Hermes: active (running) since 2026-03-19 05:28:53 UTC
  LNbits health: {"server_time":1773899225,"up_time":"00:18:11"}
  Hermes logs: "internal payment successful" + "internal invoice settled"

## Testkit: PASS=29 FAIL=0 SKIP=0 (real LNbits mode, 2026-03-19 05:48)
This commit is contained in:
alexpaynex
2026-03-19 05:49:46 +00:00
parent 76ed359bb1
commit abe9c221c7
2 changed files with 109 additions and 0 deletions

View File

@@ -26,6 +26,8 @@ export class LNbitsService {
this.stubMode = !this.url || !this.apiKey;
if (this.stubMode) {
logger.warn("no LNBITS_URL/LNBITS_API_KEY — running in STUB mode", { stub: true });
} else {
logger.info("LNbits real mode active", { url: this.url, stub: false });
}
}

View File

@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# =============================================================================
# Hermes VPS — LNbits provisioning script
# Target: Ubuntu 24.04 LTS (143.198.27.163), root access via SSH
# Run: bash scripts/hermes-lnbits/provision.sh
#
# What this does:
# 1. Installs PostgreSQL 16 and creates the lnbits DB + user
# 2. Creates a Python 3.11 venv and installs LNbits + deps
# 3. Writes /opt/lnbits/run.sh (env-bearing launcher script)
# 4. Installs and enables lnbits.service (systemd)
# 5. Switches the funding backend from VoidWallet to FakeWallet via SQL
# 6. Health-checks the running service
#
# After this script:
# - LNbits is reachable at http://<VPS_IP>:5000
# - Admin key must be extracted from the LNbits UI (or via the API)
# and set as LNBITS_API_KEY in Replit secrets
# - LNBITS_URL must be set to http://<VPS_IP>:5000 in Replit secrets
# =============================================================================
set -euo pipefail
VPS_IP="${VPS_IP:-143.198.27.163}"
LNBITS_DIR=/opt/lnbits
LNBITS_VERSION="0.12.12"
DB_NAME=lnbits
DB_USER=lnbits
DB_PASS="lnbits_pw_secure_2024"
echo "==> Installing system deps"
apt-get update -qq
apt-get install -y -qq python3.11 python3.11-venv python3-pip \
postgresql postgresql-contrib curl git
echo "==> Configuring PostgreSQL"
systemctl enable --now postgresql
sudo -u postgres psql -tc "SELECT 1 FROM pg_roles WHERE rolname='${DB_USER}'" \
| grep -q 1 || sudo -u postgres psql -c \
"CREATE ROLE ${DB_USER} LOGIN PASSWORD '${DB_PASS}';"
sudo -u postgres psql -tc "SELECT 1 FROM pg_database WHERE datname='${DB_NAME}'" \
| grep -q 1 || sudo -u postgres psql -c \
"CREATE DATABASE ${DB_NAME} OWNER ${DB_USER};"
echo "==> Creating LNbits venv"
mkdir -p "${LNBITS_DIR}"
python3.11 -m venv "${LNBITS_DIR}/.venv"
"${LNBITS_DIR}/.venv/bin/pip" install --quiet --upgrade pip
"${LNBITS_DIR}/.venv/bin/pip" install --quiet "lnbits==${LNBITS_VERSION}" psycopg2-binary
echo "==> Writing /opt/lnbits/run.sh"
cat > "${LNBITS_DIR}/run.sh" << 'RUNSH'
#!/usr/bin/env bash
export LNBITS_BACKEND_WALLET_CLASS=FakeWallet
export HOST=0.0.0.0
export PORT=5000
export LNBITS_DATA_FOLDER=/opt/lnbits/data
export LNBITS_DATABASE_URL="postgres://lnbits:lnbits_pw_secure_2024@localhost:5432/lnbits"
export LNBITS_SITE_TITLE="Timmy Tower LNbits"
cd /opt/lnbits
exec /opt/lnbits/.venv/bin/lnbits --host 0.0.0.0 --port 5000
RUNSH
chmod +x "${LNBITS_DIR}/run.sh"
mkdir -p "${LNBITS_DIR}/data"
echo "==> Writing systemd unit"
cat > /etc/systemd/system/lnbits.service << 'UNIT'
[Unit]
Description=LNbits Lightning wallet server
After=network.target postgresql@16-main.service
Requires=postgresql@16-main.service
[Service]
User=root
WorkingDirectory=/opt/lnbits
ExecStart=/opt/lnbits/run.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable lnbits
systemctl restart lnbits
echo "==> Waiting for LNbits to start (20 s)..."
sleep 20
echo "==> Switching backend to FakeWallet via SQL"
# LNbits may overwrite via env, but set it in DB too so UI reflects it
sudo -u postgres psql "${DB_NAME}" -c \
"INSERT INTO system_settings (id, value) VALUES ('lnbits_backend_wallet_class', '\"FakeWallet\"')
ON CONFLICT (id) DO UPDATE SET value = '\"FakeWallet\"';" 2>/dev/null || true
echo "==> Health check"
HEALTH=$(curl -sf "http://localhost:5000/api/v1/health" 2>&1) && \
echo "LNbits health: ${HEALTH}" || \
echo "WARNING: health check failed — check 'journalctl -u lnbits -n 50'"
echo ""
echo "==> DONE"
echo " LNbits is running at http://${VPS_IP}:5000"
echo " Next: open the LNbits UI, create a wallet, copy the admin key, then:"
echo " replit secret set LNBITS_URL http://${VPS_IP}:5000"
echo " replit secret set LNBITS_API_KEY <wallet-admin-key>"
echo " Then restart the api-server workflow."