mirror of
https://github.com/MeshTender/MeshTender.git
synced 2026-09-02 01:38:17 +00:00
133 lines
5.8 KiB
HTML
133 lines
5.8 KiB
HTML
{{define "title"}}Reverse proxy test · MeshTender{{end}}
|
|
{{define "header"}}
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col">
|
|
<div class="page-pretitle">Administration</div>
|
|
<h1 class="page-title fs-1">Reverse proxy test</h1>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{define "content"}}
|
|
<div class="row row-cards">
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="text-secondary">Client IP the app records</div>
|
|
<div class="h1 mb-1 font-monospace">{{.ResolvedIP}}</div>
|
|
<div class="text-secondary small">Used for rate limiting and audit logs (via chi RealIP → X-Forwarded-For / X-Real-IP).</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="text-secondary">Actual connection (TCP peer)</div>
|
|
<div class="h1 mb-1 font-monospace">{{.RawPeer}}</div>
|
|
<div class="text-secondary small">The socket that reached the app — your proxy/load balancer if one is in front.</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{{if .HeaderApplied}}
|
|
<div class="alert alert-info mt-3" role="alert">
|
|
<div>
|
|
A forwarding header was honored: the recorded client IP differs from the connecting peer, so a proxy's
|
|
headers are being trusted. <strong>Confirm the recorded IP above is the real visitor</strong> — if it's an
|
|
intermediate proxy/CDN node, the wrong entry in <code>X-Forwarded-For</code> is being used.
|
|
</div>
|
|
</div>
|
|
{{else}}
|
|
<div class="alert alert-warning mt-3" role="alert">
|
|
<div>
|
|
The recorded client IP equals the connecting peer — no forwarding header changed it. If MeshTender sits
|
|
behind a reverse proxy or CDN, that proxy is <strong>not</strong> sending a trusted
|
|
<code>X-Forwarded-For</code> / <code>X-Real-IP</code>, so the app is logging the <em>proxy's</em> address
|
|
rather than the visitor's. (If this is a direct connection with no proxy, this is expected.)
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h2 class="card-title">Trusted-proxy resolution</h2></div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<div class="form-label">Connecting peer</div>
|
|
<span class="font-monospace">{{.RawPeer}}</span>
|
|
{{if .PeerTrusted}}<span class="badge bg-success-lt ms-1">trusted</span>{{else}}<span class="badge bg-yellow-lt ms-1">not trusted</span>{{end}}
|
|
{{if not .PeerTrusted}}
|
|
<div class="text-secondary small mt-1">The connecting peer isn't a trusted proxy, so forwarding headers are ignored and the peer is used as the client IP. If a proxy or router sits in front, add its address to the trusted list below.</div>
|
|
{{end}}
|
|
</div>
|
|
<div class="mb-3">
|
|
<div class="form-label">X-Forwarded-For chain <span class="text-secondary">(client = rightmost untrusted hop)</span></div>
|
|
{{if .XFFChain}}
|
|
<div class="d-flex flex-wrap gap-2">
|
|
{{range .XFFChain}}
|
|
<span class="badge font-monospace {{if .Selected}}bg-success-lt{{else if .Trusted}}bg-secondary-lt{{else}}bg-azure-lt{{end}}">{{.IP}}{{if .Trusted}} · trusted{{end}}{{if .Selected}} · client{{end}}</span>
|
|
{{end}}
|
|
</div>
|
|
{{else}}<span class="text-secondary">No X-Forwarded-For header on this request.</span>{{end}}
|
|
</div>
|
|
<div>
|
|
<div class="form-label">Trusted proxy ranges</div>
|
|
<div class="d-flex flex-wrap gap-2 mb-1">
|
|
{{range .TrustedProxies}}<code>{{.}}</code>{{end}}
|
|
</div>
|
|
<small class="form-hint">Set <code>MESHTENDER_TRUSTED_PROXIES</code> (comma-separated CIDRs/IPs, or the <code>private</code> shorthand) to trust additional hops. Loopback is always trusted.</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h2 class="card-title">Forwarding headers</h2></div>
|
|
<div class="table-responsive">
|
|
<table class="table table-vcenter card-table">
|
|
<thead><tr><th>Header</th><th>Value</th></tr></thead>
|
|
<tbody>
|
|
{{range .Forwarding}}
|
|
<tr>
|
|
<td class="font-monospace text-nowrap">{{.Name}}</td>
|
|
<td class="font-monospace">{{if .Value}}{{.Value}}{{else}}<span class="text-secondary">—</span>{{end}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h2 class="card-title">Connection</h2></div>
|
|
<div class="card-body">
|
|
<div class="datagrid">
|
|
<div class="datagrid-item"><div class="datagrid-title">Host</div><div class="datagrid-content font-monospace">{{.Host}}</div></div>
|
|
<div class="datagrid-item"><div class="datagrid-title">Scheme</div><div class="datagrid-content font-monospace">{{.Scheme}}</div></div>
|
|
<div class="datagrid-item"><div class="datagrid-title">Protocol</div><div class="datagrid-content font-monospace">{{.Proto}}</div></div>
|
|
<div class="datagrid-item"><div class="datagrid-title">Method</div><div class="datagrid-content font-monospace">{{.Method}}</div></div>
|
|
<div class="datagrid-item"><div class="datagrid-title">Request URI</div><div class="datagrid-content font-monospace">{{.RequestURI}}</div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card mt-3">
|
|
<div class="card-header"><h2 class="card-title">All request headers</h2>
|
|
<span class="card-subtitle ms-auto">credentials redacted</span>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-vcenter card-table">
|
|
<thead><tr><th>Header</th><th>Value</th></tr></thead>
|
|
<tbody>
|
|
{{range .AllHeaders}}
|
|
<tr>
|
|
<td class="font-monospace text-nowrap align-top">{{.Name}}</td>
|
|
<td class="font-monospace" style="word-break:break-all">{{.Value}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<a class="back-link mt-3" href="/admin">{{template "icon-arrow-left" "me-1"}}Back to admin</a>
|
|
{{end}}
|