Skip to content

Installation

WoompaLoompa edited this page Aug 9, 2026 · 13 revisions

Installation

Requirements

  • LNbits >= 1.5.6 (the background task manager differs between releases: the extension uses lnbits.task_manager when available and falls back to the legacy lnbits.tasks module on LNbits 1.5.x — both work, but nothing below 1.5.x has been tested).
  • Python >= 3.10 (whatever ships with your LNbits image).
  • A working Lightning backend configured in LNbits for the extension's wallet backend. See Lightning backend below.
  • Network access to the Nostr relays you configure (wss://…).

The extension adds no new Python dependencies. It reuses LNbits' bundled coincurve, websockets, and bech32 packages and LNbits' own Nostr utilities (lnbits.utils.nostr).

Installing

Option A — official release (v0.1.0 is published)

v0.1.0 is released. Once the registry pull request (lnbits/lnbits-extensions #830) is merged it will be installable from the LNbits extension manager:

  1. Log in to LNbits.
  2. Open Extensions and enable CLINK for your user.
  3. The extension appears under CLINK in the sidebar.

Until the PR is merged (or if you do not want to wait), use Option B.

The release pipeline automatically publishes GitHub releases and opens a pull request to the official lnbits/lnbits-extensions registry.

Option B — manual install (from the repository)

Until a release tag exists you can install the extension by placing the code in LNbits' extensions directory:

# Inside the LNbits app folder
cd extensions
git clone https://github.com/WoompaLoompa/lnbits-clink.git clink

Important: LNbits scans the directory <LNBITS_EXTENSIONS_PATH>/extensions/ (that is, it appends an extensions sub-folder to the configured path — the default lnbits gives lnbits/extensions). The extension folder must be named clink — LNbits derives the extension id from the folder name and imports it as the clink Python package. (The repository is named lnbits-clink only because GitHub disallows single-word lowercase repo names.)

Then restart LNbits. On a stock install (non-admin-gated extension) the extension is available to every user without per-user enablement.

Option C — repo manifest install (no registry wait)

The repository ships a top-level manifest.json ({"repos":[{"id":"clink","organisation":"WoompaLoompa","repository":"lnbits-clink"}]}). LNbits (>= 1.5.6) merges manifest URLs into the installable-extension listing, so clink becomes installable from the extension manager before the registry PR is merged — no manual copy needed:

# Add the manifest URL alongside the default registry manifest
LNBITS_EXTENSIONS_MANIFESTS="https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json,https://raw.githubusercontent.com/WoompaLoompa/lnbits-clink/main/manifest.json"

For each repo entry LNbits resolves the repository's releases/latest GitHub release and the config.json from its default branch to build an installable extension. The extension id comes from config.json["id"] (clink).

GitHub rate limits: manifest resolution calls the GitHub API (releases/latest) and is rate-limited to 60 requests/hour per IP for unauthenticated clients. A busy Fly machine shares its IP, so this budget is easily exhausted. Set LNBITS_EXT_GITHUB_TOKEN to a GitHub token (fine-grained, read-only Contents on the extension repo) to avoid intermittent failures — LNbits documents this setting as "required due to GitHub rate-limit":

fly secrets set -a <app> LNBITS_EXT_GITHUB_TOKEN=<token>

Fly.io install (verified)

The LNbits Docker image ships without extensions, and anything written to the container filesystem is lost on redeploy. Extensions must live on a persistent volume.

  1. Point LNBITS_EXTENSIONS_PATH at a path on your volume in fly.toml and redeploy:

    [env]
      LNBITS_EXTENSIONS_PATH = "/app/data/extensions"

    LNbits creates <path>/extensions/ automatically on startup.

  2. Upload the code. git is usually not installed in the container, so package the repo locally and push it over SFTP:

    tar czf clink.tgz --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' \
      -C /path/to/lnbits-clink .
    printf 'put clink.tgz /tmp/clink.tgz\nbye\n' | fly ssh sftp shell -a clink-lnbits
  3. Extract it into the volume (note the nested extensions folder):

    fly ssh console -a clink-lnbits -C 'sh -s' <<'EOF'
    mkdir -p /app/data/extensions/extensions/clink
    tar xzf /tmp/clink.tgz -C /app/data/extensions/extensions/clink
    rm /tmp/clink.tgz
    ls /app/data/extensions/extensions/clink/config.json
    EOF
  4. Restart the machine so LNbits discovers the extension and runs migrations:

    fly machine restart <machine-id> -a clink-lnbits
  5. Verify (see Verifying the install).

Notes specific to Fly

  • Extensions stored under /app/data/... survive fly deploy and machine restarts because the volume is persistent.
  • The LNbits extension builder in the admin UI (/extensions/builder) can only build from the official registry — it cannot import an existing repo, so it is not usable for this extension.
  • On the demo app clink-lnbits the Lightning backend is FakeWallet (LNBITS_BACKEND_WALLET_CLASS=FakeWallet): invoices are created in-memory and always "payable", which is enough to exercise the full UI/protocol flow but does not move real funds. Swap it for a real backend to settle actual Lightning payments.
  • The demo app runs both manifests: LNBITS_EXTENSIONS_MANIFESTS="https://raw.githubusercontent.com/lnbits/lnbits-extensions/main/extensions.json,https://raw.githubusercontent.com/WoompaLoompa/lnbits-clink/main/manifest.json", so clink shows up in the extension manager there.

Superadmin setup (first run)

The superadmin flow differs from the old per-user extension toggle:

  1. With LNBITS_ADMIN_UI=true, LNbits auto-generates a superuser on first run and stores it in <data>/data/.super_user. Read it over SSH:

    fly ssh console -a clink-lnbits -C 'cd /app && uv run lnbits-cli superuser'
  2. Open https://<your-lnbits>/admin and log in as the superuser (or use lnbits-cli superuser-url to get a ?usr=<id> deep link).

  3. Create a wallet/user to click around with:

    fly ssh console -a clink-lnbits -C 'sh -s' <<'EOF'
    cd /app
    uv run lnbits-cli users new -u alice -p change-me
    EOF
  4. Log in as that user at the dashboard. On LNbits 1.5.x, a non-admin-gated extension like clink is enabled for every user automatically — the per-user extensions list in the admin API only gates extensions listed in LNBITS_ADMIN_EXTENSIONS. The CLINK pages are then reachable at /clink/pay and /clink/subscriptions.

Configuration

The extension has no environment variables of its own. It is a plain LNbits extension:

  • Backend wallet: it uses whatever wallet backend LNbits is configured with (LNBITS_BACKEND_WALLET_CLASS). The public checkout, debit settlement, and subscriptions all call create_invoice/pay_invoice on that backend.
  • First relay: you add relays from the UI or the API (/clink/api/v1/relays). Nothing works until at least one relay is enabled.

Lightning backend

For a real end-to-end experience (actually creating and paying Lightning invoices) you need a real Lightning backend such as:

  • LND (LNDWallet)
  • Core Lightning (CoreLightningWallet)
  • Eclair (EclairWallet)
  • A remote service such as Alby (AlbyWallet)

The default VoidWallet backend reports "cannot create invoices" — it is only useful for exercising the protocol layer, not for payments. FakeWallet (in-memory) lets you walk the full checkout/subscription UI flow.

Verifying the install

# Public info endpoint: relay list + listener state
curl https://<your-lnbits>/clink/api/v1/info

# Auth-protected pages (401 without a user context is expected)
curl -i https://<your-lnbits>/clink/pay

# In the container
uv run lnbits-cli extensions list
#   Installed extensions:
#     - clink (0.0)

On startup the LNbits log confirms migrations and background tasks:

running migration clink.1
running migration clink.2
running migration clink.3
✔️ All migrations done.
clink: listener task started
clink: subscription poller started

Clone this wiki locally