- Python 76.1%
- HTML 23.9%
|
retiolus
08fe56d2e1
fix CSRF failure behind HTTPS reverse proxy
Django behind Nginx rejects POST forms when the Referer header scheme (https://) doesn't match the scheme uvicorn sees (http://). - Add SECURE_PROXY_SSL_HEADER and USE_X_FORWARDED_HOST to settings so Django trusts the X-Forwarded-Proto header sent by Nginx - Add CSRF_TRUSTED_ORIGINS read from config.json - Add X-Forwarded-Proto $scheme to Nginx location block in README - Add csrf_trusted_origins to config.json.example and README example |
||
|---|---|---|
| pybittrack | fix CSRF failure behind HTTPS reverse proxy | |
| templates | add admin interface, optimise Redis storage, harden tracker | |
| tests | add admin interface, optimise Redis storage, harden tracker | |
| tracker | add admin interface, optimise Redis storage, harden tracker | |
| .gitignore | transition to redis | |
| config.json.example | fix CSRF failure behind HTTPS reverse proxy | |
| LICENSE | Initial commit | |
| manage.py | refactor: migrate from Flask to Django with modular architecture | |
| README.md | fix CSRF failure behind HTTPS reverse proxy | |
| requirements.txt | add admin interface, optimise Redis storage, harden tracker | |
PyBitTrack
High-performance BitTorrent tracker built with Django + Redis. Handles 1 M+ concurrent torrents, async ASGI workers, and an admin interface.
Announce: https://your-domain/announce
Scrape: https://your-domain/scrape
Stats: https://your-domain/stats
Admin: https://your-domain/admin/
Requirements
| Component | Version |
|---|---|
| Python | 3.11+ |
| Redis | 6+ |
| Nginx | any recent |
| OS | Debian/Ubuntu (or any Linux) |
Installation
1. Clone
git clone https://codeberg.org/retiolus/pybittrack.git
cd pybittrack
2. Virtual environment & dependencies
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
3. Configuration
cp config.json.example config.json
Edit config.json:
{
"host": "0.0.0.0",
"port": 6969,
"secret_key": "change_this_to_a_long_random_string",
"redis": {
"host": "localhost",
"port": 6379,
"db": 1,
"password": ""
},
"site": {
"title": "PyBitTrack"
},
"tracker": {
"announce_interval": 900,
"announce_min_interval": 899,
"announce_timeout_factor": 1.25
},
"logging": {
"level": "ERROR"
},
"csrf_trusted_origins": ["https://your-domain.tld"],
"admin": {
"password": "change_this_strong_password"
}
}
Key fields:
| Field | Description |
|---|---|
secret_key |
Django secret key — long, random, keep private |
redis.db |
Redis DB index (0–15). Use a dedicated index, not 0. |
tracker.announce_interval |
Seconds between client announces (900 = 15 min) |
tracker.announce_timeout_factor |
Peer considered stale after interval ×ばつ factor |
admin.password |
Password for the /admin/ interface |
4. Verify
source venv/bin/activate
python manage.py check
Expected output: System check identified no issues (0 silenced).
Running
Development (quick test)
source venv/bin/activate
DJANGO_SETTINGS_MODULE=pybittrack.settings \
uvicorn pybittrack.asgi:application --host 0.0.0.0 --port 6969
Remove
--no-access-logduring development if you want to see requests in the terminal. Always keep it in production (see note in the Nginx section).
Production — systemd service
Create /etc/systemd/system/pybittrack.service:
[Unit]
Description=PyBitTrack BitTorrent Tracker
After=network.target redis.service
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/opt/pybittrack
Environment="DJANGO_SETTINGS_MODULE=pybittrack.settings"
ExecStart=/opt/pybittrack/venv/bin/uvicorn \
pybittrack.asgi:application \
--host 127.0.0.1 \
--port 6969 \
--workers 4 \
--loop uvloop \
--no-access-log
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Adjust WorkingDirectory and ExecStart to your actual install path, then:
sudo systemctl daemon-reload
sudo systemctl enable --now pybittrack
sudo systemctl status pybittrack
Workers:
--workers 4is a good starting point. Use2 ×ばつ CPU coresfor announce-heavy traffic.
Nginx
Why disable access logs? A busy tracker receives thousands of
/announceand/scraperequests per minute. Nginx access logs would grow at several GB per day and thrash the disk. Keep error logs — disable only access logs.
HTTP only (port 80/8080)
server {
listen 80;
server_name your-domain.tld;
# Suppress access logs — announce/scrape volume would flood disk
access_log off;
location / {
proxy_pass http://127.0.0.1:6969;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
}
}
HTTPS (recommended)
Install Certbot, obtain a certificate, then:
server {
listen 80;
server_name your-domain.tld;
access_log off;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name your-domain.tld;
ssl_certificate /etc/letsencrypt/live/your-domain.tld/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.tld/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Suppress access logs — announce/scrape volume would flood disk
access_log off;
# Optional: restrict admin to specific IP(s)
# location /admin/ {
# allow 203.0.113.10;
# deny all;
# proxy_pass http://127.0.0.1:6969;
# }
location / {
proxy_pass http://127.0.0.1:6969;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 30s;
# Required for .torrent file uploads in the admin
client_max_body_size 10M;
}
}
Reload Nginx:
sudo nginx -t && sudo systemctl reload nginx
Redis
Redis must be running before starting the tracker.
# Install (Debian/Ubuntu)
sudo apt install redis-server
# Recommended: set a password in /etc/redis/redis.conf
# requirepass your_redis_password
# Then update config.json → redis.password accordingly
sudo systemctl enable --now redis
redis-cli ping # should return PONG
Logging
A tracker under normal load receives tens of thousands of requests per hour. All three layers must have logging disabled or minimised, otherwise disk I/O from log writes becomes a bottleneck and storage fills up within hours.
| Layer | What to do | Where |
|---|---|---|
| Nginx | access_log off; in every server block |
/etc/nginx/sites-available/pybittrack |
| uvicorn | --no-access-log flag |
systemd unit ExecStart |
| Django | "logging": {"level": "ERROR"} in config.json |
config.json |
Each layer logs only actual errors. Normal announces and scrapes produce no log output.
To verify nothing is accumulating after deployment:
# Nginx — should stay at 0 bytes
ls -lh /var/log/nginx/access.log
# uvicorn/systemd — only errors, no per-request lines
sudo journalctl -u pybittrack -n 50 --no-pager
Admin interface
Visit https://your-domain/admin/ and log in with the password set in config.json → admin.password.
Features:
- Global stats (total torrents, active torrents, seeders, leechers)
- Search by info hash (40-char hex, base32, or base64url)
- Search by magnet link
- Search by IP address
- Upload a
.torrentfile to inspect its peers
The admin interface requires
announce_interval ×ばつ announce_timeout_factorseconds of announce traffic before peers appear. Stats refresh every 15 minutes via a background thread.
Running the tests
source venv/bin/activate
DJANGO_SETTINGS_MODULE=pybittrack.settings python -m pytest tests/test_tracker.py -v
Tests use Redis DB 3 (isolated). Redis must be reachable.
License
AGPL-3.0 — see LICENSE.
Torrent ≠ Piracy. This tracker does not host or distribute any content.