Skip to content

Commit ac0c66c

Browse files
committed
1 parent 5653a79 commit ac0c66c

9 files changed

Lines changed: 253 additions & 139 deletions

File tree

changelog/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1734,12 +1734,13 @@
17341734

17351735
<h1 id="changelog">Changelog<a class="headerlink" href="#changelog" title="Permanent link">&para;</a></h1>
17361736
<h2 id="490">4.9.0<a class="headerlink" href="#490" title="Permanent link">&para;</a></h2>
1737-
<p>PROXY protocol v1/v2 listener support (<a href="https://github.com/teleproxy/teleproxy/issues/50">#50</a>).</p>
1737+
<p>PROXY protocol v1/v2 listener support (<a href="https://github.com/teleproxy/teleproxy/issues/50">#50</a>) and per-IP top-N Prometheus metrics (<a href="https://github.com/teleproxy/teleproxy/issues/46">#46</a>).</p>
17381738
<ul>
17391739
<li><strong>PROXY protocol</strong> — accept HAProxy PROXY protocol v1 (text) and v2 (binary) headers on client listeners. Required when running behind a load balancer (HAProxy, nginx, AWS NLB) that injects client IP. Enable with <code>--proxy-protocol</code> (CLI), <code>proxy_protocol = true</code> (TOML), or <code>PROXY_PROTOCOL=true</code> (Docker).</li>
17401740
<li>Auto-detects v1 and v2 headers, extracts real client IP, re-checks IP ACLs against the real address.</li>
17411741
<li>v2 LOCAL command accepted for load balancer health check probes.</li>
17421742
<li>New Prometheus metrics: <code>teleproxy_proxy_protocol_connections_total</code>, <code>teleproxy_proxy_protocol_errors_total</code>.</li>
1743+
<li><strong>Per-IP top-N metrics</strong> — opt-in <code>top_ips_per_secret = N</code> (TOML) or <code>TOP_IPS_PER_SECRET=N</code> (Docker) exposes the top-N heaviest client IPs per secret in <code>/metrics</code>. Three new families: <code>teleproxy_secret_ip_connections</code>, <code>teleproxy_secret_ip_bytes_received_total</code>, <code>teleproxy_secret_ip_bytes_sent_total</code>. Sorted by total bytes; cap at 32 per secret to keep Prometheus cardinality bounded. Default 0 (disabled, zero overhead). Useful for diagnosing the "proxy works for 5 minutes then stops" complaint pattern alongside the Grafana dashboard.</li>
17431744
<li>Fix auto-generated secret not written to TOML config — <code>start.sh</code> now correctly stores the generated secret in the TOML config.</li>
17441745
<li>Documentation: complete SEO overhaul with per-page meta descriptions, OpenGraph tags, JSON-LD structured data, and robots.txt.</li>
17451746
<li>Translations: Russian documentation now at 100% coverage, Farsi and Vietnamese expanded to 38%.</li>

fa/changelog/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1734,12 +1734,13 @@
17341734

17351735
<h1 id="changelog">Changelog<a class="headerlink" href="#changelog" title="Permanent link">&para;</a></h1>
17361736
<h2 id="490">4.9.0<a class="headerlink" href="#490" title="Permanent link">&para;</a></h2>
1737-
<p>PROXY protocol v1/v2 listener support (<a href="https://github.com/teleproxy/teleproxy/issues/50">#50</a>).</p>
1737+
<p>PROXY protocol v1/v2 listener support (<a href="https://github.com/teleproxy/teleproxy/issues/50">#50</a>) and per-IP top-N Prometheus metrics (<a href="https://github.com/teleproxy/teleproxy/issues/46">#46</a>).</p>
17381738
<ul>
17391739
<li><strong>PROXY protocol</strong> — accept HAProxy PROXY protocol v1 (text) and v2 (binary) headers on client listeners. Required when running behind a load balancer (HAProxy, nginx, AWS NLB) that injects client IP. Enable with <code>--proxy-protocol</code> (CLI), <code>proxy_protocol = true</code> (TOML), or <code>PROXY_PROTOCOL=true</code> (Docker).</li>
17401740
<li>Auto-detects v1 and v2 headers, extracts real client IP, re-checks IP ACLs against the real address.</li>
17411741
<li>v2 LOCAL command accepted for load balancer health check probes.</li>
17421742
<li>New Prometheus metrics: <code>teleproxy_proxy_protocol_connections_total</code>, <code>teleproxy_proxy_protocol_errors_total</code>.</li>
1743+
<li><strong>Per-IP top-N metrics</strong> — opt-in <code>top_ips_per_secret = N</code> (TOML) or <code>TOP_IPS_PER_SECRET=N</code> (Docker) exposes the top-N heaviest client IPs per secret in <code>/metrics</code>. Three new families: <code>teleproxy_secret_ip_connections</code>, <code>teleproxy_secret_ip_bytes_received_total</code>, <code>teleproxy_secret_ip_bytes_sent_total</code>. Sorted by total bytes; cap at 32 per secret to keep Prometheus cardinality bounded. Default 0 (disabled, zero overhead). Useful for diagnosing the "proxy works for 5 minutes then stops" complaint pattern alongside the Grafana dashboard.</li>
17431744
<li>Fix auto-generated secret not written to TOML config — <code>start.sh</code> now correctly stores the generated secret in the TOML config.</li>
17441745
<li>Documentation: complete SEO overhaul with per-page meta descriptions, OpenGraph tags, JSON-LD structured data, and robots.txt.</li>
17451746
<li>Translations: Russian documentation now at 100% coverage, Farsi and Vietnamese expanded to 38%.</li>

fa/features/secrets/index.html

Lines changed: 54 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,17 @@
11571157
</span>
11581158
</a>
11591159

1160+
</li>
1161+
1162+
<li class="md-nav__item">
1163+
<a href="#per-ip-top-n-metrics" class="md-nav__link">
1164+
<span class="md-ellipsis">
1165+
1166+
Per-IP Top-N Metrics
1167+
1168+
</span>
1169+
</a>
1170+
11601171
</li>
11611172

11621173
<li class="md-nav__item">
@@ -1662,6 +1673,17 @@
16621673
</span>
16631674
</a>
16641675

1676+
</li>
1677+
1678+
<li class="md-nav__item">
1679+
<a href="#per-ip-top-n-metrics" class="md-nav__link">
1680+
<span class="md-ellipsis">
1681+
1682+
Per-IP Top-N Metrics
1683+
1684+
</span>
1685+
</a>
1686+
16651687
</li>
16661688

16671689
<li class="md-nav__item">
@@ -1843,25 +1865,40 @@ <h2 id="secret-expiration">Secret Expiration<a class="headerlink" href="#secret-
18431865
<li><strong>Stats:</strong> <code>secret_temp_expires 1751327999</code>, <code>secret_temp_rejected_expired 12</code></li>
18441866
<li><strong>Prometheus:</strong> <code>teleproxy_secret_expires_timestamp{secret="temp"} 1751327999</code></li>
18451867
</ul>
1868+
<h2 id="per-ip-top-n-metrics">Per-IP Top-N Metrics<a class="headerlink" href="#per-ip-top-n-metrics" title="Permanent link">&para;</a></h2>
1869+
<p>Surface the heaviest client IPs per secret in <code>/metrics</code> to diagnose rogue clients. Disabled by default — opt in with a top-level config knob, not a per-secret one (cardinality is an operator concern).</p>
1870+
<p>TOML config:</p>
1871+
<div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="n">top_ips_per_secret</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span><span class="w"> </span><span class="c1"># 0 disables; max 32</span>
1872+
</code></pre></div>
1873+
<p>Docker:</p>
1874+
<div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="nv">TOP_IPS_PER_SECRET</span><span class="o">=</span><span class="m">10</span>
1875+
</code></pre></div>
1876+
<p>When enabled, three new Prometheus metric families are emitted, each labelled <code>{secret="...", ip="..."}</code> for the top-N heaviest IPs per secret (sorted by total bytes):</p>
1877+
<ul>
1878+
<li><code>teleproxy_secret_ip_connections</code> — current active connections from this IP (gauge)</li>
1879+
<li><code>teleproxy_secret_ip_bytes_received_total</code> — bytes received from this IP (counter)</li>
1880+
<li><code>teleproxy_secret_ip_bytes_sent_total</code> — bytes sent to this IP (counter)</li>
1881+
</ul>
1882+
<p>Cardinality is bounded at <code>top_ips_per_secret × secret_count</code> labelled samples per family. Counters reset when an IP entry is recycled — Prometheus <code>rate()</code> handles this correctly.</p>
18461883
<h2 id="toml-config-example">TOML Config Example<a class="headerlink" href="#toml-config-example" title="Permanent link">&para;</a></h2>
18471884
<p>All per-secret features combined:</p>
1848-
<div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="k">[[secret]]</span>
1849-
<a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;cafe01234567890abcafe01234567890a&quot;</span>
1850-
<a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;family&quot;</span>
1851-
<a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">100</span>
1852-
<a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="n">quota</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;50G&quot;</span>
1853-
<a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a><span class="n">rate_limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;10M&quot;</span>
1854-
<a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a><span class="n">max_ips</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span>
1855-
<a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a><span class="n">expires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ld">2026-12-31T23:59:59Z</span>
1856-
<a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a>
1857-
<a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a><span class="k">[[secret]]</span>
1858-
<a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;dead01234567890abcead01234567890a&quot;</span>
1859-
<a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;guest&quot;</span>
1860-
<a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">50</span>
1861-
<a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a><span class="n">quota</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;5G&quot;</span>
1862-
<a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a><span class="n">rate_limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;2M&quot;</span>
1863-
<a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a><span class="n">max_ips</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3</span>
1864-
<a id="__codelineno-17-17" name="__codelineno-17-17" href="#__codelineno-17-17"></a><span class="n">expires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ld">2025-06-30T00:00:00Z</span>
1885+
<div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="k">[[secret]]</span>
1886+
<a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;cafe01234567890abcafe01234567890a&quot;</span>
1887+
<a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;family&quot;</span>
1888+
<a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">100</span>
1889+
<a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="n">quota</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;50G&quot;</span>
1890+
<a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a><span class="n">rate_limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;10M&quot;</span>
1891+
<a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a><span class="n">max_ips</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">10</span>
1892+
<a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a><span class="n">expires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ld">2026-12-31T23:59:59Z</span>
1893+
<a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a>
1894+
<a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a><span class="k">[[secret]]</span>
1895+
<a id="__codelineno-19-11" name="__codelineno-19-11" href="#__codelineno-19-11"></a><span class="n">key</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;dead01234567890abcead01234567890a&quot;</span>
1896+
<a id="__codelineno-19-12" name="__codelineno-19-12" href="#__codelineno-19-12"></a><span class="n">label</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;guest&quot;</span>
1897+
<a id="__codelineno-19-13" name="__codelineno-19-13" href="#__codelineno-19-13"></a><span class="n">limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">50</span>
1898+
<a id="__codelineno-19-14" name="__codelineno-19-14" href="#__codelineno-19-14"></a><span class="n">quota</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;5G&quot;</span>
1899+
<a id="__codelineno-19-15" name="__codelineno-19-15" href="#__codelineno-19-15"></a><span class="n">rate_limit</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s2">&quot;2M&quot;</span>
1900+
<a id="__codelineno-19-16" name="__codelineno-19-16" href="#__codelineno-19-16"></a><span class="n">max_ips</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">3</span>
1901+
<a id="__codelineno-19-17" name="__codelineno-19-17" href="#__codelineno-19-17"></a><span class="n">expires</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="ld">2025-06-30T00:00:00Z</span>
18651902
</code></pre></div>
18661903

18671904

0 commit comments

Comments
 (0)