NAT & Port Forwarding
debt(d9/e3/b3/t7)
Closest to 'silent in production until users hit it' (d9). The detection_hints note automated=no and the code_pattern describes a webhook endpoint simply not receiving events — no compiler, linter, or static tool flags this. The tools listed (ngrok, localtunnel, cloudflare-tunnel) are workarounds, not detectors. The failure manifests silently: the app runs fine locally, Stripe/OAuth callbacks just never arrive, and the developer must infer the cause from missing events in production or testing.
Closest to 'simple parameterised fix' (e3). The quick_fix points to using ngrok for local webhook development — a small, contained change (install ngrok, expose local port, update webhook URL in the third-party dashboard). It's more than a one-line patch (e1) because it involves environment setup and updating callback URLs, but it stays within one component/workflow rather than touching multiple files.
Closest to 'localised tax' (b3). The applies_to scope is web and cli contexts, but the burden is largely confined to local development and deployment configuration. Once understood and resolved (via ngrok, proper port forwarding, or a tunnel), the ongoing tax is low. It doesn't shape every future change, but developers on the team do need to remember to run a tunnel when testing webhooks.
Closest to 'serious trap' (t7). The misconception field explicitly states that 'NAT provides security by hiding internal IPs' — a widespread belief that contradicts how NAT actually works (IP conservation, not a firewall). This leads to real security decisions being made on a false premise (relying on NAT as a security boundary is listed as a common mistake). This contradicts how similar 'hiding' mechanisms work in other contexts, making it a serious cognitive trap for competent developers.
Also Known As
TL;DR
Explanation
NAT (Network Address Translation): a router with one public IP maps multiple private devices (192.168.x.x, 10.x.x.x) by tracking source IP:port to destination. Port forwarding: manually map public_ip:port → private_ip:port for inbound connections. NAT traversal: WebRTC uses STUN to discover public IP and TURN as a relay when direct P2P fails. For PHP developers: ngrok creates a tunnel bypassing NAT so Stripe can reach localhost:8000.
Common Misconception
Why It Matters
Common Mistakes
- Relying on NAT as a security boundary
- Not using ngrok for local webhook development
- Hard-coding private IPs in configuration — not routable on internet
- Docker: forgetting -p host:container to publish ports
Code Examples
// Stripe webhook URL: http://192.168.1.100:8000/webhook
// Problem: 192.168.1.100 is a private IP
// Stripe cannot reach this from the internet — webhook never fires
// Use ngrok for local webhook testing:
// Terminal 1: php -S localhost:8000
// Terminal 2: ngrok http 8000
// ngrok output: https://abc123.ngrok.io -> localhost:8000
// Stripe webhook URL: https://abc123.ngrok.io/webhook
// Docker: expose port to host:
// docker run -p 8000:80 myapp
// nginx on port 80 inside container → localhost:8000 on host