-
Notifications
You must be signed in to change notification settings - Fork 0
Installation
-
LNbits
>= 1.5.6(the background task manager differs between releases: the extension useslnbits.task_managerwhen available and falls back to the legacylnbits.tasksmodule 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).
v0.1.1 is released (fixes the LNbits 1.5.x frontend window.g issue — see
Development). Once the registry pull request
(lnbits/lnbits-extensions #831)
is merged it will be installable from the LNbits extension manager:
- Log in to LNbits.
- Open Extensions and enable CLINK for your user.
- 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-extensionsregistry.
If you do not want to wait for the registry PR (or the extension manager is not available), install by placing the code in LNbits' extensions directory:
# Inside the LNbits app folder
cd extensions
git clone https://github.com/WoompaLoompa/lnbits-clink.git clinkImportant: 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.
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. SetLNBITS_EXT_GITHUB_TOKENto a GitHub token (fine-grained, read-onlyContentson 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>
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.
-
Point
LNBITS_EXTENSIONS_PATHat a path on your volume infly.tomland redeploy:[env] LNBITS_EXTENSIONS_PATH = "/app/data/extensions"
LNbits creates
<path>/extensions/automatically on startup. -
Upload the code.
gitis 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
-
Extract it into the volume (note the nested
extensionsfolder):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
-
Restart the machine so LNbits discovers the extension and runs migrations:
fly machine restart <machine-id> -a clink-lnbits
-
Verify (see Verifying the install).
- Extensions stored under
/app/data/...survivefly deployand 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-lnbitsthe Lightning backend isFakeWallet(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", soclinkshows up in the extension manager there.
The superadmin flow differs from the old per-user extension toggle:
-
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' -
Open
https://<your-lnbits>/adminand log in as the superuser (or uselnbits-cli superuser-urlto get a?usr=<id>deep link). -
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
-
Log in as that user at the dashboard. On LNbits 1.5.x, a non-admin-gated extension like
clinkis enabled for every user automatically — the per-userextensionslist in the admin API only gates extensions listed inLNBITS_ADMIN_EXTENSIONS. The CLINK pages are then reachable at/clink/payand/clink/subscriptions.
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 callcreate_invoice/pay_invoiceon 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.
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.
# 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
-
Blank/white extension pages (
/clink/pay,/clink/subscriptions) with a console error likeCannot read properties of undefined (reading 'user')mean the frontend read the oldthis.gobject. On LNbits 1.5.x extension pages must usewindow.ginstead (see Development). Use a release that includes the fix (v0.1.1+).
lnbits-clink — CLINK (Nostr-native Lightning) for LNbits.