Problem: Using HTTP redirects for Lightning Address (sats@example.com → user@getalby.com) adds 200-500ms latency because wallets must follow the redirect before fetching the LNURL-pay response.
Solution: Replace redirects with an Edge Function proxy that fetches from Alby server-side and returns the response directly.
Before (redirect):
Wallet → example.com → 302 redirect → Wallet → getalby.com → response
After (proxy):
Wallet → example.com → [edge fetches getalby.com] → response
The wallet makes one request. The server-to-server fetch happens on fast edge networks (even faster than regular serverless functions).
- Lower latency: Run at the edge, closer to users (~10-50ms vs ~50-100ms for serverless)
- Simpler setup: No build step, TypeScript runs directly
- Free tier: 3 million invocations/month (vs 125k for serverless functions)
import type { Context, Config } from "@netlify/edge-functions";
export default async (req: Request, context: Context) => {
const url = new URL(req.url);
const pathParts = url.pathname.split('/');
const username = pathParts[pathParts.length - 1];
// All aliases map to the same Alby account
const validUsernames = ['sats', 'user', 'zap'];
if (!validUsernames.includes(username)) {
return new Response(JSON.stringify({
status: "ERROR",
reason: "User not found"
}), {
status: 404,
headers: { "Content-Type": "application/json" }
});
}
// Fetch from Alby
const albyResponse = await fetch(
"https://getalby.com/.well-known/lnurlp/YOUR_ALBY_USERNAME"
);
if (!albyResponse.ok) {
return new Response(JSON.stringify({
status: "ERROR",
reason: "Upstream error"
}), {
status: 502,
headers: { "Content-Type": "application/json" }
});
}
const data = await albyResponse.json();
// Rewrite metadata to show vanity address instead of Alby address
if (data.metadata) {
data.metadata = data.metadata.replace(
'YOUR_ALBY_USERNAME@getalby.com',
`${username}@example.com`
);
}
return new Response(JSON.stringify(data), {
status: 200,
headers: {
"Content-Type": "application/json",
"Cache-Control": "no-store"
}
});
};
export const config: Config = {
path: "/.well-known/lnurlp/*"
};npm install --save-dev @netlify/edge-functionsIf you had redirects in _redirects or netlify.toml for /.well-known/lnurlp/*, remove them. Edge Functions take precedence, but cleaner to remove.
- validUsernames: Array of aliases that map to your Alby account (e.g.,
sats,user,zap) - Alby URL: Replace
YOUR_ALBY_USERNAMEwith your actual Alby username - Metadata rewrite: The
text/identifierin Alby's response tells wallets the recipient address. Without rewriting it, wallets displayyou@getalby.cominstead of your vanity address.
- Vanity address preserved (
sats@example.com) - Single HTTP request from wallet perspective
- Edge-to-origin fetch is fast (~10-50ms)
- Free tier: 3 million edge function invocations/month
# Local
netlify dev
curl http://localhost:8888/.well-known/lnurlp/sats
# Should return JSON with "status": "OK", not a redirectTested from US East, November 2025:
| Method | Avg Latency | Requests | Vanity Address |
|---|---|---|---|
| Direct to Alby | ~80ms | 1 | No |
| Edge Proxy | ~220ms | 1 | Yes |
| 302 Redirect | ~305ms | 2 | No |
The edge proxy is ~85ms faster than redirects. Redirects require two round-trips from the wallet (302 response + Alby fetch), while the proxy handles the Alby fetch server-side on fast edge networks.
Bonus: The proxy rewrites metadata so wallets display your vanity address (sats@example.com) instead of the upstream provider (user@getalby.com).
- Wallet parses
sats@example.com→ querieshttps://example.com/.well-known/lnurlp/sats - Server returns LNURL-pay JSON with callback URL, min/max amounts, metadata
- Wallet requests invoice from callback URL
- Payment executes
The proxy intercepts step 2, fetching from Alby and returning the response as if it originated from your domain.