From dc555d0424b828c3aee4a492c1a766e410598718 Mon Sep 17 00:00:00 2001 From: benthecarman Date: Tue, 14 Apr 2026 16:45:02 -0500 Subject: [PATCH] Add initial guides & documentation Add docs/ directory with guides for getting started, configuration, the gRPC API, Tor setup, and production operations. Add per-crate READMEs for ldk-server-client, ldk-server-grpc, and ldk-server-cli. Include READMEs in lib.rs via doc = include_str! so rustdoc validates the code examples. Update the root README to link to the new docs and fix outdated REST/port references. Co-Authored-By: Claude Opus 4.6 (1M context) --- CONTRIBUTING.md | 4 +- README.md | 77 ++---- .../ldk-server-config.toml | 12 +- contrib/ldk-server.service | 22 ++ docs/api-guide.md | 240 ++++++++++++++++++ docs/configuration.md | 142 +++++++++++ docs/getting-started.md | 161 ++++++++++++ docs/operations.md | 167 ++++++++++++ docs/tor.md | 106 ++++++++ ldk-server-cli/README.md | 45 ++++ ldk-server-client/README.md | 73 ++++++ ldk-server-client/src/lib.rs | 9 +- ldk-server-grpc/README.md | 46 ++++ ldk-server-grpc/src/lib.rs | 2 + ldk-server/README.md | 25 ++ 15 files changed, 1065 insertions(+), 66 deletions(-) rename {ldk-server => contrib}/ldk-server-config.toml (91%) create mode 100644 contrib/ldk-server.service create mode 100644 docs/api-guide.md create mode 100644 docs/configuration.md create mode 100644 docs/getting-started.md create mode 100644 docs/operations.md create mode 100644 docs/tor.md create mode 100644 ldk-server-cli/README.md create mode 100644 ldk-server-client/README.md create mode 100644 ldk-server-grpc/README.md create mode 100644 ldk-server/README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ecaa51ec..f9fa15f3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -13,7 +13,7 @@ cargo build --release # Production build (LTO enabled) ## Running ```bash -cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml +cargo run --bin ldk-server ./contrib/ldk-server-config.toml ``` ## Testing @@ -54,7 +54,7 @@ cargo fmt --all ## Configuration -- Config template with all options: `ldk-server/ldk-server-config.toml` +- Config template with all options: `contrib/ldk-server-config.toml` - When updating config options, also update the tests in `ldk-server/src/util/config.rs` ## Before Submitting diff --git a/README.md b/README.md index f14d2881..93a74aea 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ a Lightning node while exposing a robust, language-agnostic API via [Protocol Bu - Deploy a Lightning Network node with minimal configuration, no coding required. - **API-First Design**: - - Exposes a well-defined API using Protobuf, allowing seamless integration with HTTP-clients or applications. + - Exposes a well-defined gRPC API using Protobuf, allowing seamless integration with any language. - **Powered by LDK**: - Built on top of LDK-Node, leveraging the modular, reliable, and high-performance architecture of LDK. @@ -26,67 +26,38 @@ a Lightning node while exposing a robust, language-agnostic API via [Protocol Bu ### Project Status -🚧 **Work in Progress**: -- **APIs Under Development**: Expect breaking changes as the project evolves. -- **Potential Bugs and Inconsistencies**: While progress is being made toward stability, unexpected behavior may occur. -- **Improved Logging and Error Handling Coming Soon**: Current error handling is rudimentary (specially for CLI), and usability improvements are actively being worked on. -- **Pending Testing**: Not tested, hence don't use it for production! +**Work in Progress**: +- APIs are under development. Expect breaking changes as the project evolves. +- Not tested for production use. +- We welcome your feedback and contributions to help shape the future of LDK Server! -We welcome your feedback and contributions to help shape the future of LDK Server! +### Quick Start - -### Configuration -Refer `./ldk-server/ldk-server-config.toml` to see available configuration options. - -You can configure the node via a TOML file, environment variables, or CLI arguments. All options are optional — values provided via CLI override environment variables, which override the values in the TOML file. - -### Building -``` +```bash git clone https://github.com/lightningdevkit/ldk-server.git -cargo build -``` - -### Running -- Using a config file: -``` -cargo run --bin ldk-server ./ldk-server/ldk-server-config.toml +cd ldk-server +cargo build --release +cp contrib/ldk-server-config.toml my-config.toml # edit with your settings +./target/release/ldk-server my-config.toml ``` -- Using environment variables (all optional): -``` -export LDK_SERVER_NODE_NETWORK=regtest -export LDK_SERVER_NODE_LISTENING_ADDRESS=localhost:3001 -export LDK_SERVER_NODE_REST_SERVICE_ADDRESS=127.0.0.1:3002 -export LDK_SERVER_NODE_ALIAS=LDK-Server -export LDK_SERVER_BITCOIND_RPC_ADDRESS=127.0.0.1:18443 -export LDK_SERVER_BITCOIND_RPC_USER=your-rpc-user -export LDK_SERVER_BITCOIND_RPC_PASSWORD=your-rpc-password -export LDK_SERVER_STORAGE_DIR_PATH=/path/to/storage -cargo run --bin ldk-server -``` - -Interact with the node using CLI: -``` -ldk-server-cli -b localhost:3002 --api-key your-secret-api-key --tls-cert /path/to/tls_cert.pem onchain-receive # To generate onchain-receive address. -ldk-server-cli -b localhost:3002 --api-key your-secret-api-key --tls-cert /path/to/tls_cert.pem help # To print help/available commands. -``` - -### Shell Completions +See [Getting Started](docs/getting-started.md) for a full walkthrough. -The CLI supports generating shell completions for Bash, Zsh, Fish, Elvish, and PowerShell. +### Documentation -Add completions to your shell config: -```bash -# Bash (add to ~/.bashrc) -eval "$(ldk-server-cli completions bash)" +| Document | Description | +|----------|-------------| +| [Getting Started](docs/getting-started.md) | Install, configure, and run your first node | +| [Configuration](docs/configuration.md) | All config options, environment variables, and Bitcoin backend tradeoffs | +| [API Guide](docs/api-guide.md) | gRPC transport, authentication, and endpoint reference | +| [Tor](docs/tor.md) | Connecting to and receiving connections over Tor | +| [Operations](docs/operations.md) | Production deployment, backups, and monitoring | -# Zsh (add to ~/.zshrc) -eval "$(ldk-server-cli completions zsh)" +### API -# Fish (add to ~/.config/fish/config.fish) -ldk-server-cli completions fish | source -``` +The canonical API definitions are in [`ldk-server-grpc/src/proto/`](ldk-server-grpc/src/proto/). A ready-made +Rust client library is provided in [`ldk-server-client/`](ldk-server-client/). -## Contributing +### Contributing Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on building, testing, code style, and development workflow. diff --git a/ldk-server/ldk-server-config.toml b/contrib/ldk-server-config.toml similarity index 91% rename from ldk-server/ldk-server-config.toml rename to contrib/ldk-server-config.toml index 1873e2d6..7657f553 100644 --- a/ldk-server/ldk-server-config.toml +++ b/contrib/ldk-server-config.toml @@ -1,9 +1,9 @@ # Lightning node settings [node] network = "regtest" # Bitcoin network to use -listening_addresses = ["localhost:3001"] # Lightning node listening addresses -announcement_addresses = ["54.3.7.81:3001"] # Lightning node announcement addresses -#grpc_service_address = "127.0.0.1:3536" # LDK Server gRPC address (optional, defaults to 127.0.0.1:3536) +listening_addresses = ["localhost:9735"] # Lightning node listening addresses +#announcement_addresses = ["54.3.7.81:9735"] # Lightning node announcement addresses +#grpc_service_address = "127.0.0.1:3536" # LDK Server gRPC address (optional, defaults to 127.0.0.1:3536) alias = "ldk_server" # Lightning node alias #pathfinding_scores_source_url = "" # External Pathfinding Scores Source #rgs_server_url = "https://rapidsync.lightningdevkit.org/snapshot/v2/" # Optional: RGS URL for rapid gossip sync @@ -14,12 +14,12 @@ dir_path = "/tmp/ldk-server/" # Path for LDK and BDK data persis [log] level = "Debug" # Log level (Error, Warn, Info, Debug, Trace) -file = "/tmp/ldk-server/ldk-server.log" # Log file path +#file = "/tmp/ldk-server/ldk-server.log" # Log file path [tls] #cert_path = "/path/to/tls.crt" # Path to TLS certificate, by default uses dir_path/tls.crt #key_path = "/path/to/tls.key" # Path to TLS private key, by default uses dir_path/tls.key -hosts = ["example.com"] # Allowed hosts for TLS, will always include "localhost" and "127.0.0.1" +#hosts = ["example.com"] # Allowed hosts for TLS, will always include "localhost" and "127.0.0.1" # Must set one of bitcoind, electrum, or esplora @@ -100,4 +100,4 @@ poll_metrics_interval = 60 # The polling interval for metrics in seconds. # Tor Config [tor] # Only connections to OnionV3 peers will be made via this proxy; other connections (IPv4 peers, Electrum server) will not be routed over Tor. -#proxy_address = "" # Tor daemon SOCKS proxy address. +#proxy_address = "127.0.0.1:9050" # Tor daemon SOCKS proxy address. diff --git a/contrib/ldk-server.service b/contrib/ldk-server.service new file mode 100644 index 00000000..3b130373 --- /dev/null +++ b/contrib/ldk-server.service @@ -0,0 +1,22 @@ +[Unit] +Description=LDK Server Lightning Node +After=network-online.target bitcoind.service +Wants=network-online.target + +[Service] +Type=notify +ExecStart=/usr/local/bin/ldk-server /etc/ldk-server/config.toml +Restart=always +RestartSec=10 + +# Security hardening +User=ldk-server +ProtectSystem=strict +NoNewPrivileges=true +PrivateTmp=true +PrivateDevices=true +MemoryDenyWriteExecute=true +ReadWritePaths=/var/lib/ldk-server + +[Install] +WantedBy=multi-user.target \ No newline at end of file diff --git a/docs/api-guide.md b/docs/api-guide.md new file mode 100644 index 00000000..63594f3d --- /dev/null +++ b/docs/api-guide.md @@ -0,0 +1,240 @@ +# API Guide + +LDK Server exposes a gRPC API over HTTP/2 with TLS. This guide covers transport, authentication, +and provides an index of all available RPCs. For field-level details on each request and response, +refer to the proto definitions, which are the canonical reference and include links to the +underlying LDK Node documentation. + +## Transport + +- **Protocol:** gRPC over HTTP/2 with TLS (self-signed by default) +- **Default address:** `127.0.0.1:3536` +- **Content-Type:** `application/grpc+proto` +- **Service name:** `api.LightningNode` +- **Full RPC path format:** `/api.LightningNode/` + +## Authentication + +Every gRPC request must include an `x-auth` metadata header with an HMAC-SHA256 signature: + +``` +x-auth: HMAC : +``` + +Where: + +- `unix_timestamp` is the current time in seconds since the Unix epoch +- `hmac_hex` is the hex-encoded result of `HMAC-SHA256(api_key_bytes, timestamp_be_bytes)` + - `api_key_bytes` is the API key string encoded as UTF-8 bytes + - `timestamp_be_bytes` is the timestamp as a big-endian 8-byte unsigned integer + +The server rejects requests where the timestamp differs from the server's clock by more than +**60 seconds**. + +## TLS + +The server auto-generates a self-signed ECDSA P-256 certificate on first startup, stored at +`/tls.crt`. Clients must pin this certificate (not rely on system trust roots) +since it is self-signed. + +For the Rust client library, pass the PEM contents to `LdkServerClient::new()`. For other +languages, configure your gRPC channel to trust the server's certificate file. + +## Proto Definitions + +The canonical API definitions live in `ldk-server-grpc/src/proto/`: + +| File | Contents | +|----------------|-----------------------------------------------------| +| `api.proto` | All RPC request/response messages and documentation | +| `types.proto` | Shared types (Payment, Channel, Peer, etc.) | +| `events.proto` | Event envelope and event types for streaming | +| `error.proto` | Error response definitions | + +### Generating Client Stubs + +Any standard `protoc` toolchain can generate clients from these proto files. The proto directory +path is `ldk-server-grpc/src/proto/`. For Rust specifically, the `ldk-server-client` crate +provides a ready-made async client. + +## Error Model + +Errors are returned as standard gRPC status codes: + +| gRPC Code | Meaning | +|---------------------------|------------------------------------------------------------------| +| `INVALID_ARGUMENT` (3) | Malformed request or invalid parameters | +| `FAILED_PRECONDITION` (9) | Lightning operation error (e.g., insufficient balance, no route) | +| `INTERNAL` (13) | Server-side bug | +| `UNAUTHENTICATED` (16) | Missing or invalid `x-auth` header | + +The `grpc-message` trailer contains a human-readable error description. + +## Endpoint Reference + +All RPCs are unary (single request, single response) unless noted otherwise. + +### Node Information + +| RPC | Description | +|---------------|-------------------------------------------------------------------------------------| +| `GetNodeInfo` | Node ID, best block, sync timestamps, listening/announcement addresses, alias, URIs | +| `GetBalances` | On-chain, Lightning channel, and claimable balance breakdown | + +### On-Chain + +| RPC | Description | +|------------------|----------------------------------------------------------------------| +| `OnchainReceive` | Generate a new on-chain funding address | +| `OnchainSend` | Send to a Bitcoin address (with optional fee rate and send-all mode) | + +### BOLT11 Payments + +| RPC | Description | +|-----------------|-------------------------------------------------------------------| +| `Bolt11Receive` | Create an invoice (fixed or variable amount) with automatic claim | +| `Bolt11Send` | Pay a BOLT11 invoice (with optional routing config) | + +### BOLT11 Hodl Invoices + +These RPCs support a manual claim/fail workflow for held payments. See +[Hodl Invoice Lifecycle](#hodl-invoice-lifecycle) below. + +| RPC | Description | +|------------------------|--------------------------------------------------------------------| +| `Bolt11ReceiveForHash` | Create an invoice for a given payment hash (manual claim required) | +| `Bolt11ClaimForHash` | Claim a held payment by providing the preimage | +| `Bolt11FailForHash` | Reject a held payment | + +### BOLT11 JIT Channels (LSPS2) + +Requires an `[liquidity.lsps2_client]` configuration. The LSP opens a channel just-in-time +when the invoice is paid. + +| RPC | Description | +|--------------------------------------------|-----------------------------------------------------------| +| `Bolt11ReceiveViaJitChannel` | Create a fixed-amount invoice with JIT channel opening | +| `Bolt11ReceiveVariableAmountViaJitChannel` | Create a variable-amount invoice with JIT channel opening | + +### BOLT12 Offers + +| RPC | Description | +|-----------------|-------------------------------------------------------------------------| +| `Bolt12Receive` | Create a BOLT12 offer (fixed or variable amount) | +| `Bolt12Send` | Pay a BOLT12 offer (with optional quantity, payer note, routing config) | + +### Spontaneous and Unified Send + +| RPC | Description | +|-------------------|--------------------------------------------------------------------------------| +| `SpontaneousSend` | Send a keysend payment to a node ID | +| `UnifiedSend` | Pay a BIP 21 URI, BIP 353 Human-Readable Name, BOLT11 invoice, or BOLT12 offer | + +### Channel Management + +| RPC | Description | +|-----------------------|------------------------------------------------------------------------| +| `OpenChannel` | Open a new outbound channel (with optional push amount and fee config) | +| `CloseChannel` | Cooperatively close a channel | +| `ForceCloseChannel` | Force-close a channel unilaterally | +| `SpliceIn` | Add on-chain funds to an existing channel | +| `SpliceOut` | Remove funds from a channel back on-chain | +| `UpdateChannelConfig` | Update forwarding fees and CLTV expiry delta | +| `ListChannels` | List all channels with balances and configuration | + +### Payment History + +| RPC | Description | +|-------------------------|------------------------------------------------| +| `GetPaymentDetails` | Get details for a specific payment by ID | +| `ListPayments` | List all payments (paginated) | +| `ListForwardedPayments` | List all forwarded/routed payments (paginated) | + +See [Pagination](#pagination) below for how to page through results. + +### Peer Management + +| RPC | Description | +|------------------|----------------------------------------------------------| +| `ConnectPeer` | Connect to a peer (optionally persist the connection) | +| `DisconnectPeer` | Disconnect from a peer and remove it from the peer store | +| `ListPeers` | List all connected peers | + +### Cryptography + +| RPC | Description | +|-------------------|-----------------------------------------------------| +| `SignMessage` | Sign a message with the node's private key | +| `VerifySignature` | Verify a signature against a message and public key | + +### Network Graph + +| RPC | Description | +|---------------------|-------------------------------------------------------| +| `GraphListChannels` | List all known short channel IDs in the network graph | +| `GraphGetChannel` | Get channel details by short channel ID | +| `GraphListNodes` | List all known node IDs in the network graph | +| `GraphGetNode` | Get node details by node ID | + +### Routing + +| RPC | Description | +|---------------------------|------------------------------------------------------| +| `ExportPathfindingScores` | Export the router's pathfinding score cache | +| `DecodeInvoice` | Decode a BOLT11 invoice and return its parsed fields | +| `DecodeOffer` | Decode a BOLT12 offer and return its parsed fields | + +### Event Streaming + +| RPC | Description | +|-------------------|-------------------------------------------------------------| +| `SubscribeEvents` | **Server-streaming.** Subscribe to real-time payment events | + +`SubscribeEvents` returns a stream of `EventEnvelope` messages. Each envelope contains one of: + +| Event | When | +|---------------------|-----------------------------------------------------------------------| +| `PaymentReceived` | An inbound payment was received and auto-claimed | +| `PaymentSuccessful` | An outbound payment succeeded | +| `PaymentFailed` | An outbound payment failed | +| `PaymentClaimable` | A hodl invoice payment arrived and is waiting to be claimed or failed | +| `PaymentForwarded` | A payment was routed through this node | + +Events are broadcast to all connected subscribers. The server uses a bounded broadcast channel +(capacity 1024). A slow subscriber that falls behind will miss events. + +### Metrics + +Metrics are served as a plain HTTP GET endpoint (not gRPC): + +``` +GET /metrics +``` + +Returns Prometheus-format text. Requires `[metrics] enabled = true` in the config. Supports +optional Basic Auth. See [Configuration](configuration.md#metrics) for setup. + +## Hodl Invoice Lifecycle + +Hodl invoices allow you to inspect and conditionally accept incoming payments: + +1. **Create the invoice:** Call `Bolt11ReceiveForHash` with a payment hash you control. +2. **Wait for payment:** Subscribe to events via `SubscribeEvents` and watch for a + `PaymentClaimable` event matching your payment hash. +3. **Decide:** + - **Accept:** Call `Bolt11ClaimForHash` with the preimage corresponding to the payment hash. + - **Reject:** Call `Bolt11FailForHash` with the payment hash. + +The payment is held in a pending state until you explicitly claim or fail it. **You must +always call one of these.** If you do neither, the HTLC will eventually time out, which +can cause a force-closure of the channel. + +## Pagination + +`ListPayments` and `ListForwardedPayments` support cursor-based pagination: + +1. Make the first request with your desired `number_of_payments` page size. +2. If the response includes a `next_page_token`, pass it as `page_token` in the next request. +3. When `next_page_token` is absent, you have reached the end of the results. + +Results are ordered by creation time (most recent first). diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..40f2927d --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,142 @@ +# Configuration + +LDK Server can be configured via a TOML file, environment variables, or CLI arguments. +The [annotated config template](../contrib/ldk-server-config.toml) shows every available +option with comments and is the canonical reference for individual fields. + +## Precedence + +When the same option is set in multiple places, the highest-priority source wins: + +1. **CLI arguments** (highest) +2. **Environment variables** (`LDK_SERVER_*` prefix) +3. **TOML config file** +4. **Built-in defaults** (lowest) + +## CLI Arguments + +All CLI flags use long-form hyphenated names derived from the TOML keys. For example, +`node.network` becomes `--node-network`, `bitcoind.rpc_address` becomes +`--bitcoind-rpc-address`, etc. See `ldk-server --help` for the full list of options. + +```bash +ldk-server path/to/config.toml --node-network signet +``` + +## Environment Variables + +All environment variables use the `LDK_SERVER_` prefix. For example, `node.network` in the +TOML becomes `LDK_SERVER_NODE_NETWORK`, `bitcoind.rpc_address` becomes +`LDK_SERVER_BITCOIND_RPC_ADDRESS`, etc. See `ldk-server --help` for the full list of options +and their corresponding environment variables. + +```bash +LDK_SERVER_NODE_NETWORK=signet ldk-server /path/to/config.toml +``` + +## Config File + +Pass a TOML file as a positional argument: + +```bash +ldk-server /path/to/config.toml +``` + +If no file is provided, the server looks for `config.toml` in the default storage directory +(`~/.ldk-server/config.toml` on Linux, `~/Library/Application Support/ldk-server/config.toml` +on macOS). + +## Config Sections + +### `[node]` + +Core node settings: which Bitcoin network to use, Lightning peer listening and announcement +addresses, the gRPC bind address, node alias, and optional Rapid Gossip Sync / pathfinding +scores URLs. + +### `[storage.disk]` + +Where persistent data is stored. Defaults to `~/.ldk-server/` on Linux and +`~/Library/Application Support/ldk-server/` on macOS. + +### `[log]` + +Log level and file path. The server reopens the log file on `SIGHUP`, which integrates with +standard `logrotate` setups. + +### `[tls]` + +TLS certificate and key paths, plus additional hostnames/IPs for the certificate's Subject +Alternative Names. If no certificate exists, the server auto-generates a self-signed ECDSA +P-256 cert. `localhost` and `127.0.0.1` are always included in the SANs. Add your server's +public hostname or IP to `hosts` if clients connect remotely. + +To bring your own certificate (e.g., from Let's Encrypt), set `cert_path` and `key_path`. + +### Bitcoin Backend + +You must configure **exactly one** of the following sections: + +- **`[bitcoind]`** - Bitcoin Core RPC. **Recommended.** Most reliable and private option. + Required for production deployments. +- **`[electrum]`** - Electrum server. Lighter weight, but relies on a trusted third-party + server for chain data. +- **`[esplora]`** - Esplora HTTP API. Convenient for quick testing with a public block + explorer (e.g., mempool.space), but not recommended for production use. + +> **Warning:** When using Electrum or Esplora, LDK cannot verify Lightning gossip messages +> against the blockchain. This means a malicious peer could flood your node with fake channel +> announcements, consuming memory and disk. If your node is publicly reachable, use bitcoind. + +### `[liquidity.lsps2_client]` + +Connects to an [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md) +Liquidity Service Provider for just-in-time (JIT) inbound channel opening. When configured, +the `Bolt11ReceiveViaJitChannel` and `Bolt11ReceiveVariableAmountViaJitChannel` RPCs become +available, the LSP will open a channel on the fly when the generated invoice is paid. + +Requires the LSP's public key and address. Some LSPs also require an authentication token. + +### `[liquidity.lsps2_service]` + +> Requires building with `--features experimental-lsps2-support`. +> See [Build Features](getting-started.md#build-features). + +Configures the node to act as an LSPS2 liquidity service provider, opening JIT channels on +behalf of clients. This involves setting fee parameters (opening fee, minimum fee, overprovisioning +ratio), channel lifetime guarantees, payment size limits, and the trust model. + +The `client_trusts_lsp` flag controls when the funding transaction is broadcast: when enabled, +the LSP delays broadcasting until the client has claimed enough HTLC parts to cover the +channel opening cost. + +### `[metrics]` + +Enables a [Prometheus](https://prometheus.io/) metrics endpoint at `GET /metrics` on the gRPC port, with optional +Basic Auth. See [Operations](operations.md) for scrape configuration. + +### `[tor]` + +SOCKS proxy address for outbound Tor connections. **Only connections to OnionV3 peers** are +routed through the proxy, other connections (IPv4 peers, Electrum servers, Esplora endpoints) +are not proxied. This does not set up inbound connections, to make your node reachable as a +hidden service, you need to configure Tor separately. See the [Tor guide](tor.md) for the +full setup. + +## Storage Layout + +``` +/ + keys_seed # Node entropy/seed + tls.crt # TLS certificate (PEM) + tls.key # TLS private key (PEM) + / # e.g., bitcoin/, regtest/, signet/ + api_key # API key + ldk-server.log # Log file + ldk_node_data.sqlite # LDK Node state (channels, on-chain wallet) + ldk_server_data.sqlite # Payment and forwarding history +``` + +The `keys_seed` file is the node's master secret, required to recover on-chain funds. +`ldk_node_data.sqlite` holds channel state, both are required to recover channel funds. See +[Operations - Backups](operations.md#backups) for backup guidance. diff --git a/docs/getting-started.md b/docs/getting-started.md new file mode 100644 index 00000000..78e39e37 --- /dev/null +++ b/docs/getting-started.md @@ -0,0 +1,161 @@ +# Getting Started + +This guide walks you through building, configuring, and running your first LDK Server node. + +## Prerequisites + +- **Rust** 1.85.0 or later +- **A Bitcoin chain backend** (one of): + - [Bitcoin Core](https://bitcoincore.org/) (bitcoind) with RPC enabled + - An [Electrum](https://electrum.org/) server + - An [Esplora](https://github.com/Blockstream/esplora) API endpoint + +No other external dependencies are required. + +## Build + +```bash +git clone https://github.com/lightningdevkit/ldk-server.git +cd ldk-server +cargo build --release +``` + +The binaries are placed in `target/release/`: + +- `ldk-server` (the node daemon) +- `ldk-server-cli` (the command-line client) + +### Build Features + +`experimental-lsps2-support` — Enables the LSPS2 liquidity service provider. **Experimental — for testing only.** +Requires `[liquidity.lsps2_service]` in config. + +```bash +cargo build --release --features experimental-lsps2-support +``` + +## Configure + +Copy the annotated config template and edit it: + +```bash +cp contrib/ldk-server-config.toml my-config.toml +``` + +The only required decision is which Bitcoin backend to use. Keep **exactly one** of the +`[bitcoind]`, `[electrum]`, or `[esplora]` sections and remove the others. + +**Minimal regtest example** (using Bitcoin Core): + +```toml +[node] +network = "regtest" + +[bitcoind] +rpc_address = "127.0.0.1:18443" +rpc_user = "user" +rpc_password = "pass" +``` + +Everything else has sensible defaults. See [Configuration](configuration.md) for the full +reference. + +## Start the Server + +```bash +./target/release/ldk-server my-config.toml +``` + +On first startup, watch the logs for: + +``` +gRPC service listening on 127.0.0.1:3536 +NODE_URI: @
+``` + +Two files are auto-generated on first run: + +| File | Location | Purpose | +|-----------------|-----------------------------------|------------------------------------------| +| API key | `//api_key` | 32-byte random key (stored as raw bytes) | +| TLS certificate | `/tls.crt` | Self-signed ECDSA P-256 certificate | + +The default storage directory is `~/.ldk-server/` on Linux and +`~/Library/Application Support/ldk-server/` on macOS. + +### Reading the API Key + +The API key file contains raw bytes. To get the hex string the CLI and client library expect: + +```bash +xxd -p -c 64 ~/.ldk-server/bitcoin/api_key +``` + +## First Commands + +If the CLI and server share the same machine and use the default storage directory, the CLI +auto-discovers the API key and TLS certificate, so no flags are needed: + +```bash +# Check the node is running +ldk-server-cli get-node-info + +# Generate an on-chain funding address +ldk-server-cli onchain-receive + +# Check balances +ldk-server-cli get-balances +``` + +When running on a different machine or using a non-default storage path, pass the connection +details explicitly: + +```bash +ldk-server-cli \ + --base-url localhost:3536 \ + --api-key \ + --tls-cert /path/to/tls.crt \ + get-node-info +``` + +## CLI Tips + +### Amount Syntax + +Commands that accept amounts support `sat` and `msat` suffixes: + +```bash +ldk-server-cli bolt11-receive --amount 50000sat +ldk-server-cli bolt11-receive --amount 50000000msat # same as above +``` + +### Shell Completions + +Generate completions for your shell: + +```bash +# Bash (add to ~/.bashrc) +eval "$(ldk-server-cli completions bash)" + +# Zsh (add to ~/.zshrc) +eval "$(ldk-server-cli completions zsh)" + +# Fish (add to ~/.config/fish/config.fish) +ldk-server-cli completions fish | source +``` + +PowerShell and Elvish are also supported. Run `ldk-server-cli completions --help` for details. + +### Per-Command Help + +Every command supports `--help` for detailed argument descriptions: + +```bash +ldk-server-cli open-channel --help +``` + +## Next Steps + +- [Configuration](configuration.md): all config options, environment variables, and Bitcoin backend tradeoffs +- [API Guide](api-guide.md): gRPC transport, authentication, and endpoint reference +- [Operations](operations.md): production deployment, backups, and monitoring diff --git a/docs/operations.md b/docs/operations.md new file mode 100644 index 00000000..1a8935dd --- /dev/null +++ b/docs/operations.md @@ -0,0 +1,167 @@ +# Operations Guide + +This guide covers running LDK Server in production: process management, backups, security, +monitoring, and remote access. + +## Process Management + +### systemd + +LDK Server integrates with systemd via `sd_notify`. It sends `READY=1` after the gRPC listener +is bound and `STOPPING=1` when shutting down. A sample unit file can be found in [ +`contrib/ldk-server.service`](../contrib/ldk-server.service). + +### Graceful Shutdown + +The server handles `SIGTERM` and `CTRL-C` (SIGINT). On receipt, it: + +1. Signals all active streaming clients (SubscribeEvents) to disconnect +2. Stops the LDK Node (persists channel state) +3. Exits cleanly + +### Log Rotation + +> **Important:** LDK Server does not rotate or truncate its own log file. Without log rotation +> configured, the log file will grow indefinitely and can eventually fill your disk. A full +> disk can prevent the node from persisting channel state, risking fund loss. + +The server reopens its log file on `SIGHUP`. This integrates with standard `logrotate`. Save +the following config to `/etc/logrotate.d/ldk-server` (adjust the log path to match your +setup): + +``` +/var/lib/ldk-server/regtest/ldk-server.log { + daily + rotate 14 + compress + missingok + notifempty + postrotate + systemctl kill --signal=HUP ldk-server.service + endscript +} +``` + +## Backups + +### What to Back Up + +| File | Priority | Description | +|----------------------------------------|--------------|----------------------------------------------------------------------------| +| `/keys_seed` | **Critical** | Node identity and master secret. Required to recover on-chain funds. | +| `/ldk_node_data.sqlite` | **Critical** | Channel state and on-chain wallet data. Required to recover channel funds. | +| `/ldk_server_data.sqlite` | Nice-to-have | Payment and forwarding history | + +### What is Reconstructable + +- Network graph data (re-synced from gossip or RGS) +- Fee rate cache (re-fetched from the chain backend) +- The API key (can be regenerated, but clients will need the new one) +- The TLS certificate (can be regenerated, but clients will need the new one) + +> **Warning:** Do not restore a backup onto two running nodes simultaneously. Running the +> same node identity on two instances will cause channel state conflicts and potential fund +> loss. + +## Security + +### API Key + +- Auto-generated as 32 random bytes on first startup +- Stored at `/api_key` with `0400` permissions (read-only for owner) +- The hex-encoded form of this key is used for HMAC authentication +- Treat it as a secret: anyone with the API key and network access to the gRPC port can + control the node + +### TLS + +- Self-signed ECDSA P-256 certificate generated automatically +- Private key stored at `/tls.key` with `0400` permissions +- Certificate includes `localhost` and `127.0.0.1` in SANs by default +- Add your server's hostname/IP to `[tls] hosts` for remote access + +### Network Exposure + +The gRPC service binds to `127.0.0.1:3536` by default. For remote access, either: + +1. Change `grpc_service_address` to bind to `0.0.0.0:3536` and add the server's hostname to + `[tls] hosts`, or +2. Use a reverse proxy (e.g., nginx, Caddy) that terminates TLS and forwards to the loopback + address + +## Monitoring + +### Prometheus Metrics + +LDK Server can expose metrics in [Prometheus](https://prometheus.io/) text format. +Prometheus is an open-source monitoring toolkit that scrapes HTTP endpoints and stores +time-series data for alerting and dashboards. + +Enable metrics in the config: + +```toml +[metrics] +enabled = true +poll_metrics_interval = 60 +``` + +Metrics are served at `GET /metrics` on the same port as the gRPC service (default 3536). +This is a plain HTTP endpoint (not gRPC), returning Prometheus text format. + +Basic Auth is recommended to prevent unauthorized access to node metrics: + +```toml +[metrics] +enabled = true +username = "prometheus" +password = "secret" +``` + +The Prometheus scrape config would then use: + +```yaml +scrape_configs: + - job_name: ldk-server + scheme: https + tls_config: + ca_file: /path/to/tls.crt + basic_auth: + username: prometheus + password: secret + static_configs: + - targets: [ 'localhost:3536' ] +``` + +### Available Metrics + +Metrics cover: + +- On-chain and Lightning balances +- Public and Private Channel counts +- Payment counts (successful, failed, pending) +- Peer count + +## Remote Access + +To allow clients to connect from other machines: + +1. **Update TLS hosts:** Add the server's hostname or IP to `[tls] hosts` in the config so + the certificate's SANs cover the address clients will use. +2. **Update bind address:** Set `grpc_service_address` to bind on the appropriate interface + (e.g., `0.0.0.0:3536`). +3. **Distribute the TLS certificate:** Copy `/tls.crt` to each client machine. + Clients must pin this certificate since it is self-signed. +4. **Share the API key:** Provide the hex-encoded API key to authorized clients. + +If you regenerate the TLS certificate (by deleting `tls.crt` and `tls.key` and restarting), +all clients will need the new certificate. + +## Network-Specific Notes + +Data is stored in per-network subdirectories (`bitcoin/`, `testnet/`, `signet/`, `regtest/`, +etc.) under the storage root. This means you can run multiple networks from one storage +directory without conflicts. + +The `keys_seed` file is shared across networks (stored at the storage root, not per-network). +Keys are split by network at the derivation path level, so the same seed will produce +different keys. diff --git a/docs/tor.md b/docs/tor.md new file mode 100644 index 00000000..699f1403 --- /dev/null +++ b/docs/tor.md @@ -0,0 +1,106 @@ +# Tor + +> **Warning:** Tor support in LDK Server applies **only when connecting outbound to +> `.onion` Lightning peers**. Connections to clearnet peers are not routed through +> Tor exit nodes. All other connections, including Electrum servers, Esplora endpoints, and +> Rapid Gossip Sync (RGS) servers, are also **not** routed through Tor and will use your +> normal network connection. +> If you require full network privacy, you should use a local bitcoind node as your chain +> source. Support for routing these connections through Tor may be added in the future. + +LDK Server supports connecting to peers over Tor. This guide covers both outbound connections +(connecting to `.onion` peers) and inbound connections (making your node reachable as a hidden +service). + +## Installing Tor + +Follow tor's official installation instructions for your platform: https://support.torproject.org/little-t-tor/getting-started/installing/ + +The Tor daemon listens on `127.0.0.1:9050` by default. + +## Outbound Connections + +The `[tor]` section in the config sets a SOCKS proxy for outbound connections to OnionV3 peers: + +```toml +[tor] +proxy_address = "127.0.0.1:9050" +``` + +This requires a running Tor daemon with a SOCKS port. Only connections to `.onion` peers use +the proxy. Connections to IPv4/IPv6 peers, Electrum servers, and Esplora endpoints are **not** +routed through Tor. + +## Inbound Connections + +To make your node reachable as a Tor hidden service, you need to configure Tor itself. LDK +Server does not manage this automatically. + +### 1. Configure the Hidden Service + +Edit your `torrc` file (typically `/etc/tor/torrc`): + +``` +HiddenServiceDir /var/lib/tor/ldk-server/ +HiddenServicePort 9735 127.0.0.1:9735 +``` + +This tells Tor to forward incoming connections on port 9735 of the hidden service to your +node's local Lightning listening port. Adjust the local port to match your +`node.listening_addresses` config. + +### 2. Restart Tor + +```bash +sudo systemctl restart tor +``` + +### 3. Get Your Onion Address + +After restarting, Tor generates your `.onion` address: + +```bash +sudo cat /var/lib/tor/ldk-server/hostname +``` + +This outputs something like `abcdef...xyz.onion`. + +### 4. Configure LDK Server + +Set the onion address as an announcement address so other nodes can find you: + +```toml +[node] +listening_addresses = ["localhost:9735"] +announcement_addresses = ["abcdef...xyz.onion:9735"] + +[tor] +proxy_address = "127.0.0.1:9050" +``` + +- `listening_addresses`: the local address your node actually listens on +- `announcement_addresses`: the public address announced to the network (your `.onion` address) +- `proxy_address`: needed so your node can also connect outbound to other `.onion` peers + +### 5. Verify + +After starting LDK Server, confirm your onion address appears in the node info: + +```bash +ldk-server-cli get-node-info +``` + +The `node_uris` field should include `@abcdef...xyz.onion:9735`. Other nodes can +now connect to you over Tor using this URI. + +## Dual-Stack (Clearnet + Tor) + +You can announce both a clearnet address and an onion address: + +```toml +[node] +listening_addresses = ["0.0.0.0:9735"] +announcement_addresses = ["203.0.113.1:9735", "abcdef...xyz.onion:9735"] +``` + +This makes your node reachable over both the public internet and Tor. diff --git a/ldk-server-cli/README.md b/ldk-server-cli/README.md new file mode 100644 index 00000000..d28caa16 --- /dev/null +++ b/ldk-server-cli/README.md @@ -0,0 +1,45 @@ +# ldk-server-cli + +Command-line client for interacting with a running [LDK Server](https://github.com/lightningdevkit/ldk-server) +node. + +## Installation + +```bash +cargo install ldk-server-cli --locked +``` + +Or build from the repository root: + +```bash +cargo build --release -p ldk-server-cli +``` + +## Prerequisites + +A running LDK Server instance. See the [Getting Started](../docs/getting-started.md) guide. + +## Quick Start + +If the CLI and server are on the same machine with default paths, no flags are needed: + +```bash +ldk-server-cli get-node-info +ldk-server-cli onchain-receive +ldk-server-cli get-balances +``` + +When using custom paths or connecting remotely: + +```bash +ldk-server-cli \ + --base-url localhost:3536 \ + --api-key \ + --tls-cert /path/to/tls.crt \ + get-node-info +``` + +## Documentation + +- [Getting Started](../docs/getting-started.md): first-run walkthrough, shell completions, and CLI tips +- [API Guide](../docs/api-guide.md): gRPC API details and endpoint reference diff --git a/ldk-server-client/README.md b/ldk-server-client/README.md new file mode 100644 index 00000000..65648a5b --- /dev/null +++ b/ldk-server-client/README.md @@ -0,0 +1,73 @@ +# ldk-server-client + +Async Rust client library for communicating with an [LDK Server](https://github.com/lightningdevkit/ldk-server) +node over gRPC. Uses `reqwest` for unary RPCs and `hyper` for server-streaming (event +subscriptions). + +## Usage + +```rust,no_run +use ldk_server_client::client::LdkServerClient; +use ldk_server_client::ldk_server_grpc::api::GetNodeInfoRequest; + +# #[tokio::main] +# async fn main() { +let cert_pem = std::fs::read("/path/to/tls.crt").unwrap(); +let api_key = "your_hex_api_key".to_string(); + +let client = LdkServerClient::new( + "localhost:3536".to_string(), + api_key, + &cert_pem, +).unwrap(); + +let info = client.get_node_info(GetNodeInfoRequest {}).await.unwrap(); +println!("Node ID: {}", info.node_id); +# } +``` + +## Authentication + +The client handles HMAC-SHA256 authentication automatically. Pass the hex-encoded API key +(found at `//api_key`) and the server's TLS certificate (found at +`/tls.crt`). + +## Event Streaming + +Subscribe to real-time payment events: + +```rust,no_run +# use ldk_server_client::client::LdkServerClient; +# #[tokio::main] +# async fn main() { +# let cert_pem = std::fs::read("/path/to/tls.crt").unwrap(); +# let client = LdkServerClient::new("localhost:3536".to_string(), "key".to_string(), &cert_pem).unwrap(); +let mut stream = client.subscribe_events().await.unwrap(); +while let Some(result) = stream.next_message().await { + match result { + Ok(event) => println!("Event: {:?}", event), + Err(e) => eprintln!("Error: {}", e), + } +} +# } +``` + +## Features + +- **`serde`**: Enables `serde::Serialize` and `serde::Deserialize` on all proto types + (via `ldk-server-grpc/serde`). Useful for JSON serialization. + +## Error Handling + +All methods return `Result`. Error codes map to gRPC status codes: + +| `LdkServerErrorCode` | gRPC Code | Meaning | +|-----------------------|-------------------------|---------------------------| +| `InvalidRequestError` | INVALID_ARGUMENT (3) | Bad request parameters | +| `LightningError` | FAILED_PRECONDITION (9) | Lightning operation error | +| `InternalServerError` | INTERNAL (13) | Server bug | +| `AuthError` | UNAUTHENTICATED (16) | Invalid credentials | + +## Documentation + +- [API Guide](../docs/api-guide.md): full endpoint reference, auth details, and usage patterns diff --git a/ldk-server-client/src/lib.rs b/ldk-server-client/src/lib.rs index ab89afe8..4959f127 100644 --- a/ldk-server-client/src/lib.rs +++ b/ldk-server-client/src/lib.rs @@ -7,17 +7,16 @@ // You may not use this file except in accordance with one or both of these // licenses. -//! Client-side library to interact with LDK Server. - +#![doc = include_str!("../README.md")] #![deny(rustdoc::broken_intra_doc_links)] #![deny(rustdoc::private_intra_doc_links)] #![deny(missing_docs)] -/// Implements a ldk-ldk-server-client ([`client::LdkServerClient`]) to access a hosted instance of LDK Server. +/// Implements a [`LdkServerClient`](client::LdkServerClient) to access a hosted instance of LDK Server. pub mod client; -/// Implements the error type ([`error::LdkServerError`]) returned on interacting with [`client::LdkServerClient`] +/// Implements the error type ([`LdkServerError`](error::LdkServerError)) returned on interacting with [`LdkServerClient`](client::LdkServerClient). pub mod error; -/// Request/Response structs required for interacting with the ldk-ldk-server-client. +/// Request/Response structs required for interacting with the client. pub use ldk_server_grpc; diff --git a/ldk-server-grpc/README.md b/ldk-server-grpc/README.md new file mode 100644 index 00000000..d6a55a7b --- /dev/null +++ b/ldk-server-grpc/README.md @@ -0,0 +1,46 @@ +# ldk-server-grpc + +Canonical Protocol Buffer definitions for the [LDK Server](https://github.com/lightningdevkit/ldk-server) +API, along with generated Rust types and shared gRPC primitives. + +This crate has **no LDK dependency** and can be used by anyone who wants to speak the LDK +Server wire protocol. + +## Proto Files + +The proto definitions live in `src/proto/`: + +| File | Contents | +|------|----------| +| `api.proto` | RPC request/response messages with documentation | +| `types.proto` | Shared types: Payment, Channel, Peer, ForwardedPayment, etc. | +| `events.proto` | Event envelope and event types for streaming | +| `error.proto` | Error response definitions | + +## Using from Other Languages + +The proto files can be compiled with any standard `protoc` toolchain to generate clients in +Go, Python, TypeScript, Java, etc. Point your proto compiler at the `src/proto/` directory. + +## Regenerating Rust Bindings + +After modifying any `.proto` file: + +```bash +RUSTFLAGS="--cfg genproto" cargo build -p ldk-server-grpc +cargo fmt --all +``` + +This requires `protoc` to be installed. + +## Features + +- **`serde`**: Enables `serde::Serialize` and `serde::Deserialize` on all generated types, + with custom serialization for hex-encoded fields. + +## Additional Rust Modules + +Beyond the generated types, this crate provides: + +- `grpc`: gRPC frame encoding/decoding, error response helpers, request validation +- `endpoints`: Path constants for all RPC methods (e.g., `GRPC_SERVICE_PREFIX`, `GET_NODE_INFO_PATH`) diff --git a/ldk-server-grpc/src/lib.rs b/ldk-server-grpc/src/lib.rs index 56dc2228..69ef1f8a 100644 --- a/ldk-server-grpc/src/lib.rs +++ b/ldk-server-grpc/src/lib.rs @@ -7,6 +7,8 @@ // You may not use this file except in accordance with one or both of these // licenses. +#![doc = include_str!("../README.md")] + pub mod api; pub mod endpoints; pub mod error; diff --git a/ldk-server/README.md b/ldk-server/README.md new file mode 100644 index 00000000..2f232798 --- /dev/null +++ b/ldk-server/README.md @@ -0,0 +1,25 @@ +# ldk-server + +The main LDK Server daemon. This is a Lightning Network node that exposes a gRPC API over +HTTP/2 with TLS, built on [LDK Node](https://github.com/lightningdevkit/ldk-node). + +## Running + +```bash +cargo run --release --bin ldk-server /path/to/config.toml +``` + +See the [Getting Started](../docs/getting-started.md) guide for a full walkthrough. + +## Configuration + +A fully annotated config template is provided at +[ldk-server-config.toml](ldk-server-config.toml). See +[Configuration](../docs/configuration.md) for details on all options, environment variables, +and Bitcoin backend choices. + +## Documentation + +- [Getting Started](../docs/getting-started.md): build, configure, and run your first node +- [API Guide](../docs/api-guide.md): gRPC transport, authentication, and endpoint reference +- [Operations](../docs/operations.md): production deployment, backups, and monitoring