Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Redis & Dynamic Configuration

The module supports real-time configuration updates via Redis without requiring an Nginx reload.

Setup

Environment=REDIS_URL=redis://127.0.0.1:6379

Dynamic Pricing

Set the price for a specific path in Redis. Changes are picked up immediately by the next request.

# Set price to 1000 msats for /api/resource
SET /api/resource 1000

# Set price to 5000 msats for /api/premium
SET /api/premium 5000

Note: If no Redis key exists for a path, the module falls back to l402_amount_msat_default in nginx.conf.


Dynamic LNURL (Per-Tenant Routing)

Override the LNURL address for a specific request path. This takes precedence over l402_lnurl_addr in nginx.conf.

Key format: lnurl:<request_path>

# Route /api/tenant1 payments to alice
SET lnurl:/api/tenant1 alice@getalby.com

# Route /api/tenant2 payments to bob
SET lnurl:/api/tenant2 bob@getalby.com

Note

These keys set the payout destination for a route — for Lightning invoices and for Cashu redemption, where a token accepted on a route is melted to the LNURL that route maps to. Redis is a trusted component here: bind it to a private interface, set requirepass, and limit write access to tenant configuration.


Replay Attack Prevention

Redis is used to enforce single-use of L402 preimages and Cashu tokens, preventing replay attacks across distributed deployments.

Environment=REDIS_URL=redis://127.0.0.1:6379
Environment=L402_PREIMAGE_TTL_SECONDS=86400      # Default: 24 hours
Environment=L402_CASHU_TOKEN_TTL_SECONDS=86400   # Default: 24 hours

How it works: After successful verification, a SHA-256 hash of the preimage or token is stored in Redis, and reusing the credential is rejected with 401. Protection persists across Nginx restarts and works with multiple Nginx instances.

A preimage’s marker lives for L402_PREIMAGE_TTL_SECONDS or the macaroon’s own timeout, whichever is longer. On routes with l402_macaroon_timeout 0 it never expires, because neither does the macaroon. A Cashu token’s marker lives for L402_CASHU_TOKEN_TTL_SECONDS.


Invoice Rate Limiting

Limits how many invoices (402 responses) a single IP can request per route within a time window. This protects your Lightning node from invoice-spam without affecting clients that hold a valid token.

location /api/resource {
    l402 on;
    l402_amount_msat_default 1000;
    l402_invoice_rate_limit 5r/m;   # 5 invoices per minute per IP
}

Supported formats:

ValueLimit
5r/m5 per minute
10r/h10 per hour
2r/s2 per second
55 per minute (shorthand)

Requests that exceed the limit receive 429 Too Many Requests with a Retry-After header set to the window duration.

The rate limit only applies to unauthenticated requests (those that would result in a 402). Requests presenting a valid L402 token bypass it entirely.

How it works: Uses a fixed-window Redis counter (INCR + EXPIRE on first hit) keyed by IP and path. Fails open — if Redis is unavailable, rate limiting is disabled and traffic passes through normally.


Keys the Module Writes

KeyHoldsExpires
<path>Dynamic price you setNever — you manage it
lnurl:<path>Per-route LNURL override you setNever — you manage it
l402:preimage:<sha256>Spent Lightning preimageSee Replay Attack Prevention
l402:cashu_token:<sha256>Spent Cashu token: a hash of the token, or in P2PK mode of its proofs, so a re-encoded token still matchesL402_CASHU_TOKEN_TTL_SECONDS
l402:settled:<payment hash>Settled preimage cached by auto-detectL402_PREIMAGE_TTL_SECONDS
l402:invoice_rate:<sha256>Invoice rate-limit counter for a client and routeThe rate-limit window
cashu:proof_lnurl:<sha256>Which tenant a Cashu proof belongs to20 redemption intervals — see Multi-Tenant

Run Redis with maxmemory-policy noeviction: an evicted replay marker makes its credential usable again.