You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Feature Request: Support Cloudflare WARP as an Outbound for Geo-blocking and Captcha Mitigation #309
Issue Description:
Is your feature request related to a problem? Please describe.
Currently, tunnel-node egresses traffic directly via the VPS main IP. This presents a significant hurdle for users in two ways:
Cloudflare/Google CAPTCHAs: Most VPS IP ranges have a poor reputation. Users frequently encounter endless cf-captcha loops or are outright blocked by websites using Cloudflare security layers.
Geo-restrictions: VPS IPs are often flagged as "Datacenter" IPs, preventing access to region-locked services (Streaming, AI tools, etc.).
Since I (and many others) haven't routed the entire system traffic through WARP yet, having the tunnel itself handle this would be a lifesaver.
Describe the solution you'd like
I suggest implementing an Outbound Configuration for tunnel-node. Specifically:
SOCKS5 Outbound Support: Allow the node to forward its egress traffic to a local SOCKS5 proxy (like a local WARP-CLI instance running on port 4000).
Direct WARP Integration (Optional but preferred): A native way to define a WARP/WireGuard outbound within the configuration file to rotate or clean the exit IP.
This would allow the tunnel to act as a bridge while the actual "exit" to the internet happens through a clean Cloudflare IP, effectively solving the CAPTCHA and blocking issues.
Describe alternatives you've considered
Setting up a global WARP interface on the OS level is an option, but it often breaks SSH connections or interferes with other services on a technical specialist's server. A per-application outbound is much more robust.
Additional context
This feature is crucial for maintaining the usability of the MasterHttpRelayVPN project in environments with strict filtering and aggressive bot-detection systems.
WARP IPs are Cloudflare consumer ranges that Cloudflare's own security layers don't penalize. From an origin server's POV, traffic looks like it came from a regular Cloudflare consumer, not a datacenter VPS. That sidesteps:
Cloudflare cf-captcha loops
Datacenter-IP heuristic that hits Instagram, Meta, OpenAI, OpenRouter, etc.
Some geo-restrictions (WARP IPs aren't always region-locked the same way)
Implementation paths:
Option A: Document setup, no code change. WARP is already a standalone Linux client. Users can install it on their VPS:
# On VPS (after tunnel-node is running)
curl https://pkg.cloudflareclient.com/install.sh | sudo bash
warp-cli register
warp-cli connect
# Verify outbound goes via WARP
curl https://www.cloudflare.com/cdn-cgi/trace
# Should show 'warp=on'
This routes the VPS's entire outbound through WARP. tunnel-node automatically benefits without any mhrv-rs code changes. Trade-off: VPS's own incoming connections (the Apps Script→VPS hop) still work because incoming isn't affected by WARP, only outgoing.
We could ship this as a docs/tunnel-node-warp.md guide. ~30 min of doc work.
Option B: tunnel-node integrates a WARP client library. Bigger surface area — would need to bundle WARP's WireGuard tunnel as a Rust dep, manage WARP credentials, handle reconnects. Probably 200-400 LOC + ongoing maintenance for WARP API drift.
My recommendation: Option A first. Ships in days, gets users the benefit immediately, no maintenance burden. Option B is only worth doing if Option A turns out to be insufficient (e.g., per-flow routing instead of all-VPS-traffic).
Caveats:
WARP+ (paid tier) gives more bandwidth and stability than free WARP. Free WARP throttles after sustained heavy use. For a tunnel-node with multiple users, WARP+ ($5/month) may be necessary.
WARP doesn't accept incoming connections by default — the VPS's tunnel-node listener is fine because that's the server side, but if you need outbound P2P (e.g., direct-connect VoIP) that won't work with stock WARP.
Some sites detect WARP and treat it the same as a VPN (not common, but happens). For those, you'd want to disable WARP for those specific destinations — which is back to needing per-flow routing.
Tracking as v1.8.x roadmap item — likely Option A docs first, Option B if demand justifies. If you want to take Option A as a PR (write the docs/tunnel-node-warp.md), happy to review.
[reply via Anthropic Claude | reviewed by @therealaleph]
WARP IPs are Cloudflare consumer ranges that Cloudflare's own security layers don't penalize. From an origin server's POV, traffic looks like it came from a regular Cloudflare consumer, not a datacenter VPS. That sidesteps:
Cloudflare cf-captcha loops
Datacenter-IP heuristic that hits Instagram, Meta, OpenAI, OpenRouter, etc.
Some geo-restrictions (WARP IPs aren't always region-locked the same way)
Implementation paths:
Option A: Document setup, no code change. WARP is already a standalone Linux client. Users can install it on their VPS:
# On VPS (after tunnel-node is running)
curl https://pkg.cloudflareclient.com/install.sh | sudo bash
warp-cli register
warp-cli connect
# Verify outbound goes via WARP
curl https://www.cloudflare.com/cdn-cgi/trace
# Should show 'warp=on'
This routes the VPS's entire outbound through WARP. tunnel-node automatically benefits without any mhrv-rs code changes. Trade-off: VPS's own incoming connections (the Apps Script→VPS hop) still work because incoming isn't affected by WARP, only outgoing.
We could ship this as a docs/tunnel-node-warp.md guide. ~30 min of doc work.
Option B: tunnel-node integrates a WARP client library. Bigger surface area — would need to bundle WARP's WireGuard tunnel as a Rust dep, manage WARP credentials, handle reconnects. Probably 200-400 LOC + ongoing maintenance for WARP API drift.
My recommendation: Option A first. Ships in days, gets users the benefit immediately, no maintenance burden. Option B is only worth doing if Option A turns out to be insufficient (e.g., per-flow routing instead of all-VPS-traffic).
Caveats:
WARP+ (paid tier) gives more bandwidth and stability than free WARP. Free WARP throttles after sustained heavy use. For a tunnel-node with multiple users, WARP+ ($5/month) may be necessary.
WARP doesn't accept incoming connections by default — the VPS's tunnel-node listener is fine because that's the server side, but if you need outbound P2P (e.g., direct-connect VoIP) that won't work with stock WARP.
Some sites detect WARP and treat it the same as a VPN (not common, but happens). For those, you'd want to disable WARP for those specific destinations — which is back to needing per-flow routing.
Tracking as v1.8.x roadmap item — likely Option A docs first, Option B if demand justifies. If you want to take Option A as a PR (write the docs/tunnel-node-warp.md), happy to review.
[reply via Anthropic Claude | reviewed by @therealaleph]
option a not good recommendation because using cloudflare warp cli to tunnel all vps traffic will make it unusable and ssh connection will be effected by this
i have another proposal for this :
just add an choosable upstream interface to node tunnel code that can be enable through .env for docker that will route the traffic to warp interface
for example i have run the cloud flare warp as interface warp then i need to change the --upstream-interface : warp in container .env so upstream goes to warp like this :
tunnel node container > upstream interface flag : warp > warp
best case scenario with lowest code changes
best regards
@w0l4i — agreed, your counter-proposal is much cleaner than my Option A. The issue with WARP-as-default-route on the VPS (breaking SSH + the inbound Apps Script→VPS hop) is real and your --upstream-interface warp approach side-steps it entirely.
Updated design (as you proposed):
User installs WARP on the VPS as a separate interface (warp device, not as default route). tunnel-node binds outgoing sockets specifically to that interface via SO_BINDTODEVICE. SSH and tunnel-node's listener still use the default route.
# On VPS:
warp-cli connect # creates interface "warp", does NOT change default route
ip link show warp # verify the interface exists# tunnel-node config:
docker run -d --name mhrv-tunnel \
--restart unless-stopped \
--network host \ # need host networking for SO_BINDTODEVICE to see warp
-p 8443:8443 \
-e MHRV_AUTH_KEY="$(openssl rand -hex 32)" \
-e UPSTREAM_INTERFACE="warp"\ # NEW
ghcr.io/therealaleph/mhrv-tunnel-node:latest
Implementation in tunnel-node: small surface area. Roughly:
// In TcpStream::connect path of tunnel-node:let sock = TcpSocket::new_v4()?;ifletSome(iface) = config.upstream_interface.as_ref(){// Linux only — SO_BINDTODEVICE requires CAP_NET_RAW or rootlet iface_cstr = std::ffi::CString::new(iface.as_str())?;unsafe{
libc::setsockopt(
sock.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
iface_cstr.as_ptr()as*const_,
iface.len()as libc::socklen_t,);}}
sock.connect(addr).await?
Plus equivalent for UDP for udpgw flows. ~50 LOC + env-var plumbing + Dockerfile capability docs (the container needs CAP_NET_RAW to use SO_BINDTODEVICE).
Trade-offs:
Linux-only.SO_BINDTODEVICE doesn't exist on macOS/Windows. tunnel-node ships as Linux Docker so this is fine — but we'd need to feature-gate or make it a no-op when the env var is unset.
Capability requirement. Container needs CAP_NET_RAW. Adds --cap-add=NET_RAW to the docker run.
Per-flow routing not free. All outbound from tunnel-node goes via warp. If you want some flows direct (e.g. low-latency Google), need a richer routing rule. For v1, "all outbound via warp" is the simple default; finer-grained = follow-up.
This is genuinely better than Option A — happy to take this as the v1.8.x WARP support landing point.
If you want to take a PR (you've done good work on the longpoll fix in #290 / #319 area), I'll happily review. Roughly the changes:
tunnel-node/src/main.rs — read UPSTREAM_INTERFACE env var into config
tunnel-node/src/connect.rs (or wherever the outbound TCP/UDP connect lives) — apply SO_BINDTODEVICE if config set
tunnel-node/Dockerfile — document capability need; maybe add RUN setcap cap_net_raw+ep so non-root works
tunnel-node/README.md — short "WARP outbound" section explaining the install + run flow
(No mhrv-rs client changes needed — this is tunnel-node-only)
Otherwise I'll plan to ship it myself in the v1.8.x cycle. Tracked.
[reply via Anthropic Claude | reviewed by @therealaleph]
@w0l4i — agreed, your counter-proposal is much cleaner than my Option A. The issue with WARP-as-default-route on the VPS (breaking SSH + the inbound Apps Script→VPS hop) is real and your --upstream-interface warp approach side-steps it entirely.
Updated design (as you proposed):
User installs WARP on the VPS as a separate interface (warp device, not as default route). tunnel-node binds outgoing sockets specifically to that interface via SO_BINDTODEVICE. SSH and tunnel-node's listener still use the default route.
On VPS:
warp-cli connect # creates interface "warp", does NOT change default route
ip link show warp # verify the interface exists
tunnel-node config:
docker run -d --name mhrv-tunnel
--restart unless-stopped
--network host \ # need host networking for SO_BINDTODEVICE to see warp
-p 8443:8443
-e MHRV_AUTH_KEY="$(openssl rand -hex 32)"
-e UPSTREAM_INTERFACE="warp" \ # NEW
ghcr.io/therealaleph/mhrv-tunnel-node:latest Implementation in tunnel-node: small surface area. Roughly:
// In TcpStream::connect path of tunnel-node:
let sock = TcpSocket::new_v4()?;
if let Some(iface) = config.upstream_interface.as_ref() {
// Linux only — SO_BINDTODEVICE requires CAP_NET_RAW or root
let iface_cstr = std::ffi::CString::new(iface.as_str())?;
unsafe {
libc::setsockopt(
sock.as_raw_fd(),
libc::SOL_SOCKET,
libc::SO_BINDTODEVICE,
iface_cstr.as_ptr() as *const _,
iface.len() as libc::socklen_t,
);
}
}
sock.connect(addr).await?
Plus equivalent for UDP for udpgw flows. ~50 LOC + env-var plumbing + Dockerfile capability docs (the container needs CAP_NET_RAW to use SO_BINDTODEVICE).
Trade-offs:
Linux-only.SO_BINDTODEVICE doesn't exist on macOS/Windows. tunnel-node ships as Linux Docker so this is fine — but we'd need to feature-gate or make it a no-op when the env var is unset.
Capability requirement. Container needs CAP_NET_RAW. Adds --cap-add=NET_RAW to the docker run.
Per-flow routing not free. All outbound from tunnel-node goes via warp. If you want some flows direct (e.g. low-latency Google), need a richer routing rule. For v1, "all outbound via warp" is the simple default; finer-grained = follow-up.
This is genuinely better than Option A — happy to take this as the v1.8.x WARP support landing point.
If you want to take a PR (you've done good work on the longpoll fix in #290 / #319 area), I'll happily review. Roughly the changes:
tunnel-node/src/main.rs — read UPSTREAM_INTERFACE env var into config
tunnel-node/src/connect.rs (or wherever the outbound TCP/UDP connect lives) — apply SO_BINDTODEVICE if config set
tunnel-node/Dockerfile — document capability need; maybe add RUN setcap cap_net_raw+ep so non-root works
tunnel-node/README.md — short "WARP outbound" section explaining the install + run flow
(No mhrv-rs client changes needed — this is tunnel-node-only)
Otherwise I'll plan to ship it myself in the v1.8.x cycle. Tracked.
[reply via Anthropic Claude | reviewed by @therealaleph]
I strongly support this. Most VPS providers are currently in a 'reputation debt'—their IP ranges are pre-flagged by IP Intelligence services as Datacenter/Proxy. This leads to the 'Captcha Hell' many users are experiencing.
Adding a SOCKS5/WireGuard outbound allows for Application-Level Routing. This is significantly safer than a global OS-level WARP configuration, which often risks breaking SSH access due to asymmetric routing issues. By exiting through Cloudflare's Anycast network, we leverage their high IP reputation to bypass aggressive bot-detection and Geo-fencing that wouldn't otherwise trust a standard VPS IP." @w0l4i@therealaleph
i would LOVE if this got added
would probably make discord work, and thats pretty much all i want from this project: to talk with my friends outside the country and watch videos on youtube (and occasionally do programming stuff)
WARP IPs are Cloudflare consumer ranges that Cloudflare's own security layers don't penalize. From an origin server's POV, traffic looks like it came from a regular Cloudflare consumer, not a datacenter VPS. That sidesteps:
Cloudflare cf-captcha loops
Datacenter-IP heuristic that hits Instagram, Meta, OpenAI, OpenRouter, etc.
Some geo-restrictions (WARP IPs aren't always region-locked the same way)
Implementation paths:
Option A: Document setup, no code change. WARP is already a standalone Linux client. Users can install it on their VPS:
# On VPS (after tunnel-node is running)
curl https://pkg.cloudflareclient.com/install.sh | sudo bash
warp-cli register
warp-cli connect
# Verify outbound goes via WARP
curl https://www.cloudflare.com/cdn-cgi/trace
# Should show 'warp=on'
This routes the VPS's entire outbound through WARP. tunnel-node automatically benefits without any mhrv-rs code changes. Trade-off: VPS's own incoming connections (the Apps Script→VPS hop) still work because incoming isn't affected by WARP, only outgoing.
We could ship this as a docs/tunnel-node-warp.md guide. ~30 min of doc work.
Option B: tunnel-node integrates a WARP client library. Bigger surface area — would need to bundle WARP's WireGuard tunnel as a Rust dep, manage WARP credentials, handle reconnects. Probably 200-400 LOC + ongoing maintenance for WARP API drift.
My recommendation: Option A first. Ships in days, gets users the benefit immediately, no maintenance burden. Option B is only worth doing if Option A turns out to be insufficient (e.g., per-flow routing instead of all-VPS-traffic).
Caveats:
WARP+ (paid tier) gives more bandwidth and stability than free WARP. Free WARP throttles after sustained heavy use. For a tunnel-node with multiple users, WARP+ ($5/month) may be necessary.
WARP doesn't accept incoming connections by default — the VPS's tunnel-node listener is fine because that's the server side, but if you need outbound P2P (e.g., direct-connect VoIP) that won't work with stock WARP.
Some sites detect WARP and treat it the same as a VPN (not common, but happens). For those, you'd want to disable WARP for those specific destinations — which is back to needing per-flow routing.
Tracking as v1.8.x roadmap item — likely Option A docs first, Option B if demand justifies. If you want to take Option A as a PR (write the docs/tunnel-node-warp.md), happy to review.
[reply via Anthropic Claude | reviewed by @therealaleph]
option a not good recommendation because using cloudflare warp cli to tunnel all vps traffic will make it unusable and ssh connection will be effected by this
i have another proposal for this :
just add an choosable upstream interface to node tunnel code that can be enable through .env for docker that will route the traffic to warp interface
for example i have run the cloud flare warp as interface warp then i need to change the --upstream-interface : warp in container .env so upstream goes to warp like this :
tunnel node container > upstream interface flag : warp > warp
best case scenario with lowest code changes
best regards
Please look at this topic and if it possible help to add --out --interface flag to docker tunnel node so traffic go to custom flow like this for fixing captcha and geolocation issues :
@w0l4i agreed — OS-wide WARP is not the right long-term recommendation if it risks SSH / asymmetric routing on the VPS.
I see three implementation levels here:
Documented workaround: run WARP on the host and route globally. Fast to document, but fragile for exactly the SSH/routing reasons you called out.
SOCKS5/HTTP CONNECT outbound for tunnel-node: tunnel-node connects to a local outbound proxy instead of dialing destinations directly. This is portable and works with any local WARP/xray/sing-box setup that exposes a proxy port. Operationally simpler than binding to a Linux interface from inside Docker.
Linux interface bind / route mark: something like --out-interface warp or TUNNEL_OUT_INTERFACE=warp. This is closer to your proposal, but it is more platform-specific. In Docker, the host warp interface is not automatically visible inside the container unless users run host networking or grant extra network capabilities. In Rust it also means either Linux-specific socket options or a routing-table/fwmark design.
My preference for a first mergeable version is Option 2 first, because it gives users the WARP path without requiring privileged Docker networking:
tunnel-node -> local SOCKS5/HTTP outbound -> WARP/sing-box/xray -> internet
Then Option 3 can be added for Linux operators who specifically want interface binding.
This is still worth tracking here. It is a tunnel-node outbound feature, separate from client-side upstream proxy support like #1189.
[reply via Anthropic Claude | reviewed by @therealaleph]
Activity
w0l4i commentedon Apr 27, 2026
stocking at captcha that warp can easily fix it
therealaleph commentedon Apr 27, 2026
@w0l4i — solid feature request, well-articulated. Cloudflare WARP as tunnel-node outbound is a clean architectural win:
What it would change:
WARP IPs are Cloudflare consumer ranges that Cloudflare's own security layers don't penalize. From an origin server's POV, traffic looks like it came from a regular Cloudflare consumer, not a datacenter VPS. That sidesteps:
Implementation paths:
Option A: Document setup, no code change. WARP is already a standalone Linux client. Users can install it on their VPS:
This routes the VPS's entire outbound through WARP. tunnel-node automatically benefits without any mhrv-rs code changes. Trade-off: VPS's own incoming connections (the Apps Script→VPS hop) still work because incoming isn't affected by WARP, only outgoing.
We could ship this as a
docs/tunnel-node-warp.mdguide. ~30 min of doc work.Option B: tunnel-node integrates a WARP client library. Bigger surface area — would need to bundle WARP's WireGuard tunnel as a Rust dep, manage WARP credentials, handle reconnects. Probably 200-400 LOC + ongoing maintenance for WARP API drift.
My recommendation: Option A first. Ships in days, gets users the benefit immediately, no maintenance burden. Option B is only worth doing if Option A turns out to be insufficient (e.g., per-flow routing instead of all-VPS-traffic).
Caveats:
Tracking as v1.8.x roadmap item — likely Option A docs first, Option B if demand justifies. If you want to take Option A as a PR (write the
docs/tunnel-node-warp.md), happy to review.[reply via Anthropic Claude | reviewed by @therealaleph]
w0l4i commentedon Apr 27, 2026
option a not good recommendation because using cloudflare warp cli to tunnel all vps traffic will make it unusable and ssh connection will be effected by this
i have another proposal for this :
just add an choosable upstream interface to node tunnel code that can be enable through .env for docker that will route the traffic to warp interface
for example i have run the cloud flare warp as interface warp then i need to change the --upstream-interface : warp in container .env so upstream goes to warp like this :
tunnel node container > upstream interface flag : warp > warp
best case scenario with lowest code changes
best regards
therealaleph commentedon Apr 27, 2026
@w0l4i — agreed, your counter-proposal is much cleaner than my Option A. The issue with WARP-as-default-route on the VPS (breaking SSH + the inbound Apps Script→VPS hop) is real and your
--upstream-interface warpapproach side-steps it entirely.Updated design (as you proposed):
User installs WARP on the VPS as a separate interface (
warpdevice, not as default route). tunnel-node binds outgoing sockets specifically to that interface viaSO_BINDTODEVICE. SSH and tunnel-node's listener still use the default route.Implementation in tunnel-node: small surface area. Roughly:
Plus equivalent for UDP for udpgw flows. ~50 LOC + env-var plumbing + Dockerfile capability docs (the container needs
CAP_NET_RAWto useSO_BINDTODEVICE).Trade-offs:
SO_BINDTODEVICEdoesn't exist on macOS/Windows. tunnel-node ships as Linux Docker so this is fine — but we'd need to feature-gate or make it a no-op when the env var is unset.CAP_NET_RAW. Adds--cap-add=NET_RAWto the docker run.warp. If you want some flows direct (e.g. low-latency Google), need a richer routing rule. For v1, "all outbound via warp" is the simple default; finer-grained = follow-up.This is genuinely better than Option A — happy to take this as the v1.8.x WARP support landing point.
If you want to take a PR (you've done good work on the longpoll fix in #290 / #319 area), I'll happily review. Roughly the changes:
tunnel-node/src/main.rs— readUPSTREAM_INTERFACEenv var into configtunnel-node/src/connect.rs(or wherever the outbound TCP/UDP connect lives) — applySO_BINDTODEVICEif config settunnel-node/Dockerfile— document capability need; maybe addRUN setcap cap_net_raw+epso non-root workstunnel-node/README.md— short "WARP outbound" section explaining the install + run flowOtherwise I'll plan to ship it myself in the v1.8.x cycle. Tracked.
[reply via Anthropic Claude | reviewed by @therealaleph]
w0l4i commentedon Apr 27, 2026
i will wait for 1.8.x release for this tnx btw
2bemoji commentedon Apr 28, 2026
I strongly support this. Most VPS providers are currently in a 'reputation debt'—their IP ranges are pre-flagged by IP Intelligence services as Datacenter/Proxy. This leads to the 'Captcha Hell' many users are experiencing.
Adding a SOCKS5/WireGuard outbound allows for Application-Level Routing. This is significantly safer than a global OS-level WARP configuration, which often risks breaking SSH access due to asymmetric routing issues. By exiting through Cloudflare's Anycast network, we leverage their high IP reputation to bypass aggressive bot-detection and Geo-fencing that wouldn't otherwise trust a standard VPS IP."
@w0l4i @therealaleph
therealtunge commentedon May 1, 2026
i would LOVE if this got added
would probably make discord work, and thats pretty much all i want from this project: to talk with my friends outside the country and watch videos on youtube (and occasionally do programming stuff)
therealtunge commentedon May 1, 2026
question, wouldnt V2Ray configs that use HTTPS transport (i.e vless/xhttp/tls) work without a vps?
mewshiam commentedon May 6, 2026
Hi there,
Any Updates In This Topic?
@therealaleph
w0l4i commentedon May 15, 2026
@therealaleph @dazzling-no-more @yyoyoian-pixel
Please look at this topic and if it possible help to add --out --interface flag to docker tunnel node so traffic go to custom flow like this for fixing captcha and geolocation issues :
Tunnel node > interface outband warp > warp internal interface > internet !
therealaleph commentedon May 15, 2026
@w0l4i agreed — OS-wide WARP is not the right long-term recommendation if it risks SSH / asymmetric routing on the VPS.
I see three implementation levels here:
Documented workaround: run WARP on the host and route globally. Fast to document, but fragile for exactly the SSH/routing reasons you called out.
SOCKS5/HTTP CONNECT outbound for tunnel-node: tunnel-node connects to a local outbound proxy instead of dialing destinations directly. This is portable and works with any local WARP/xray/sing-box setup that exposes a proxy port. Operationally simpler than binding to a Linux interface from inside Docker.
Linux interface bind / route mark: something like
--out-interface warporTUNNEL_OUT_INTERFACE=warp. This is closer to your proposal, but it is more platform-specific. In Docker, the hostwarpinterface is not automatically visible inside the container unless users run host networking or grant extra network capabilities. In Rust it also means either Linux-specific socket options or a routing-table/fwmark design.My preference for a first mergeable version is Option 2 first, because it gives users the WARP path without requiring privileged Docker networking:
Then Option 3 can be added for Linux operators who specifically want interface binding.
This is still worth tracking here. It is a tunnel-node outbound feature, separate from client-side upstream proxy support like #1189.
[reply via Anthropic Claude | reviewed by @therealaleph]