This repository contains the configuration needed to run the live Torrust Tracker demo.
Live demo tracker endpoints:
- HTTP: https://http1.torrust-tracker-demo.com:443/announce
- UDP:
udp://udp1.torrust-tracker-demo.com:6969/announce
The tracker is listed on newtrackon for public uptime tracking.
Note: The low uptime shown for the UDP tracker (
udp1) reflects the fact that it was added only 24 hours before this screenshot was taken, and there was an IPv6 routing misconfiguration during that period that prevented newtrackon from receiving responses. See the post-mortem for details. Uptime figures should also be read in the context of server size and request load — a tracker running on a small server that is receiving more requests than it can handle will report low uptime even if the software itself is healthy. See docs/infrastructure.md for the exact server specification used in this demo.
Live public dashboards are available without a Grafana account:
| Dashboard | Public link | Screenshot |
|---|---|---|
| Tracker Overview | open | view |
| UDP Tracker 1 | open | view |
| HTTP Tracker 1 | open | view |
Torrust is an open-source organization building BitTorrent tools in Rust. Our two main projects are:
- Torrust Tracker — a feature-complete BitTorrent tracker (UDP + HTTP, IPv4 + IPv6).
- Torrust Index — a BitTorrent index (think: a self-hosted torrent site). It integrates with the tracker to automatically embed the tracker URL into uploaded torrents.
We have been running a combined live demo of both services since April 24, 2024, available at https://index.torrust-demo.com. That demo serves as a reference deployment and a public integration test for the two applications working together.
The original demo lived in a single repository: torrust/torrust-demo.
After running the combined demo for a while, we decided to split it into two separate repositories (torrust-demo#79):
- torrust/torrust-tracker-demo — this repository (tracker only).
- torrust/torrust-index-demo — the index demo (coming soon).
Reasons for the split:
- Independent deployability — the tracker and index can be deployed, updated, and scaled separately.
- Independent teams — different maintainers can own each demo without stepping on each other.
- Independent scaling — tracker and index have very different traffic patterns and resource needs.
- Tracker-only users — many users only need a tracker. Keeping tracker configuration separate makes it easier to adopt.
- Share the demo configuration — so that others can replicate the setup for their own deployments.
- Track production issues — issues raised here correspond to problems or improvements observed in the live demo environment.
- Document deployment — we believe there is a significant lack of practical documentation on how to deploy and operate BitTorrent tools. This repo is part of our effort to fix that.
| Property | Value |
|---|---|
| Running since | March 3, 2026 |
| Database | MySQL |
| IP support | IPv4 + IPv6 |
| Hosting | Hetzner |
| Monitoring | Grafana (dashboards for peer connections, performance, system health) |
The new tracker uses MySQL (the original combined demo used SQLite) and supports both IPv4 and IPv6.
The server was provisioned using torrust-tracker-deployer. Some features (floating IP routing, Docker IPv6) require manual post-deployment steps not covered by the deployer.
The diagram below shows the three levels of network isolation (floating IPs, server IPs, Docker networking), the software components involved in packet handling (OS kernel, UFW, Docker), and all real IPv4/IPv6 addresses.
flowchart TB
subgraph internet["Internet"]
client(["Client"])
end
subgraph hetzner["Floating IPs · Hetzner Cloud Routing"]
direction LR
http1["<b>http1</b><br/>IPv4: 116.202.176.169<br/>IPv6: 2a01:4f8:1c0c:9aae::1"]
udp1["<b>udp1</b><br/>IPv4: 116.202.177.184<br/>IPv6: 2a01:4f8:1c0c:828e::1"]
end
subgraph vm["VM Server · Hetzner CCX23 · nbg1-dc3"]
eth0["<b>eth0</b><br/>Server IPv4: 46.225.234.201<br/>Server IPv6: 2a01:4f8:1c19:620b::1<br/><i>+ floating IPs attached via netplan</i>"]
kernel["<b>OS Kernel</b> · Linux 6.8<br/>iptables · ip6tables<br/>netplan policy routing (tables 100, 200)"]
ufw["<b>UFW</b><br/>TCP :22 SSH · UDP :6969 Tracker"]
subgraph docker["Docker 28.2.2 · ip6tables: true"]
subgraph proxynet["proxy_network · bridge · IPv6: fd01:db8:1::/64"]
caddy["Caddy<br/>:80 · :443"]
tracker["Tracker<br/>:6969/udp · :6868/udp<br/>:7070 · :1212"]
grafana["Grafana<br/>:3000"]
end
subgraph dbnet["database_network · bridge"]
mysql["MySQL 8.4"]
end
subgraph metricsnet["metrics_network · bridge"]
prom["Prometheus<br/>:9090"]
end
end
end
client -- "HTTPS :443" --> http1
client -- "UDP :6969" --> udp1
http1 --> eth0
udp1 --> eth0
eth0 --> kernel
kernel --> ufw
ufw --> docker
caddy -. "reverse proxy" .-> tracker
caddy -. "reverse proxy" .-> grafana
tracker --> mysql
tracker --> prom
prom --> grafana
The trickiest traffic path is a native IPv6 UDP announce. The sequence below shows every hop and address rewrite between the client and the tracker container, including the DNAT on ingress and the SNAT on egress that keeps the reply source equal to the floating IP the client originally contacted.
sequenceDiagram
participant C as Client<br/>2409:8a5e::1
participant H as Hetzner<br/>Floating IP routing
participant E as eth0<br/>2a01:4f8:1c0c:828e::1
participant PRE as ip6tables<br/>PREROUTING
participant BR as Docker bridge<br/>fd01:db8:1::/64
participant T as Tracker container<br/>fd01:db8:1::3
participant POST as ip6tables<br/>POSTROUTING
Note over C,T: Ingress — client request
C->>H: UDP :6969<br/>src 2409:8a5e::1<br/>dst 2a01:4f8:1c0c:828e::1
H->>E: Hetzner routes floating IP<br/>to VM server
E->>PRE: packet enters kernel
PRE->>BR: DNAT: dst rewritten<br/>2a01:4f8:1c0c:828e::1 → fd01:db8:1::3
BR->>T: forwarded on bridge<br/>dst fd01:db8:1::3:6969
Note over C,T: Egress — tracker reply
T->>POST: reply<br/>src fd01:db8:1::3<br/>dst 2409:8a5e::1
Note over POST: SNAT (before6.rules):<br/>src rewritten<br/>fd01:db8:1::3 → 2a01:4f8:1c0c:828e::1
POST->>E: src = 2a01:4f8:1c0c:828e::1 ✅
E->>H: packet leaves eth0
H->>C: reply from floating IP ✅<br/>src 2a01:4f8:1c0c:828e::1
Note over POST: Without this SNAT rule,<br/>Docker MASQUERADE would use<br/>primary IPv6 2a01:4f8:1c19:620b::1<br/>→ client sees wrong source → timeout
For the full explanation of why both ip6tables: true in the Docker daemon and
the SNAT rule in before6.rules are required, see
docs/docker-ipv6.md. For full IP and DNS tables, see
docs/infrastructure.md.
| Repository | Description |
|---|---|
| torrust/torrust-tracker | The tracker software itself |
| torrust/torrust-index | The index software |
| torrust/torrust-demo | Original combined demo (Index + Tracker) |
| torrust/torrust-tracker-deployer | Deployment tooling used to provision this demo |
This project uses torrust-linting as a unified linter for Markdown, YAML, spell checking, and shell scripts. A CI workflow runs all linters automatically on every push and pull request.
cargo install torrust-linting --lockedThis installs a binary called linter on your $PATH.
./scripts/lint.shThis runs markdown, YAML, spell check, and shell script linters in sequence.
Note: Do not run
linter all— this repo is not a Rust project, so the Rust-specific linters (clippy, rustfmt) will fail.
Add any new project-specific words to project-words.txt (one word per line)
to suppress false positives from the spell checker.
This demo tracker is provided for documentation and educational purposes only. It is intended to demonstrate how to deploy and operate the Torrust Tracker, and not to provide a persistent or general-purpose public tracking service.
This software is provided solely for lawful purposes. Users must ensure compliance with all applicable laws and regulations regarding copyright and intellectual property. The Torrust organization and its contributors do not condone or support the use of this tracker for any illegal activities, including but not limited to the distribution of copyrighted, protected, or otherwise illegal content.
By using this tracker, you agree to use it responsibly and in compliance with all applicable legal requirements. Misuse of this tracker for illegal purposes may lead to legal consequences, for which the Torrust organization and its contributors are not liable.
Tracker data (peer lists, announce history) may be reset at any time without notice.
Feedback, issues, and pull requests are welcome. If you spot a problem with the live demo or have a suggestion for improving the configuration or documentation, please open an issue.