$npx -y skills add lightninglabs/lightning-agent-tools --skill apertureInstall and run Aperture, the L402 Lightning reverse proxy from Lightning Labs. Use when creating L402 paywalls, configuring paid API endpoints, hosting paid content for other agents, or testing L402 authentication flows.
| 1 | # Aperture - L402 Lightning Reverse Proxy |
| 2 | |
| 3 | Aperture is a reverse proxy that implements the L402 protocol, enabling |
| 4 | payment-gated API access via the Lightning Network. It sits in front of your |
| 5 | backend services and requires Lightning micropayments before granting access. |
| 6 | |
| 7 | **Source:** `github.com/lightninglabs/aperture` |
| 8 | |
| 9 | ## Quick Start |
| 10 | |
| 11 | ```bash |
| 12 | # 1. Install aperture |
| 13 | skills/aperture/scripts/install.sh |
| 14 | |
| 15 | # 2. Generate config (connects to local lnd) |
| 16 | skills/aperture/scripts/setup.sh |
| 17 | |
| 18 | # 3. Ensure invoice.macaroon exists (required for L402 invoice creation) |
| 19 | # If not present, bake one with the macaroon-bakery skill: |
| 20 | skills/macaroon-bakery/scripts/bake.sh --role invoice-only \ |
| 21 | --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon |
| 22 | |
| 23 | # 4. Start aperture |
| 24 | skills/aperture/scripts/start.sh |
| 25 | |
| 26 | # 5. Test with lnget |
| 27 | lnget -k --no-pay https://localhost:8081/api/test |
| 28 | ``` |
| 29 | |
| 30 | ## How Aperture Works |
| 31 | |
| 32 | 1. Client requests a protected resource through Aperture |
| 33 | 2. Aperture responds with HTTP 402 + `WWW-Authenticate: L402` header containing |
| 34 | a macaroon and a Lightning invoice |
| 35 | 3. Client pays the invoice and obtains the preimage |
| 36 | 4. Client retries with `Authorization: L402 <macaroon>:<preimage>` |
| 37 | 5. Aperture validates the token and proxies to the backend service |
| 38 | |
| 39 | ## Installation |
| 40 | |
| 41 | ```bash |
| 42 | skills/aperture/scripts/install.sh |
| 43 | ``` |
| 44 | |
| 45 | This will: |
| 46 | - Verify Go is installed |
| 47 | - Run `go install github.com/lightninglabs/aperture/cmd/aperture@latest` |
| 48 | - Verify `aperture` is on `$PATH` |
| 49 | |
| 50 | To install manually: |
| 51 | |
| 52 | ```bash |
| 53 | go install github.com/lightninglabs/aperture/cmd/aperture@latest |
| 54 | ``` |
| 55 | |
| 56 | Or build from source: |
| 57 | |
| 58 | ```bash |
| 59 | git clone https://github.com/lightninglabs/aperture.git |
| 60 | cd aperture |
| 61 | make install |
| 62 | ``` |
| 63 | |
| 64 | ## Setup |
| 65 | |
| 66 | ```bash |
| 67 | skills/aperture/scripts/setup.sh |
| 68 | ``` |
| 69 | |
| 70 | This generates `~/.aperture/aperture.yaml` from the config template with |
| 71 | sensible defaults. The setup script auto-detects the local lnd node paths. |
| 72 | |
| 73 | **Options:** |
| 74 | |
| 75 | ```bash |
| 76 | # Custom network |
| 77 | setup.sh --network testnet |
| 78 | |
| 79 | # Custom lnd paths |
| 80 | setup.sh --lnd-host localhost:10009 \ |
| 81 | --lnd-tls ~/.lnd/tls.cert \ |
| 82 | --lnd-macdir ~/.lnd/data/chain/bitcoin/mainnet |
| 83 | |
| 84 | # Custom listen port |
| 85 | setup.sh --port 8081 |
| 86 | |
| 87 | # Disable TLS (development only) |
| 88 | setup.sh --insecure |
| 89 | |
| 90 | # Disable auth (no payments required) |
| 91 | setup.sh --no-auth |
| 92 | ``` |
| 93 | |
| 94 | ## Running Aperture |
| 95 | |
| 96 | ### Start |
| 97 | |
| 98 | ```bash |
| 99 | skills/aperture/scripts/start.sh |
| 100 | ``` |
| 101 | |
| 102 | Starts aperture as a background process reading `~/.aperture/aperture.yaml`. |
| 103 | |
| 104 | **Options:** |
| 105 | |
| 106 | ```bash |
| 107 | start.sh --foreground # Run in foreground |
| 108 | start.sh --config /path/to # Custom config path |
| 109 | ``` |
| 110 | |
| 111 | ### Stop |
| 112 | |
| 113 | ```bash |
| 114 | skills/aperture/scripts/stop.sh |
| 115 | ``` |
| 116 | |
| 117 | ## Configuration |
| 118 | |
| 119 | Config file: `~/.aperture/aperture.yaml` |
| 120 | |
| 121 | ### Invoice Macaroon Requirement |
| 122 | |
| 123 | Aperture requires `invoice.macaroon` in the configured `macdir` to create |
| 124 | Lightning invoices for L402 challenges. This is **not** the same as |
| 125 | `admin.macaroon`. If the macaroon is missing, aperture will fail to start or |
| 126 | will return errors when clients request paid resources. |
| 127 | |
| 128 | To bake an invoice macaroon with the macaroon-bakery skill: |
| 129 | |
| 130 | ```bash |
| 131 | skills/macaroon-bakery/scripts/bake.sh --role invoice-only \ |
| 132 | --save-to ~/.lnd/data/chain/bitcoin/mainnet/invoice.macaroon |
| 133 | ``` |
| 134 | |
| 135 | The `setup.sh` script will warn you if `invoice.macaroon` is not found at the |
| 136 | expected path. |
| 137 | |
| 138 | ### Minimal Agent Configuration |
| 139 | |
| 140 | This is the minimal config for an agent hosting paid endpoints with a local |
| 141 | lnd node: |
| 142 | |
| 143 | ```yaml |
| 144 | listenaddr: "localhost:8081" |
| 145 | insecure: true |
| 146 | debuglevel: "info" |
| 147 | dbbackend: "sqlite" |
| 148 | sqlite: |
| 149 | dbfile: "~/.aperture/aperture.db" |
| 150 | |
| 151 | authenticator: |
| 152 | network: "mainnet" |
| 153 | lndhost: "localhost:10009" |
| 154 | tlspath: "~/.lnd/tls.cert" |
| 155 | macdir: "~/.lnd/data/chain/bitcoin/mainnet" |
| 156 | |
| 157 | services: |
| 158 | - name: "my-api" |
| 159 | hostregexp: ".*" |
| 160 | pathregexp: "^/api/.*$" |
| 161 | address: "127.0.0.1:8080" |
| 162 | protocol: http |
| 163 | price: 100 |
| 164 | ``` |
| 165 | |
| 166 | ### Service Configuration |
| 167 | |
| 168 | Each service entry defines a backend to protect: |
| 169 | |
| 170 | ```yaml |
| 171 | services: |
| 172 | - name: "service-name" |
| 173 | # Match requests by host (regex). |
| 174 | hostregexp: "^api.example.com$" |
| 175 | |
| 176 | # Match requests by path (regex). |
| 177 | pathregexp: "^/paid/.*$" |
| 178 | |
| 179 | # Backend address to proxy to. |
| 180 | address: "127.0.0.1:8080" |
| 181 | |
| 182 | # Protocol: http or https. |
| 183 | protocol: http |
| 184 | |
| 185 | # Static price in satoshis. |
| 186 | price: 100 |
| 187 | |
| 188 | # Macaroon capabilities granted at base tier. |
| 189 | capabilities: "read,write" |
| 190 | |
| 191 | # Token expiry in seconds (31557600 = 1 year). |
| 192 | timeout: 31557600 |
| 193 | |
| 194 | # Paths exempt from payment. |
| 195 | authwhitelistpaths: |
| 196 | - "^/health$" |
| 197 | - "^/public/.*$" |
| 198 | |
| 199 | # Per-endpoint rate limits (token bucket). |
| 200 | ratelimits: |
| 201 | - pathregexp: "^/api/query.*$" |
| 202 | requests: 10 |
| 203 | per: 1s |
| 204 | burst: 20 |
| 205 | ``` |
| 206 | |
| 207 | ### Authentication Backends |
| 208 | |
| 209 | #### Direct LND Connection |
| 210 | |
| 211 | ```yaml |
| 212 | authenticator: |
| 213 | ne |