Skip to content

Commit bf73227

Browse files
committed
docs: [#272] Document tracker on_reverse_proxy global setting limitation
- Document issue discovered during HTTPS/Caddy implementation - Explain why per-HTTP-tracker on_reverse_proxy is needed - Propose solution with backward-compatible configuration - Reference deployer workaround (all-or-nothing proxy rule)
1 parent a857e07 commit bf73227

1 file changed

Lines changed: 189 additions & 0 deletions

File tree

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Tracker `on_reverse_proxy` is Global Instead of Per-HTTP-Tracker
2+
3+
**Issue Date**: January 16, 2026
4+
**Affected Component**: Torrust Tracker Configuration
5+
**Status**: Documented - Issue filed in tracker repository
6+
**Upstream Issue**: [torrust/torrust-tracker#1640](https://github.com/torrust/torrust-tracker/issues/1640)
7+
8+
## Problem Description
9+
10+
The Torrust Tracker has a configuration option `[core.net].on_reverse_proxy` that controls whether the tracker expects `X-Forwarded-For` HTTP headers to determine the real client IP address. This setting is **global** and applies to **all HTTP trackers** in the deployment.
11+
12+
This creates a limitation: you cannot have some HTTP trackers behind a reverse proxy while others are accessed directly in the same deployment.
13+
14+
## How We Discovered This
15+
16+
While implementing HTTPS support with Caddy as a TLS-terminating reverse proxy in the [Torrust Tracker Deployer](https://github.com/torrust/torrust-tracker-deployer), we needed to configure the tracker to work behind Caddy.
17+
18+
Our use case:
19+
20+
- Multiple HTTP trackers on different ports (e.g., 7070, 7071, 7072)
21+
- Some trackers exposed via HTTPS through Caddy (TLS termination)
22+
- Some trackers exposed directly via HTTP (no proxy)
23+
24+
**Example configuration intent**:
25+
26+
```json
27+
{
28+
"http_trackers": [
29+
{
30+
"bind_address": "0.0.0.0:7070",
31+
"domain": "http1.tracker.local",
32+
"use_tls_proxy": true
33+
},
34+
{
35+
"bind_address": "0.0.0.0:7071",
36+
"domain": "http2.tracker.local",
37+
"use_tls_proxy": true
38+
},
39+
{
40+
"bind_address": "0.0.0.0:7072"
41+
}
42+
]
43+
}
44+
```
45+
46+
In this scenario:
47+
48+
- Trackers on ports 7070 and 7071 are behind Caddy (need `on_reverse_proxy = true`)
49+
- Tracker on port 7072 is direct (needs `on_reverse_proxy = false`)
50+
51+
However, the current tracker configuration only allows:
52+
53+
```toml
54+
[core.net]
55+
on_reverse_proxy = true # Applies to ALL HTTP trackers
56+
```
57+
58+
## Root Cause
59+
60+
The `on_reverse_proxy` setting is defined in `[core.net]` which is a global network configuration section, not per-tracker. Looking at the tracker's network configuration structure:
61+
62+
**Reference**: [Torrust Tracker Network Configuration](https://docs.rs/torrust-tracker-configuration/latest/torrust_tracker_configuration/v2_0_0/network/struct.Network.html)
63+
64+
```rust
65+
pub struct Network {
66+
// ...
67+
pub on_reverse_proxy: bool, // Global setting
68+
// ...
69+
}
70+
```
71+
72+
Each HTTP tracker configuration does not have its own `on_reverse_proxy` field.
73+
74+
## Impact
75+
76+
### For Deployer Users
77+
78+
When `on_reverse_proxy = true` is set globally:
79+
80+
1. **All HTTP trackers expect `X-Forwarded-For` headers**
81+
2. Trackers accessed directly (without proxy) will **fail to identify client IPs correctly**
82+
3. The tracker will see the absence of `X-Forwarded-For` and may log warnings or behave unexpectedly
83+
84+
When `on_reverse_proxy = false` is set globally:
85+
86+
1. **All HTTP trackers ignore `X-Forwarded-For` headers**
87+
2. Trackers behind a reverse proxy will **see the proxy's IP as the client IP**
88+
3. All peers from different clients will appear to come from the same IP (the proxy)
89+
4. This breaks peer identification in swarms
90+
91+
### Current Workaround in Deployer
92+
93+
We enforce a rule in the deployer:
94+
95+
> **If ANY HTTP tracker uses a TLS proxy, ALL HTTP trackers must use the TLS proxy.**
96+
97+
This is documented as a known limitation and validated during environment creation:
98+
99+
```text
100+
Known Limitation (due to tracker's global setting):
101+
102+
If you have multiple HTTP trackers where some use use_tls_proxy and others don't,
103+
the ones without it will still receive the global on_reverse_proxy = true setting
104+
and may fail if they receive direct requests without X-Forwarded-For headers.
105+
106+
Workaround: Ensure all HTTP trackers in a deployment either ALL use the TLS proxy
107+
or NONE use it.
108+
```
109+
110+
This limitation reduces deployment flexibility and forces users into an all-or-nothing approach.
111+
112+
## Recommended Solution
113+
114+
Add an optional `on_reverse_proxy` field to each HTTP tracker configuration, allowing per-tracker control:
115+
116+
### Proposed Configuration Structure
117+
118+
```toml
119+
[core.net]
120+
on_reverse_proxy = false # Default for trackers without explicit setting
121+
122+
[[http_trackers]]
123+
bind_address = "0.0.0.0:7070"
124+
on_reverse_proxy = true # Override: this tracker is behind a proxy
125+
126+
[[http_trackers]]
127+
bind_address = "0.0.0.0:7071"
128+
on_reverse_proxy = true # Override: this tracker is behind a proxy
129+
130+
[[http_trackers]]
131+
bind_address = "0.0.0.0:7072"
132+
# No override: uses global default (false) - direct access
133+
```
134+
135+
### Behavior
136+
137+
1. If `on_reverse_proxy` is specified on an HTTP tracker, use that value
138+
2. If not specified, fall back to `[core.net].on_reverse_proxy` (backward compatible)
139+
3. Each HTTP tracker independently decides whether to read `X-Forwarded-For`
140+
141+
### Implementation Considerations
142+
143+
The HTTP tracker request handler would need to check its own `on_reverse_proxy` setting when extracting the client IP, rather than checking the global setting.
144+
145+
**Pseudocode change**:
146+
147+
```rust
148+
// Before (global check)
149+
fn get_client_ip(request: &Request, config: &Config) -> IpAddr {
150+
if config.core.net.on_reverse_proxy {
151+
extract_from_x_forwarded_for(request)
152+
} else {
153+
request.peer_addr()
154+
}
155+
}
156+
157+
// After (per-tracker check)
158+
fn get_client_ip(request: &Request, tracker_config: &HttpTrackerConfig) -> IpAddr {
159+
let on_reverse_proxy = tracker_config.on_reverse_proxy
160+
.unwrap_or(config.core.net.on_reverse_proxy);
161+
162+
if on_reverse_proxy {
163+
extract_from_x_forwarded_for(request)
164+
} else {
165+
request.peer_addr()
166+
}
167+
}
168+
```
169+
170+
## Benefits of This Change
171+
172+
1. **Flexible deployments**: Mix proxied and direct HTTP trackers in one deployment
173+
2. **Backward compatible**: Global setting remains the default
174+
3. **Clearer intent**: Each tracker explicitly declares its network topology
175+
4. **Better for edge cases**: Internal trackers (localhost) vs external (behind proxy)
176+
177+
## Use Cases Enabled
178+
179+
1. **Mixed TLS/non-TLS deployment**: Some trackers via HTTPS (Caddy), some via direct HTTP
180+
2. **Internal monitoring**: Direct localhost tracker for Prometheus, proxied trackers for public access
181+
3. **Gradual migration**: Move trackers behind proxy one at a time during migration
182+
4. **Multi-tenant**: Different trackers for different networks with different proxy configurations
183+
184+
## References
185+
186+
- [Torrust Tracker Network Configuration Docs](https://docs.rs/torrust-tracker-configuration/latest/torrust_tracker_configuration/v2_0_0/network/struct.Network.html)
187+
- [Torrust Tracker Repository](https://github.com/torrust/torrust-tracker)
188+
- [Deployer Issue #272 - Add HTTPS Support](https://github.com/torrust/torrust-tracker-deployer/issues/272)
189+
- [Deployer PR #273 - HTTPS Implementation](https://github.com/torrust/torrust-tracker-deployer/pull/273)

0 commit comments

Comments
 (0)