Files
tuliprox/docs/src/examples-recipes.md
T
euzuandGitHub 5ecfd68148 Staged filter and safe yaml update (#846)
New Features

    Added separate processing and persistence filters, with empty/non-empty checks and expanded filter fields.
    Added persistence-stage filter controls in target settings.
    Added clear_invalid_epg_ids, preserving playlist entries while clearing unresolved EPG IDs; the legacy setting remains supported.
    Added safer, atomic source configuration updates that preserve comments and formatting.

Bug Fixes

    Null-like Xtream and Stalker values are now handled correctly.
    Duplicate credential warnings provide clearer details.
2026-08-30 21:08:30 +02:00

284 lines
10 KiB
Markdown

# 🧪 Examples, Recipes & Ecosystem Stacks
This chapter provides concrete copy & paste solutions for common scenarios spanning the different pillars of the Tuliprox architecture, concluding
with the ultimate Docker deployment stack.
## 1. Quickstart: Minimal Provider Setup
To use Tuliprox, you need to configure at least three core files:
1. `config.yml`: Defines the core server settings.
2. `source.yml`: Defines the upstream provider and your output targets.
3. `api-proxy.yml`: Defines your local/external server addresses and the users who can access the targets.
### Scenario: Minimal Xtream Setup
You have an Xtream provider (`http://fantastic.provider.xyz:8080`) and want to simply "pass through" the streams while utilizing the Web UI.
**1. `config.yml` (Core Engine):**
```yaml
api:
host: 0.0.0.0
port: 8901
web_root: ./web
storage_dir: ./data
update_on_boot: true
```
*This configuration starts Tuliprox on port 8901. Downloaded playlists are stored inside the `data` folder.*
*Setting `update_on_boot: true` is helpful during initial setup to immediately pull provider data.*
**2. `source.yml` (Inputs & Targets):**
```yaml
inputs:
- type: xtream
name: my_provider
url: http://fantastic.provider.xyz:8080
username: tvjunkie
password: junkie.secret
sources:
- inputs:
- my_provider
targets:
- name: clean_list
output:
- type: xtream
```
*Here we define the input source based on the provider's information and create a 1:1 mapped target (`clean_list`).
The optional target filter is omitted, so every entry passes the processing stage.*
**3. `api-proxy.yml` (Servers & Users):**
```yaml
server:
- name: default
protocol: http
host: 192.168.1.41
port: 8901
timezone: Europe/Berlin
message: Welcome to tuliprox
- name: external
protocol: https
host: tv.my-domain.com
port: 443
timezone: Europe/Berlin
path: iptv
user:
- target: clean_list
credentials:
- username: me
password: mypass
proxy: redirect # Tuliprox only redirects the player; it does not proxy the video stream
server: default
```
*We define two server endpoints (internal LAN and external HTTPS). We then bind a user to the `clean_list` target.*
*Using `proxy: redirect` saves bandwidth on your server during initial testing.*
**Resulting Client Endpoints:**
You can now enter the following credentials into your IPTV player (e.g., TiviMate, IPTV Smarters):
* **Portal URL:** `http://192.168.1.41:8901`
* **Username:** `me`
* **Password:** `mypass`
Start `tuliprox`, fire up your IPTV-Application, enter credentials and watch.
### Scenario: Minimal M3U Setup
If your provider uses standard M3U instead of the Xtream Codes API, simply adjust the input type in `source.yml`.
Tuliprox automatically extracts credentials from the URL if present.
**`source.yml` (M3U Variation):**
```yaml
inputs:
- type: m3u
name: my_m3u_provider
url: "http://fantastic.provider.xyz:8080/get.php?username=tvjunkie&password=junkie.secret&type=m3u_plus&output=ts"
cache_duration: 1d
```
---
## 2. Advanced Filtering (Exclusion Logic & Templates)
A 1:1 pass-through is rarely what you want. Upstream provider lists are often cluttered with countries or VOD sections you don't need.
Tuliprox uses a custom DSL (Domain Specific Language) for filtering. You need a basic understanding of Regular Expressions (Regex).
A good site for learning and testing is[regex101.com](https://regex101.com/) (ensure you select the **Rust** flavor).
### The Basics
DSL filters are applied in `source.yml` at the `target` level. The tilde `~` operator executes a Regex match.
Evaluatable fields include `Group`, `Title`, `Name`, `Url`, and `Type`.
* **Simple Inclusion:**
Include all categories: `Group ~ ".*"`
* **Case-Insensitive Inclusion:**
Include all categories whose name contains "shopping": `Group ~ "(?i).*Shopping.*"`
* **Reversing Logic (Exclusion):**
I don't want any shopping categories: `NOT (Group ~ "(?i).*Shopping.*")`
* **Specific Channel Exclusion:**
Filtering a specific channel, even if it appears in multiple groups:
`NOT (Title ~ "FR: TV5Monde" AND Group ~ "FR: TF1")`
### Complex Matrix (Bracket Logic)
Allow everything from Germany (DE) and France (FR), except Series and Commercials. Always allow Australia (AU).
```text
((Group ~ "^(DE|FR).*") AND NOT (Group ~ "(?i).*SERIES.*" OR Group ~ "(?i).*COMMERCIAL.*")) OR (Group ~ "^AU.*")
```
### Refactoring with Templates (The DRY Principle)
As you can see, filter strings can quickly become massive and unmaintainable.
This is where **Templates**[**Templates**](./configuration/template.md) come into play.
You can disassemble a monolithic filter into smaller, readable parts and combine them.
```yaml
templates:
- name: NO_SHOPPING
value: 'NOT (Group ~ "(?i).*Shopping.*" OR Group ~ "(?i).*Einkaufen.*" OR Group ~ "(?i).*téléachat.*")'
- name: GERMAN_CHANNELS
value: 'Group ~ "^DE: .*"'
- name: FRENCH_CHANNELS
value: 'Group ~ "^FR: .*"'
- name: NO_TV5MONDE_IN_TF1
value: 'NOT (Group ~ "FR: TF1" AND Title ~ "FR: TV5Monde")'
- name: EXCLUDED_CHANNELS
value: '!NO_TV5MONDE_IN_TF1! AND !NO_SHOPPING!'
# Final combination
- name: MY_CHANNELS
value: '!EXCLUDED_CHANNELS! AND (!GERMAN_CHANNELS! OR !FRENCH_CHANNELS!)'
inputs:
- type: xtream
name: my_provider
url: http://fantastic.provider.xyz:8080
sources:
- inputs:
- my_provider
targets:
- name: curated_list
output:
- type: xtream
filter: "!MY_CHANNELS!"
```
*The resulting playlist now cleanly contains all French and German channels, minus any shopping channels or specifically blacklisted streams.*
---
## 3. Generating Custom Fallback Videos (FFmpeg)
If a provider stream returns a 404 or the user hits their connection limit, it is much more elegant to play an info video ("Channel Offline") than letting
the player hang endlessly on a dropped HTTP connection. Tuliprox searches the `custom_stream_response_path` folder for exactly named `.ts` files
(MPEG-TS).
You can turn a simple image (`blank_screen.jpg`) into a clean, 10-second fallback stream with a silent audio track (crucial for player A/V
sync!) using FFmpeg:
```bash
ffmpeg -y -nostdin -loop 1 -framerate 30 -i blank_screen.jpg -f lavfi \
-i anullsrc=channel_layout=stereo:sample_rate=48000 -t 10 -shortest -c:v libx264 \
-pix_fmt yuv420p -preset veryfast -crf 23 -x264-params "keyint=30:min-keyint=30:scenecut=0:bframes=0:open_gop=0" \
-c:a aac -b:a 128k -ac 2 -ar 48000 -mpegts_flags +resend_headers -muxdelay 0 -muxpreload 0 -f mpegts channel_unavailable.ts
```
Move `channel_unavailable.ts` into your resources folder. Tuliprox will loop this file from RAM until the user switches channels or the
`custom_stream_response_timeout_secs` limit is reached.
---
## 4. The Ultimate Docker Ecosystem Stack
Running Tuliprox bare-metal is fine, but running it behind a modern DevSecOps stack provides SSL termination, VPN routing to bypass ISP
blocks, and firewall protection against brute-force attacks.
In the repository under `docker/container-templates/`, you will find ready-to-use Docker Compose files.
### Components of the Stack
1. **Traefik (Reverse Proxy Ingress):** Handles incoming port 443 traffic, auto-renews Let's Encrypt certificates (via Cloudflare DNS-01 challenge), and
applies strict Content-Security-Policy headers.
2. **Gluetun (VPN Egress):** A WireGuard/OpenVPN client container. It connects e.g. to Mullvad or Proton VPN.
Tuliprox can then be configured to route its upstream provider requests through this Socks5 proxy, completely hiding your server's IP
from the IPTV provider.
3. **CrowdSec (WAF & Bouncer):** Analyzes Traefik access logs in real-time. If someone tries to brute-force your Tuliprox Web UI or run
path-traversal attacks, CrowdSec instructs the Traefik Bouncer plugin to drop their IP at the edge.
4. **IPTV-org-epg (EPG guide):** Generates a local XMLTV guide for the selected channels and makes it available to
Tuliprox.
### How to wire it up
**1. Create the Docker Networks:**
```bash
docker network create proxy-net
docker network create crowdsec-net
```
**2. Configure Gluetun & Socks5:**
In `container-templates/gluetun/.env.wg`, add your Wireguard details.
In `container-templates/gluetun/.env.socks5-proxy`, set user/pass for the proxy.
Start it: `docker-compose up -d`. It exposes port 1388 internally.
**3. Configure Tuliprox to use the VPN:**
In your `config.yml`, point the global proxy setting to the Socks5 container:
```yaml
proxy:
url: socks5://gluetun:1388
username: "<socks5-proxy-user>"
password: "<socks5-proxy-password>"
```
*Note: Ensure Tuliprox and the Socks5 container share the `proxy-net` network.*
**4. Protect Tuliprox with Traefik Labels:**
In your Tuliprox `docker-compose.yml`, add the Traefik labels to route traffic securely:
```yaml
labels:
- "traefik.enable=true"
- "traefik.http.routers.tuliprox-secure.entrypoints=websecure"
- "traefik.http.routers.tuliprox-secure.rule=Host(`tv.yourdomain.com`)"
- "traefik.http.routers.tuliprox-secure.tls=true"
- "traefik.http.routers.tuliprox-secure.tls.certresolver=cloudflare"
# Attach CrowdSec Bouncer and Security Headers
- "traefik.http.routers.tuliprox-secure.middlewares=cs-bouncer-traefik-plugin@file,default-security-headers@file"
- "traefik.http.services.tuliprox.loadbalancer.server.port=8901"
```
This architecture ensures your IPTV provider only sees the VPN IP, your clients only see your secure `tv.yourdomain.com` domain, and malicious
bots are blocked instantly by CrowdSec before they even reach the Rust backend.
>**⚠️ Important:** make sure you add
>[tuliprox-cover-whitelist.yaml](../../docker/container-templates/crowdsec/crowdsec/config/parsers/s02-enrich/tuliprox-cover-whitelist.yaml)
> to `crowdsec/config/parsers/s02-enrich/tuliprox-cover-whitelist.yaml` in your Crowdsec instance.
> Otherwise, you could quickly end up banning yourself.
**5. Configure IPTV-org-epg:**
Copy the desired channel entries from the IPTV-org `sites` files to
`container-templates/iptv-org/data/channels.xml`. For every channel, `xmltv_id` must exactly match the
corresponding `@epg_channel_id` in Tuliprox. For example, `xmltv_id="BBCOne.uk@LondonHD"` matches
`@epg_channel_id = "BBCOne.uk@LondonHD"`. If necessary, adjust `xmltv_id` in `channels.xml` or set the corresponding
`@epg_channel_id` in `mapping.yml`.
Start it: `docker-compose up -d`. Add the generated guide to the corresponding input in your `source.yml`:
```yaml
epg:
sources:
- url: http://iptv-org-epg:3000/guide.xml
```