{"id":15161377,"url":"https://github.com/lightninglabs/lndinit","last_synced_at":"2025-10-12T03:34:29.304Z","repository":{"id":38314837,"uuid":"468511014","full_name":"lightninglabs/lndinit","owner":"lightninglabs","description":"cloud infra tooling for lnd provisioning/unlocking","archived":false,"fork":false,"pushed_at":"2025-10-08T14:29:28.000Z","size":659,"stargazers_count":31,"open_issues_count":6,"forks_count":17,"subscribers_count":19,"default_branch":"main","last_synced_at":"2025-10-08T16:13:59.945Z","etag":null,"topics":["bitcoin","k8s","lightning","ln","lnd","network"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lightninglabs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-03-10T21:08:00.000Z","updated_at":"2025-10-08T14:27:48.000Z","dependencies_parsed_at":"2024-04-23T15:50:32.302Z","dependency_job_id":"dec8774e-b500-477e-8ef7-fefd609cb10f","html_url":"https://github.com/lightninglabs/lndinit","commit_stats":{"total_commits":65,"total_committers":6,"mean_commits":"10.833333333333334","dds":0.5538461538461539,"last_synced_commit":"2c4b14fea9e108dde2f03764dceb68f5fca940c0"},"previous_names":[],"tags_count":97,"template":false,"template_full_name":null,"purl":"pkg:github/lightninglabs/lndinit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightninglabs%2Flndinit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightninglabs%2Flndinit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightninglabs%2Flndinit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightninglabs%2Flndinit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lightninglabs","download_url":"https://codeload.github.com/lightninglabs/lndinit/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lightninglabs%2Flndinit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279010149,"owners_count":26084692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitcoin","k8s","lightning","ln","lnd","network"],"created_at":"2024-09-27T00:05:14.790Z","updated_at":"2025-10-12T03:34:29.299Z","avatar_url":"https://github.com/lightninglabs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# lndinit: a wallet initializer utility for lnd\n\nThis repository contains the source for the `lndinit` command.\nThe main purpose of `lndinit` is to help automate the `lnd` wallet\ninitialization, including seed and password generation.\n\n- [Requirements](#requirements)\n- [Subcommands](#subcommands)\n  - [`gen-password`](#gen-password)\n  - [`gen-seed`](#gen-seed)\n  - [`load-secret`](#load-secret)\n  - [`store-secret`](#store-secret)\n  - [`store-configmap`](#store-configmap)\n  - [`init-wallet`](#init-wallet)\n  - [`wait-ready`](#wait-ready)\n  - [`migrate-db`](#migrate-db)\n- [Example usage](#example-usage)\n  - [Basic setup](#example-use-case-1-basic-setup)\n  - [Kubernetes](#example-use-case-2-kubernetes)\n- [Logging and idempotent operations](#logging-and-idempotent-operations)\n\n## Requirements\n\nMost commands of this tool operate independently of `lnd` and therefore don't\nrequire a specific version to be installed.\n\nThe commands `wait-ready` and `init-wallet` only work with `lnd v0.14.2-beta`\nand later though.\n\nA recent version of Kubernetes is needed when interacting with secrets stored in\nk8s. Any version `\u003e= v1.8` should work.\n\n---\n\n## Subcommands\n\nMost commands work without `lnd` running, as they are designed to do some provisioning work _before_ `lnd` is started.\n\n### gen-password\n`gen-password` generates a random password (no `lnd` needed)\n\n### gen-seed\n`gen-seed` generates a random seed phrase\n\nNo `lnd` needed, but seed will be in `lnd`-specific [`aezeed` format](https://github.com/lightningnetwork/lnd/blob/master/aezeed/README.md)\n\n### load-secret\n`load-secret` interacts with kubernetes to read from secrets (no `lnd` needed)\n\n### store-secret\n`store-secret` interacts with kubernetes to write to secrets (no `lnd` needed)\n\n### store-configmap\n`store-configmap` interacts with kubernetes to write to configmaps (no `lnd` needed)\n\n### init-wallet\n`init-wallet` has two modes:\n- `--init-type=file` creates an `lnd` specific `wallet.db` file\n  - Only works if `lnd` is NOT running yet\n- `--init-type=rpc` calls the `lnd` RPC to create a wallet\n  - Use this mode if you are using a remote database as `lnd`'s storage backend instead of bolt DB based file databases\n  - Needs `lnd` to be running and no wallet to exist\n\n### wait-ready\n`wait-ready` waits for `lnd` to be ready by connecting to `lnd`'s status RPC\n- Needs `lnd` to run, eventually\n\n### migrate-db\n`migrate-db` migrates the content of one `lnd` database to another, for example\nfrom `bbolt` to Postgres. See [data migration guide](docs/data-migration.md) for\nmore information.\n\n---\n\n## Example Usage\n\n### Example use case 1: Basic setup\n\nThis is a very basic example that shows the purpose of the different sub\ncommands of the `lndinit` binary. In this example, all secrets are stored in\nfiles. This is normally not a good security practice as potentially other users\nor processes on a system can read those secrets if the permissions aren't set\ncorrectly. It is advised to store secrets in dedicated secret storage services\nlike Kubernetes Secrets or HashiCorp Vault.\n\n#### 1. Generate a seed without a seed passphrase\n\nCreate a new seed if one does not exist yet.\n\n```shell\n$ if [[ ! -f /safe/location/seed.txt ]]; then\n    lndinit gen-seed \u003e /safe/location/seed.txt\n  fi\n```\n\n#### 2. Generate a wallet password\n\nCreate a new wallet password if one does not exist yet.\n\n```shell\n$ if [[ ! -f /safe/location/walletpassword.txt ]]; then\n    lndinit gen-password \u003e /safe/location/walletpassword.txt\n  fi\n```\n\n#### 3. Initialize the wallet\n\nCreate the wallet database with the given seed and password files. If the wallet\nalready exists, we make sure we can actually unlock it with the given password\nfile. This will take a few seconds in any case.\n\n```shell\n$ lndinit -v init-wallet \\\n    --secret-source=file \\\n    --file.seed=/safe/location/seed.txt \\\n    --file.wallet-password=/safe/location/walletpassword.txt \\\n    --init-file.output-wallet-dir=$HOME/.lnd/data/chain/bitcoin/mainnet \\\n    --init-file.validate-password\n```\n\n#### 4. Start and auto unlock lnd\n\nWith everything prepared, we can now start lnd and instruct it to auto unlock\nitself with the password in the file we prepared.\n\n```shell\n$ lnd \\\n    --bitcoin.active \\\n    ...\n    --wallet-unlock-password-file=/safe/location/walletpassword.txt\n```\n\n### Example use case 2: Kubernetes\n\nThis example shows how Kubernetes (k8s) Secrets can be used to store the wallet\nseed and password. The pod running those commands must be provisioned with a\nservice account that has permissions to read/create/modify secrets in a given\nnamespace.\n\nHere's an example of a service account, role provision and pod definition:\n\n```yaml\napiVersion: v1\nkind: ServiceAccount\nmetadata:\n  name: lnd-provision-account\n\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: Role\nmetadata:\n  name: lnd-update-secrets-role\n  namespace: default\nrules:\n  - apiGroups: [ \"\" ]\n    resources: [ \"secrets\" ]\n    verbs: [ \"get\", \"list\", \"create\", \"watch\", \"update\", \"patch\" ]\n\n\n---\napiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\nmetadata:\n  name: lnd-update-secrets-role-binding\n  namespace: default\nroleRef:\n  kind: Role\n  name: lnd-update-secrets-role\n  apiGroup: rbac.authorization.k8s.io\nsubjects:\n  - kind: ServiceAccount\n    name: lnd-provision-account\n    namespace: default\n\n\n---\napiVersion: apps/v1\nkind: Deployment\nmetadata:\n  name: lnd-pod\nspec:\n  strategy:\n    type: Recreate\n  replicas: 1\n  template:\n    spec:\n      # We use the special service account created, so the init script is able\n      # to update the secret as expected.\n      serviceAccountName: lnd-provision-account\n\n      containers:\n        # The main lnd container\n        - name: lnd\n          \n          # The lndinit image is an image based on the main lnd image that just\n          # adds the lndinit binary to it. The tag name is simply:\n          #   \u003clndinit-version\u003e-lnd-\u003clnd-version\u003e\n          image: lightninglabs/lndinit:v0.1.0-lnd-v0.14.2-beta\n          env:\n            - name: WALLET_SECRET_NAME\n              value: lnd-wallet-secret\n            - name: WALLET_DIR\n              value: /root/.lnd/data/chain/bitcoin/mainnet\n            - name: CERT_DIR\n              value: /root/.lnd\n            - name: UPLOAD_RPC_SECRETS\n              value: '1'\n            - name: RPC_SECRETS_NAME\n              value: lnd-rpc-secrets\n          command: [ '/init-wallet-k8s.sh' ]\n          args: [\n              '--bitcoin.mainnet',\n              '...',\n              '--wallet-unlock-password-file=/tmp/wallet-password',\n          ]\n```\n\nThe `/init-wallet-k8s.sh` script that is invoked in the example above can be\nfound in this repository:\n[`example-init-wallet-k8s.sh`](example-init-wallet-k8s.sh)\nThe script executes the steps described in this example and also uploads the\nRPC secrets (`tls.cert` and all `*.macaroon` files) to another secret so apps\nusing the `lnd` node can access those secrets.\n\n#### 1. Generate a seed passphrase (optional)\n\nGenerate a new seed passphrase. If an entry with the key already exists in the\nk8s secret, it is not overwritten, and the operation is a no-op.\n\n```shell\n$ lndinit gen-password \\\n    | lndinit -v store-secret \\\n    --target=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.secret-key-name=seed-passphrase\n```\n\n#### 2. Generate a seed using the passphrase\n\nGenerate a new seed with the passphrase created before. If an entry with that\nkey already exists in the k8s secret, it is not overwritten, and the operation\nis a no-op.\n\n```shell\n$ lndinit -v gen-seed \\\n    --passphrase-k8s.secret-name=lnd-secrets \\\n    --passphrase-k8s.secret-key-name=seed-passphrase \\\n    | lndinit -v store-secret \\\n    --target=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.secret-key-name=seed\n```\n\n#### 3. Generate a wallet password\n\nGenerate a new wallet password. If an entry with that key already exists in the\nk8s secret, it is not overwritten, and the operation is a no-op.\n\n```shell\n$ lndinit gen-password \\\n    | lndinit -v store-secret \\\n    --target=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.secret-key-name=wallet-password\n```\n\n#### 4. Initialize the wallet, attempting a test unlock with the password\n\nCreate the wallet database with the given seed, seed passphrase and wallet\npassword loaded from a k8s secret. If the wallet already exists, we make sure we\ncan actually unlock it with the given password file. This will take a few\nseconds in any case.\n\n```shell\n$ lndinit -v init-wallet \\\n    --secret-source=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.seed-key-name=seed \\\n    --k8s.seed-passphrase-key-name=seed-passphrase \\\n    --k8s.wallet-password-key-name=wallet-password \\\n    --init-file.output-wallet-dir=$HOME/.lnd/data/chain/bitcoin/mainnet \\\n    --init-file.validate-password\n```\n\nThe above is an example for a file/bbolt based node. For such a node creating\nthe wallet directly as a file is the most secure option, since it doesn't\nrequire the node to spin up the wallet unlocker RPC (which doesn't use macaroons\nand is therefore un-authenticated).\n\nBut in setups where the wallet isn't a file (since all state is in a remote\ndatabase such as etcd or Postgres), this method cannot be used.\nInstead, the wallet needs to be initialized through RPC, as shown in the next\nexample:\n\n```shell\n$ lndinit -v init-wallet \\\n    --secret-source=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.seed-key-name=seed \\\n    --k8s.seed-passphrase-key-name=seed-passphrase \\\n    --k8s.wallet-password-key-name=wallet-password \\\n    --init-type=rpc \\\n    --init-rpc.server=localhost:10009 \\\n    --init-rpc.tls-cert-path=$HOME/.lnd/tls.cert\n```\n\n**NOTE**: If this is used in combination with the\n`--wallet-unlock-password-file=` flag in `lnd` for automatic unlocking, then the\n`--wallet-unlock-allow-create` flag also needs to be set. Otherwise, `lnd` won't\nbe starting the wallet unlocking RPC that is used for initializing the wallet.\n\nThe following example shows how to use the `lndinit init-wallet` command to\ncreate a watch-only wallet from a previously exported accounts JSON file:\n\n```shell\n$ lndinit -v init-wallet \\\n    --secret-source=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.seed-key-name=seed \\\n    --k8s.seed-passphrase-key-name=seed-passphrase \\\n    --k8s.wallet-password-key-name=wallet-password \\\n    --init-type=rpc \\\n    --init-rpc.server=localhost:10009 \\\n    --init-rpc.tls-cert-path=$HOME/.lnd/tls.cert \\\n    --init-rpc.watch-only \\\n    --init-rpc.accounts-file=/tmp/accounts.json\n```\n\n#### 5. Store the wallet password in a file\n\nBecause we now only have the wallet password as a value in a k8s secret, we need\nto retrieve it and store it in a file that `lnd` can read to auto unlock.\n\n```shell\n$ lndinit -v load-secret \\\n    --source=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.secret-key-name=wallet-password \u003e /safe/location/walletpassword.txt\n```\n\n**Security notice**:\n\nAny process or user that has access to the file system of the container can\npotentially read the password if it's stored as a plain file.\nFor an extra bump in security, a named pipe can be used instead of a file. That\nway the password can only be read exactly once from the pipe during `lnd`'s\nstartup.\n\n```shell\n# Create a FIFO pipe first. This will behave like a file except that writes to\n# it will only occur once there's a reader on the other end.\n$ mkfifo /tmp/wallet-password\n\n# Read the secret from Kubernetes and write it to the pipe. This will only\n# return once lnd is actually reading from the pipe. Therefore we need to run\n# the command as a background process (using the ampersand notation).\n$ lndinit load-secret \\\n    --source=k8s \\\n    --k8s.secret-name=lnd-secrets \\\n    --k8s.secret-key-name=wallet-password \u003e /tmp/wallet-password \u0026\n\n# Now run lnd and point it to the named pipe.\n$ lnd \\\n    --bitcoin.active \\\n    ...\n    --wallet-unlock-password-file=/tmp/wallet-password\n```\n\n#### 6. Start and auto unlock lnd\n\nWith everything prepared, we can now start lnd and instruct it to auto unlock\nitself with the password in the file we prepared.\n\n```shell\n$ lnd \\\n    --bitcoin.active \\\n    ...\n    --wallet-unlock-password-file=/safe/location/walletpassword.txt\n```\n\n---\n\n## Logging and idempotent operations\n\nBy default, `lndinit` aborts and exits with a zero return code if the desired\nresult is already achieved (e.g. a secret key or a wallet database already\nexist). This can make it hard to follow exactly what is happening when debugging\nthe initialization. To assist with debugging, the following two flags can be\nused:\n\n- `--verbose (-v)`: Log debug information to `stderr`.\n- `--error-on-existing (-e)`: Exit with a non-zero return code (128) if the\n  result of an operation already exists. See example below.\n\n**Example**:\n\n```shell\n# Treat every non-zero return code as abort condition (default for k8s container\n# commands).\n$ set -e\n\n# Run the command and catch any non-zero return code in the ret variable. The\n# logical OR is required to not fail because of above setting.\n$ ret=0\n$ lndinit --error-on-existing init-wallet ... || ret=$?\n$ if [[ $ret -eq 0 ]]; then\n    echo \"Successfully initialized wallet.\"\n  elif [[ $ret -eq 128 ]]; then\n    echo \"Wallet already exists, skipping initialization.\"\n  else\n    echo \"Failed to initialize wallet!\"\n    exit 1\n  fi\n```\n\n---\n\n## Release Process\n\nThis project is updated less often than `lnd`, so there are two main aspects to\nthe release process. When a new `lnd` is released, and it's compatible with\nexisting `lndinit` binary, only the container image needs to be built.\n\n### Binary release\n\nWhen binary changes are required (either for dependency upgrades, or to maintain\ncompatibility with a new `lnd` release) the `lndinit` binary must be rebuilt:\n\n1. Apply the necessary code changes.\n2. Adjust the relevant version constant(s) in `version.go`.\n    - Usually this will be incrementing `AppPatch`.\n3. Open PR and have it merged.\n4. A maintainer must push a git-tag with the new version:\n    - `git checkout main \u0026\u0026 git pull`\n    - `TAG=v0.\u003cminor\u003e.\u003cpatch\u003e-beta` (e.g.: `TAG=v0.1.15-beta`)\n    - `git tag $TAG \u0026\u0026 git push $TAG`\n\nThen proceed to the container image release process.\n\n### Container image release\n\nWhen a new version of `lnd` is released, a new `lndinit` container image build\nis triggered by pushing a tag with the format:\n`docker/\u003clndinit_version\u003e-lnd-\u003clnd_version\u003e`\n\nFor example, to build an image based on lnd `v0.16.4-beta`, which includes\nlndinit `v0.1.15-beta`:\n\n```\nLNDINIT_VERSION=v0.1.15-beta\nLND_VERSION=v0.16.4-beta\n\ngit checkout $LNDINIT_VERSION\ngit tag docker/${LNDINIT_VERSION}-lnd-${LND_VERSION}\ngit push docker/${LNDINIT_VERSION}-lnd-${LND_VERSION}\n```\n\nIf lnd `v0.16.5-beta` is released and does not require additional `lndinit`\nbinary changes, the desired image can be built by re-running the previous\ncommand with the lnd version adjusted. _In this case, there's no need to modify\nany code in this repo._\n\nFor more detail, refer to the [docker.yml](.github/workflows/docker.yml)\nGithub workflow.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightninglabs%2Flndinit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flightninglabs%2Flndinit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flightninglabs%2Flndinit/lists"}