No description
  • TypeScript 96%
  • JavaScript 2.9%
  • Dockerfile 0.7%
  • Just 0.4%
Find a file
Padreug 65a6966b9f
Some checks failed
Docker image / build-and-push-image (push) Has been cancelled
fix(#9): close race between create_new_key and NIP-46 connect
Two-layer fix for the issue where a fresh client chaining
create_new_key + NIP-46 connect on the same target key would
time out — bunker had no subscription registered for the new
key by the time the connect event arrived at the relay.

Layer 1 — run.ts: loadNsec and unlockKey were synchronous and
fire-and-forgot the async startKey promise. create_new_key.ts:35
already awaited loadNsec, but the await was a no-op against a sync
return. Promoted both to async and properly awaited startKey, so
backend.start() at least gets a chance to run before the caller's
response goes out.

Layer 2 — backend/index.ts: NDKNip46Backend.start() registers the
kind-24133 subscription via this.ndk.subscribe(...) but returns
immediately, before the relay's EOSE confirms it has the
subscription on file. Override start() in our Backend subclass to
await EOSE before resolving. This is the actual race-closer —
layer 1's await alone wasn't enough because start() was still
returning before the relay registered the subscription.

Surfaced by aiolabs/lnbits#33's eager-bind chain, which publishes
a NIP-46 connect event in the same HTTP round-trip as
create_new_key. Pre-fix lnbits deferred the connect to first
sign_event (minutes-to-hours after provisioning), so the race
window was hidden.

Verified end-to-end on bohm regtest: demo account creation through
the webapp now completes cleanly, with bunker logs showing
connect + sign_event for the freshly-provisioned key.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-30 12:25:45 +02:00
.github/workflows update main branch 2024-02-04 12:50:39 +00:00
prisma feat: use dynamic DATABASE_URL for Prisma db 2024-01-26 15:13:26 +00:00
scripts fix(start.js): resolve sibling paths from script location, not cwd 2026-05-27 17:05:24 +02:00
src fix(#9): close race between create_new_key and NIP-46 connect 2026-05-30 12:25:45 +02:00
templates absolutely no reason why the username needs to be readonly 2024-02-18 00:10:03 +00:00
.dockerignore feat: cleanup docker setup 2024-01-23 17:43:02 +00:00
.env.example feat: use dynamic DATABASE_URL for Prisma db 2024-01-26 15:13:26 +00:00
.eslintrc.json initial commit 2023-05-15 20:05:55 +02:00
.gitignore gitignore 2024-09-21 13:45:11 -04:00
.prettierrc.json Replace auth request js method, change prettierrc to handle handlebar templates better 2024-02-01 11:22:10 +01:00
CONFIGURATION.md create_account work 2023-12-20 10:21:24 +00:00
docker-compose.yml fix: correct .env file in docker-compose 2024-01-26 15:10:37 +00:00
Dockerfile fix(docker): entrypoint runs migrations via scripts/start.js 2026-05-27 17:05:10 +02:00
flake.lock add nix flake with devShell and native package build 2026-05-25 23:59:31 +02:00
flake.nix add nix flake with devShell and native package build 2026-05-25 23:59:31 +02:00
justfile wip 2023-12-01 11:18:39 +00:00
LICENSE MIT license 2023-12-01 11:40:59 +00:00
OAUTH-LIKE-FLOW.md Update OAUTH-LIKE-FLOW.md 2024-01-16 19:38:31 +00:00
package.json pin @nostr-dev-kit/ndk to 2.8.1 instead of workspace:* 2026-05-26 00:29:29 +02:00
package.nix fix(nix): include prisma CLI + scripts/, wrapper invokes start.js 2026-05-27 17:08:42 +02:00
pnpm-lock.yaml update ndk 2024-04-25 14:46:32 +01:00
README.md remove default start and just document using lfg 2024-01-31 13:45:23 +00:00
SECURITY-MODEL.md Policies and single-use tokens 2023-06-04 10:03:02 +02:00
tsconfig.json wip 2023-12-01 11:18:39 +00:00

nsecbunkerd

Daemon to remotely sign nostr events using keys.

Easy setup via docker compose

To quickly install nsecbunkerd via Docker just run:

Configurations

  • Prepare your config directory

    mkdir $HOME/.nsecbunker-config
    
  • Clone .env.example and add your nostr public key to ADMIN_NPUBS to the .env file.

  • Change DATABASE_URL if necessary.

cp .env.example .env

Start nsecbunkerd

Create and start the project containers. This runs the migrations and then runs nsecbunkderd container.

# Optionally, build the image locally
docker compose build nsecbunkerd

# Start the project
docker compose up

# Or in the background
docker compose up -d

Get the connection string

docker compose exec nsecbunkerd cat /app/config/connection.txt

nsecBunker will give you a connection string like:

bunker://npub1tj2dmc4udvgafxxxxxxxrtgne8j8l6rgrnaykzc8sys9mzfcz@relay.nsecbunker.com

You can visit https://app.nsecbunker.com/ to administrate your nsecBunker remotely, or explore nsecbunkerd's CLI to find the options to add and approve keys from the CLI.

Hard setup:

(If you installed via docker you don't need to do any of this, skip to the Configure section)

Node.js v18 or newer is required.

git clone <nsecbunkerd-repo>
npm i
npm run build
npx prisma migrate deploy

Configure

Easy: Remote configuration

Using the connection string you saw before, you can go to https://app.nsecbunker.com and paste your connection string.

Note that ONLY the npub that you designated as an administrator when launching nsecBunker is able to control your nsecBunker. Even if someone sees your connection string, without access to your administrator keys, there's nothing they can do.

Hard: manual configuration

(If you are using remote configuration you don't need to do any of this)

Add your nsec to nsecBunker

Here you'll give nsecBunker your nsec. It will ask you for a passphrase to encrypt it on-disk. The name is an internal name you'll use to refer to this keypair. Choose anything that is useful to you.

npm run nsecbunkerd -- add --name <your-key-name>

Example

$ npm run nsecbunkerd -- add --name "Uncomfortable family"

nsecBunker uses a passphrase to encrypt your nsec when stored on-disk.
Every time you restart it, you will need to type in this password.

Enter a passphrase: <enter-your-passphrase-here>
Enter the nsec for Uncomfortable family: <copy-your-nsec-here>
nsecBunker generated an admin password for you:

***************************

You will need this to manage users of your keys.

Start

$ npm run lfg --admin <your-admin-npub>

Testing with nsecbunker-client

nsecbunker ships with a simple client that can request signatures from an nsecbunkerd:

nsecbunker-client sign <target-npub> "hi, I'm signing from the command line with my nsecbunkerd!"

OAuth-like provider

nsecBunker can run as an OAuth-like provider, which means it will allow new users to create accounts remotely from any compatible client.

To enable this you'll need to configure a few things on your nsecbunker.json config file. In addition to the normal configuration:

{
    "baseUrl": "https://....", // a public URL where this nsecBunker can be reached via HTTPS
    "authPort": 3000, // Port number where the OAuth-like provider will listen
    "domains": {
        "your-domain-here": {
            "nip05": "/your-nip05-nostr.json-file", // The location where NIP-05 entries to your domain are stored

            "nip89": {
                "profile": { // a kind:0-like profile
                    "name": "my cool nsecbunker instance", // The name of your nsecBunker instance
                    "about": "...",
                },
                "operator": "npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft", // (optional) npub of the operator of this nsecbunker
                "relays": [ // list of relays where to publush the nip89 announcement
                    "https://relay.damus.io",
                    "https://pyramid.fiatjaf.com"
                ]
            }

            // Wallet configuration (optional)
            "wallet": {
                "lnbits": {
                    "url": "https://legend.lnbits.com", // The URL where your LNbits instance is running
                    "key": "your-lnbits-admin-key", // The admin key for your LNbits instance
                    "nostdressUrl": "http://localhost:5556" // The URL where your nostdress instance is running
                }
            }
        }
    }
}

With this configuration users will be able to:

  • create a new key managed by your nsecbunker
  • get an lnbits-based LN wallet
  • get zapping capabilitiyes through nostdress

For this to work you'll need to run, in addition to nsecbunkerd, an lnbits instance and a nostdress instance. Your LNBits needs to have the user manager extension enabled.

  • TODO: Add NWC support

When booting up, the nsecbunkerd will publish a NIP-89 announcement (kind:31990), which is the way clients find out about your nsecbunker.

When a bunker provides a wallet and zapping service (wallet and nostdressUrl are configured), it will add tags:

{
    "tags": [
        [ "f", "wallet" ],
        [ "f", "zaps" ]
    ]
}

Authors

  • pablof7z
    • npub1l2vyh47mk2p0qlsku7hg0vn29faehy9hy34ygaclpn66ukqp3afqutajft

License

MIT