mirror of
https://github.com/euzu/tuliprox.git
synced 2026-10-23 16:22:31 +02:00
203 lines
9.9 KiB
Markdown
203 lines
9.9 KiB
Markdown
# 🌊 Reverse Proxy (Streaming, Caching & Rate Limits)
|
|||
|
|
|
||
|
|
This section documents the `reverse_proxy:` block inside `config.yml`. It is the most critical block for determining runtime
|
||
|
|
behavior when Tuliprox actively proxies video streams to clients (Reverse Proxy Mode), rather than just redirecting them.
|
||
|
|
|
||
|
|
It manages how Tuliprox establishes upstream connections, buffers video frames, handles sudden client disconnects, and caches
|
||
|
|
static resources like EPG images and channel logos.
|
||
|
|
|
||
|
|
## Top-level entries
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
resource_rewrite_disabled: false
|
||
|
|
rewrite_secret: A1B2C3D4E5F60718293A4B5C6D7E8F90
|
||
|
|
stream:
|
||
|
|
cache:
|
||
|
|
rate_limit:
|
||
|
|
disabled_header:
|
||
|
|
resource_retry:
|
||
|
|
geoip:
|
||
|
|
```
|
||
|
|
|
||
|
|
### General Parameters
|
||
|
|
|
||
|
|
| Parameter | Type | Default | Technical Impact & Background |
|
||
|
|
| :--- | :--- | :--- | :--- |
|
||
|
|
| `resource_rewrite_disabled` | Bool | `false` | Normally, Tuliprox rewrites all image URLs in playlists to point to itself (e.g., `http://tuliprox:8901/resource/...`). If set to `true`, original URLs are kept (clients load images directly from the provider). **Warning:** Local caching will stop working if this is enabled! |
|
||
|
|
| `rewrite_secret` | String | `""` | A 32-character Hex string (16 bytes). Tuliprox encrypts/signs the original image URLs during the rewrite process. To prevent image URLs from becoming invalid after a server restart, you MUST enter a static secret here (generate via `openssl rand -hex 16`). |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Stream Management (`stream`)
|
||
|
|
|
||
|
|
This sub-block defines how Tuliprox maintains stream stability, buffers data, and handles HLS/Catchup session affinity.
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
stream:
|
||
|
|
retry: true
|
||
|
|
buffer:
|
||
|
|
enabled: true
|
||
|
|
size: 1024
|
||
|
|
throttle_kbps: 12500
|
||
|
|
grace_period_millis: 2000
|
||
|
|
grace_period_timeout_secs: 4
|
||
|
|
grace_period_hold_stream: true
|
||
|
|
hls_session_ttl_secs: 15
|
||
|
|
catchup_session_ttl_secs: 45
|
||
|
|
shared_burst_buffer_mb: 12
|
||
|
|
metrics_enabled: false
|
||
|
|
```
|
||
|
|
|
||
|
|
### Stream Parameters in Detail
|
||
|
|
|
||
|
|
| Parameter | Type | Default | Technical Impact & Background |
|
||
|
|
| :--- | :--- | :--- | :--- |
|
||
|
|
| `retry` | Bool | `true` | **Background:** If the upstream provider unexpectedly drops the connection or a TCP network timeout occurs, Tuliprox immediately opens a new connection to the provider in the background and seamlessly pipes the new bytes to the end-client. The client's player (e.g., VLC) might stutter for a fraction of a second but will not abort playback. |
|
||
|
|
| `buffer.enabled` | Bool | `false` | Enables an asynchronous ring-buffer in RAM between the provider download stream and the client upload stream. Necessary if the provider stream is faster than the consumer can process. |
|
||
|
|
| `buffer.size` | Int | `0` | The size of the buffer in *Chunks* (1 Chunk = 8192 Bytes). A value of `1024` equals approximately 8 Megabytes of RAM per active stream. |
|
||
|
|
| `throttle_kbps` | Int | `0` | **Background:** Some players download VODs (Movies) at maximum line speed ("Bursting"). Providers often view this as abuse or scraping and will ban the IP. By throttling (e.g., to `12500` kbps), you force the download into a constant, inconspicuous flow. Supports units like `KB/s`, `MB/s`, `kbps`, `Mibps`. |
|
||
|
|
| `metrics_enabled` | Bool | `false` | **Monitoring:** If active, Tuliprox samples the live bandwidth (in kbps) and transferred bytes for every active reverse-proxied stream and pushes them via WebSockets to the Web UI. It adds a tiny bit of CPU overhead but is invaluable for debugging buffering issues. |
|
||
|
|
| `grace_period_millis` | Int | `2000` | The exact time window in ms where a temporary over-allocation is allowed (see notes on [The VLC Seek Problem](#the-vlc-seek-problem--grace-periods) for details). |
|
||
|
|
| `grace_period_timeout_secs` | Int | `4` | A hard timeout limit for overlapping "ghost sessions" to expire. |
|
||
|
|
| `grace_period_hold_stream` | Bool | `true` | Tuliprox artificially holds back the video data to the client, waiting for the grace check to finish, so it doesn't trigger the provider prematurely. |
|
||
|
|
| `hls_session_ttl_secs` | Int | `15` | Keeps the virtual provider slot open between HLS segment (`.ts`) requests to prevent provider bans for "Account Hopping". |
|
||
|
|
| `catchup_session_ttl_secs` | Int | `45` | The same session-holding principle applied to Archive/Catchup TV. See notes on section [Session TTLs for HLS & Catchup](#session-ttls-for-hls-m3u8--catchup) for details. |
|
||
|
|
| `shared_burst_buffer_mb` | Int | `12` | Minimum burst buffer size (in MB) used for shared live streams to immediately synchronize new clients without Keyframe dropouts. See notes on section [Shared Live Streams](#shared-live-streams) for details. |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. Resource Caching (`cache`)
|
||
|
|
|
||
|
|
Tuliprox caches channel logos, posters, and EPG images on your disk so your clients don't stress the provider's servers on every
|
||
|
|
playlist reload.
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
cache:
|
||
|
|
enabled: true
|
||
|
|
size: 1GB
|
||
|
|
directory: ./cache
|
||
|
|
```
|
||
|
|
|
||
|
|
An LRU (Least Recently Used) disk cache. If it hits the limit (e.g., `1GB`), Tuliprox automatically deletes the oldest images.
|
||
|
|
Note: Fails if `resource_rewrite_disabled` is true.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Rate Limiting (`rate_limit`)
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
rate_limit:
|
||
|
|
enabled: true
|
||
|
|
period_millis: 500
|
||
|
|
burst_size: 10
|
||
|
|
```
|
||
|
|
|
||
|
|
Implements an IP-based Token-Bucket rate limiter. In this example, an IP can fire 10 requests immediately (`burst_size`). After
|
||
|
|
that, it receives exactly one new token every 500ms (`period_millis`). This prevents DDOS attacks from malfunctioning scrapers.
|
||
|
|
*(Ensure your upstream Nginx/Traefik passes `X-Forwarded-For` for this to work correctly!)*
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Header Stripping (`disabled_header`)
|
||
|
|
|
||
|
|
When Tuliprox makes requests to the upstream provider, it can strip revealing headers that might expose which player you are
|
||
|
|
actually using or the fact that you are proxying traffic.
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
disabled_header:
|
||
|
|
referer_header: true # Removes the 'Referer' header
|
||
|
|
x_header: true # Removes all 'X-*' headers (like X-Real-IP)
|
||
|
|
cloudflare_header: true# Removes 'CF-*' headers
|
||
|
|
custom_header:
|
||
|
|
- my-custom-tracker
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 5. Resource Retries (`resource_retry`)
|
||
|
|
|
||
|
|
Defines how aggressively Tuliprox tries to retry failed logo or EPG downloads when proxying them from the provider.
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
resource_retry:
|
||
|
|
max_attempts: 3
|
||
|
|
backoff_millis: 250
|
||
|
|
backoff_multiplier: 1.5
|
||
|
|
failover_redirect_patterns:
|
||
|
|
- "service-abuse"
|
||
|
|
```
|
||
|
|
|
||
|
|
* **Retries:** After the first error, Tuliprox waits 250ms. After the second error, it waits `250 * 1.5 = 375ms`, and so on.
|
||
|
|
* **`failover_redirect_patterns`:** A list of Regex patterns. If an upstream resource responds with an HTTP Redirect (302)
|
||
|
|
containing these patterns (e.g., pointing to a "service-abuse" warning image from the provider), Tuliprox treats it as a
|
||
|
|
failure instead of blindly serving the abuse image to your clients.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 6. GeoIP Resolution (`geoip`)
|
||
|
|
|
||
|
|
To see the country flags of connected clients in the Web UI ("Active Streams" tab), Tuliprox can resolve IP addresses locally.
|
||
|
|
|
||
|
|
```yaml
|
||
|
|
reverse_proxy:
|
||
|
|
geoip:
|
||
|
|
enabled: true
|
||
|
|
url: "https://raw.githubusercontent.com/sapics/ip-location-db/refs/heads/main/asn-country/asn-country-ipv4.csv"
|
||
|
|
```
|
||
|
|
|
||
|
|
The CSV file must have exactly 3 columns: `range_start,range_end,country_code`. (The DB is periodically updated via the
|
||
|
|
`schedules` block using the `GeoIpUpdate` task type).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
## Additional Information
|
||
|
|
|
||
|
|
## The "VLC Seek Problem" & Grace Periods
|
||
|
|
|
||
|
|
When a user fast-forwards or rewinds a VOD, the player calculates the new byte offset, drops the old TCP connection, and
|
||
|
|
immediately fires a new HTTP GET request (with a `Range` header) to Tuliprox.
|
||
|
|
|
||
|
|
**The Problem:** It takes milliseconds to seconds for the upstream provider to realize the old connection is dead. If you have
|
||
|
|
a `max_connections: 1` limit at the provider, they will view this new seek-request as a *second concurrent stream* and reject
|
||
|
|
it with an HTTP 509 (Bandwidth Exceeded) or HTTP 401 error.
|
||
|
|
|
||
|
|
**The Tuliprox Solution:**
|
||
|
|
|
||
|
|
* `grace_period_millis: 2000`: Tuliprox grants the user a temporary over-allocation (Grace) for exactly this duration.
|
||
|
|
* `grace_period_hold_stream: true`: Tuliprox artificially holds back the video data to the client, waiting for the grace check
|
||
|
|
to finish, so it doesn't trigger the provider prematurely.
|
||
|
|
* After the milliseconds expire, Tuliprox checks internally: Is the old connection truly gone now? If Yes ➔ Data flows.
|
||
|
|
If No ➔ The new connection is hard-killed (serving the `user_connections_exhausted.ts` video) because the user is actually
|
||
|
|
illegally watching twice.
|
||
|
|
* `grace_period_timeout_secs: 4`: A hard timeout limit for overlapping "ghost sessions" to expire.
|
||
|
|
|
||
|
|
## Session TTLs for HLS (`.m3u8`) & Catchup
|
||
|
|
|
||
|
|
HLS streams do not consist of an endless TCP pipe. Instead, the player downloads small `.ts` segments every few seconds
|
||
|
|
(e.g., `seg1.ts`, `seg2.ts`).
|
||
|
|
|
||
|
|
If Tuliprox released and re-acquired the provider slot for every single segment, providers would block the account for "Account
|
||
|
|
Hopping" or spam. Tuliprox simulates a continuous session:
|
||
|
|
|
||
|
|
* `hls_session_ttl_secs: 15`: After a `.ts` segment finishes downloading, the physical slot to the provider is closed, but the
|
||
|
|
"Virtual Slot" for this specific user remains reserved for 15 seconds. No other user can steal this slot during this window.
|
||
|
|
Channel switches from the same client can immediately take over the reservation.
|
||
|
|
* The same principle applies to Archive/Catchup TV (`catchup_session_ttl_secs: 45`), which shares the same fragmentation and
|
||
|
|
seeking issues.
|
||
|
|
|
||
|
|
## Shared Live Streams
|
||
|
|
|
||
|
|
Tuliprox can share a live stream (`share_live_streams: true` in the target options of `source.yml`). If 5 users watch the same
|
||
|
|
Live-TV channel, Tuliprox pulls the stream only 1x from the provider and multicasts the bytes locally to 5 clients.
|
||
|
|
To ensure a user who tunes in 10 seconds later doesn't get player errors due to missing I-Frames/Keyframes, Tuliprox
|
||
|
|
continuously keeps the last X Megabytes (`shared_burst_buffer_mb`, default `12`) in RAM. It fires this burst buffer at new
|
||
|
|
subscribers so their decoders can instantly synchronize.
|