<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="atom.xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://blog.ltfi.fr/</id>
    <title>Laurent's Homelab Notes Blog</title>
    <updated>2026-07-13T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://blog.ltfi.fr/"/>
    <subtitle>Laurent's Homelab Notes Blog</subtitle>
    <icon>https://blog.ltfi.fr/img/favicon.ico</icon>
    <entry>
        <title type="html"><![CDATA[When the fix doesn't fix it: a Host header, a router, and a patched nginx]]></title>
        <id>https://blog.ltfi.fr/when-the-fix-doesnt-fix-it</id>
        <link href="https://blog.ltfi.fr/when-the-fix-doesnt-fix-it"/>
        <updated>2026-07-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Wanted to reach my Livebox's admin UI from outside my home network, through the nginx-based reverse proxy (npmplus, an nginx-proxy-manager fork) I already run for everything else. Two problems showed up back to back, and the second one took a lot longer to pin down than the first.]]></summary>
        <content type="html"><![CDATA[<p>Wanted to reach my Livebox's admin UI from outside my home network, through the nginx-based reverse proxy (npmplus, an nginx-proxy-manager fork) I already run for everything else. Two problems showed up back to back, and the second one took a lot longer to pin down than the first.</p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-1-the-livebox-rejects-requests-it-doesnt-recognize">Problem 1: the Livebox rejects requests it doesn't recognize<a href="https://blog.ltfi.fr/when-the-fix-doesnt-fix-it#problem-1-the-livebox-rejects-requests-it-doesnt-recognize" class="hash-link" aria-label="Direct link to Problem 1: the Livebox rejects requests it doesn't recognize" title="Direct link to Problem 1: the Livebox rejects requests it doesn't recognize" translate="no">​</a></h2>
<p>Any request through the proxy came back as an immediate connection reset. Testing directly against the Livebox confirmed it: any HTTPS request whose <code>Host</code> header didn't exactly match its own IP got dropped before a response was even sent. This is anti-DNS-rebinding protection, common on ISP-supplied routers — the router treats a mismatched Host header as a sign someone is trying to trick a browser into managing it from the outside.</p>
<p>Fix: rewrite the Host header before it leaves the proxy, so the Livebox sees a request for <code>192.168.1.254</code>, not for the public hostname:</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">proxy_set_header Host 192.168.1.254;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">proxy_ssl_server_name off;</span><br></div></code></pre></div></div>
<p>That cleared the reset. Progress — but not the finish line.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="problem-2-still-failing-with-a-much-sneakier-cause">Problem 2: still failing, with a much sneakier cause<a href="https://blog.ltfi.fr/when-the-fix-doesnt-fix-it#problem-2-still-failing-with-a-much-sneakier-cause" class="hash-link" aria-label="Direct link to Problem 2: still failing, with a much sneakier cause" title="Direct link to Problem 2: still failing, with a much sneakier cause" translate="no">​</a></h2>
<p>With the Host header fixed, the proxy now returned <code>502 Bad Gateway</code> — "upstream prematurely closed connection while reading response header." Replaying the exact same request by hand with <code>openssl s_client</code>, same headers, same HTTP version, worked every time: full page, correct size. Through the proxy, it kept failing.</p>
<p>A few rounds of isolating variables (HTTP version, TLS version, cipher suite, ALPN, buffering, keepalive) ruled out anything to do with what the proxy was sending. A packet capture showed the TCP/TLS session between the proxy and the Livebox completing cleanly — no reset, just less data coming back than a full page should contain.</p>
<p>The deciding test: standing up a bare, minimal nginx with an equivalent config, on a different host, worked immediately. That isolated the problem away from "nginx" in general and onto something specific to this particular proxy's setup.</p>
<p>The proxy manager in question ships a custom-patched nginx build — specifically, one patched to support the nginx-plus-only dynamic upstream <code>resolve</code> feature, so upstream targets can be re-resolved on the fly. That patched code path turned out to be the actual bug. Replacing the generated <code>upstream { ... resolve; }</code> block with a direct <code>proxy_pass</code> straight to the IP fixed it immediately:</p>
<div class="language-nginx codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-nginx codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#F8F8F2"><span class="token plain">location ~ ^/ {</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    proxy_pass https://192.168.1.254$request_uri;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    proxy_set_header Host 192.168.1.254;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">    proxy_ssl_server_name off;</span><br></div><div class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></div></code></pre></div></div>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="takeaways">Takeaways<a href="https://blog.ltfi.fr/when-the-fix-doesnt-fix-it#takeaways" class="hash-link" aria-label="Direct link to Takeaways" title="Direct link to Takeaways" translate="no">​</a></h2>
<ul>
<li class="">If a reverse-proxied request to a router/appliance admin UI gets silently reset, check the <code>Host</code> header first — a lot of consumer routers guard against exactly this.</li>
<li class="">When a <em>fix</em> doesn't fix it, don't assume the theory was wrong — check whether you're still testing the same code path. A working manual replay next to a failing proxied one is a strong signal something below the config layer is involved, not just above it.</li>
<li class="">Custom-patched software carries custom-patched bugs. A feature borrowed from a commercial fork (in this case, nginx-plus's dynamic upstream resolution) is exactly the kind of code path that gets less real-world mileage than the stable core it's bolted onto.</li>
</ul>]]></content>
        <author>
            <name>Laurent</name>
            <uri>https://github.com</uri>
        </author>
        <category label="Homelab" term="Homelab"/>
        <category label="Networking" term="Networking"/>
        <category label="nginx" term="nginx"/>
        <category label="Debugging" term="Debugging"/>
    </entry>
</feed>