Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contrib/ldk-server-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ level = "Debug" # Log level (Error, Warn, Info, De
[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
# For CA-signed certs, point cert_path/key_path to your ACME output files.
#hosts = ["example.com"] # Allowed hosts for TLS, will always include "localhost" and "127.0.0.1"

# Must set one of bitcoind, electrum, or esplora
Expand Down
4 changes: 3 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@ Alternative Names. If no certificate exists, the server auto-generates a self-si
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`.
To bring your own certificate (for example, from a public CA), set `cert_path` and
`key_path`. The server reads these files on startup, so renewals require a restart.
See [Operations - TLS](operations.md#tls) for a recommended CA-signed flow.

### Bitcoin Backend

Expand Down
37 changes: 35 additions & 2 deletions docs/operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ setup):
### What to Back Up

| File | Priority | Description |
|----------------------------------------|--------------|----------------------------------------------------------------------------|
| -------------------------------------- | ------------ | -------------------------------------------------------------------------- |
| `<storage_dir>/keys_seed` | **Critical** | Node identity and master secret. Required to recover on-chain funds. |
| `<network_dir>/ldk_node_data.sqlite` | **Critical** | Channel state and on-chain wallet data. Required to recover channel funds. |
| `<network_dir>/ldk_server_data.sqlite` | Nice-to-have | Payment and forwarding history |
Expand Down Expand Up @@ -80,6 +80,39 @@ setup):
- Certificate includes `localhost` and `127.0.0.1` in SANs by default
- Add your server's hostname/IP to `[tls] hosts` for remote access

### CA-Signed Certificates (Let's Encrypt / ACME)

For production deployments, many operators prefer a publicly trusted certificate. The
recommended approach is to provision the certificate outside of LDK Server (via an ACME
client) and point `[tls] cert_path` and `key_path` to the resulting files.

High-level flow:

1. Choose a public hostname for the gRPC endpoint (e.g., `ldk.example.com`).
2. Set `grpc_service_address` to bind on the public interface.
3. Add the hostname to `[tls] hosts` so SANs match what clients connect to.
4. Use an ACME client (certbot, lego, acme.sh) to obtain a certificate for the hostname.
5. Configure `[tls] cert_path` and `key_path` to the ACME output files.
6. Restart the server after renewals (LDK Server reads TLS files at startup).

Example (certbot with a pre-provisioned DNS or HTTP-01 flow):

```toml
[node]
grpc_service_address = "0.0.0.0:3536"

[tls]
cert_path = "/etc/letsencrypt/live/ldk.example.com/fullchain.pem"
key_path = "/etc/letsencrypt/live/ldk.example.com/privkey.pem"
hosts = ["ldk.example.com"]
```

Notes:

- Ensure the `ldk-server` process can read the cert and key files.
- After a renewal, restart the service to pick up the new certificate.
- If you want zero-downtime renewals, place a reverse proxy in front and terminate TLS there.

### Network Exposure

The gRPC service binds to `127.0.0.1:3536` by default. For remote access, either:
Expand Down Expand Up @@ -129,7 +162,7 @@ scrape_configs:
username: prometheus
password: secret
static_configs:
- targets: [ 'localhost:3536' ]
- targets: ["localhost:3536"]
```

### Available Metrics
Expand Down