Skip to content

florianjs/opentracker

Repository files navigation

🌐 OpenTracker

A modern, high-performance private BitTorrent tracker

Built with Nuxt 4 • PostgreSQL • Redis

Node.js Nuxt TypeScript License

FeaturesQuick StartSecurityDocumentation


✨ Features

Privacy & Authentication Performance
🔐 Zero-Knowledge Authentication ⚡ Redis-powered sub-ms peer lookups
🛡️ Proof of Work anti-abuse 🗄️ PostgreSQL with full-text search
🔒 Private torrents (DHT/PEX disabled) 📡 HTTP & WebSocket announce support
📊 Ratio tracking & enforcement 🔄 Optimized for high concurrency
Security Emergency
🚫 Distributed rate limiting 🚨 Panic Mode — Instant database encryption
🔥 Auto IP blacklisting 🔑 AES-256-GCM protected data
🛡️ SQL/XSS attack detection ♻️ Full restoration with master password
🔐 SHA-256 hashed IPs 💀 Unrecoverable without password

🔐 Security Architecture

Zero-Knowledge Authentication (ZKE)

OpenTracker uses a Zero-Knowledge authentication system: the server never sees or stores your password. All cryptographic operations happen client-side.

┌─────────────────────────────────────────────────────────────────────┐
│                        REGISTRATION FLOW                            │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────┐                              ┌─────────────────┐  │
│  │   CLIENT    │                              │     SERVER      │  │
│  └──────┬──────┘                              └────────┬────────┘  │
│         │                                              │           │
│         │ 1. Solve PoW Challenge (anti-spam)           │           │
│         │ ◄────────────────────────────────────────────┤           │
│         │                                              │           │
│         │ 2. Generate random salt (32 bytes)           │           │
│         │ 3. Derive key = PBKDF2(password, salt)       │           │
│         │ 4. Compute verifier = SHA256(key)            │           │
│         │                                              │           │
│         │ 5. Send {username, salt, verifier} ─────────►│           │
│         │    ⚠️ Password NEVER leaves client           │           │
│         │                                              │           │
│         │                              6. Store salt + │           │
│         │                                 verifier     │           │
│         │                              7. Create session           │
│         │ ◄──────────────────────────────── 8. OK ─────┤           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                          LOGIN FLOW                                 │
├─────────────────────────────────────────────────────────────────────┤
│                                                                     │
│  ┌─────────────┐                              ┌─────────────────┐  │
│  │   CLIENT    │                              │     SERVER      │  │
│  └──────┬──────┘                              └────────┬────────┘  │
│         │                                              │           │
│         │ 1. Request challenge ───────────────────────►│           │
│         │                                              │           │
│         │ ◄──────── 2. Return {salt, challenge} ───────┤           │
│         │                                              │           │
│         │ 3. Derive key = PBKDF2(password, salt)       │           │
│         │ 4. Compute verifier = SHA256(key)            │           │
│         │ 5. Generate proof = SHA256(verifier+challenge)           │
│         │                                              │           │
│         │ 6. Send {username, proof, challenge} ───────►│           │
│         │    ⚠️ Password NEVER leaves client           │           │
│         │                                              │           │
│         │                       7. Compute expected =  │           │
│         │                          SHA256(storedVerifier+challenge)│
│         │                       8. Verify proof == expected        │
│         │ ◄──────────────────────────────── 9. Session ┤           │
│                                                                     │
└─────────────────────────────────────────────────────────────────────┘

Key Properties:

  • 🔒 Password never transmitted — Only cryptographic proofs
  • 🛡️ PBKDF2 with 100k iterations — Brute-force resistant
  • 🎲 Unique challenge per login — Prevents replay attacks
  • Proof of Work — Stops automated registration attacks

🚨 Panic Mode (Emergency Encryption)

The Panic Button allows administrators to instantly encrypt all sensitive data in an emergency. Once activated, all torrent files become unusable and user data is unreadable.

┌───────────────────────────────────────────────────────────────────┐
│                       NORMAL STATE                                │
│  • Torrents downloadable                                          │
│  • User data readable                                             │
│  • Posts & comments visible                                       │
└───────────────────────────────────────────────────────────────────┘
                              │
                    🔴 PANIC ACTIVATED
                              │
                              ▼
┌───────────────────────────────────────────────────────────────────┐
│                      ENCRYPTED STATE                              │
│  • .torrent files → AES-256-GCM encrypted (unusable)              │
│  • Torrent names  → [ENCRYPTED]                                   │
│  • Torrent sizes  → 0                                             │
│  • User credentials → Encrypted                                   │
│  • Forum posts    → Encrypted                                     │
└───────────────────────────────────────────────────────────────────┘
                              │
                    🔑 RESTORE (with password)
                              │
                              ▼
┌───────────────────────────────────────────────────────────────────┐
│                       RESTORED STATE                              │
│  All data restored to original state                              │
└───────────────────────────────────────────────────────────────────┘

How it works:

  1. First admin sets a Panic Password during registration (min. 12 chars)
  2. Panic password is hashed and stored securely (never in plaintext)
  3. Activation: Admin → Settings → Panic → Type ENCRYPT_ALL_DATA
  4. Restoration: Enter the original Panic Password

Encryption details:

Component Algorithm
Key Derivation scrypt (32 bytes)
Encryption AES-256-GCM
IV 16 bytes random (per session)

⚠️ WARNING: Without the Panic Password, encrypted data is permanently lost. There is no recovery mechanism.


🚀 Quick Start

Prerequisites

  • Node.js 20+ • Docker & Docker Compose • npm

Option 1: Automated Installation (Recommended)

Best for production deployments. Handles dependencies, secrets, SSL, and systemd automatically.

# Download and run the installer
curl -fsSL https://raw.githubusercontent.com/florianjs/opentracker/main/scripts/install.sh -o install.sh
chmod +x install.sh
sudo ./install.sh

The installer will:

  • ✅ Install Docker and dependencies
  • ✅ Generate cryptographic secrets
  • ✅ Configure firewall rules
  • ✅ Set up TLS/SSL with Let's Encrypt
  • ✅ Create systemd service for auto-restart
  • ✅ Configure PostgreSQL, Redis, Caddy, and monitoring

Option 2: Development with Docker

Databases are only exposed to the container network for security.

# Clone repository
git clone https://github.com/florianjs/opentracker.git && cd opentracker
cp .env.example .env

# Start all services (app + postgres + redis)
docker compose up -d

# View logs
docker compose logs -f app

Open http://localhost:3000


🔒 Security

⚠️ For production, always use the install script to ensure proper secret generation and security configuration.

Key Security Features

Layer Protection
Authentication ZKE, PoW anti-abuse, session encryption, CSRF protection
Database SCRAM-SHA-256 auth, TLS, prepared statements, pool limits
Redis Password auth, command restrictions, memory limits
Network Rate limiting, auto IP bans, attack pattern detection
Privacy SHA-256 hashed IPs, no raw IP persistence, minimal logging

Rate Limits

Endpoint Limit Ban on Abuse
Public API 100/min 100+ req/10s → auto-block
Mutations 10/min Progressive penalties
Auth 5/5min IP blacklisted after violations
Tracker 200/min Distributed sliding window

Production Security Checklist

Use install.sh — it handles security automatically:

  • ✅ Generates cryptographic secrets (32-64 chars)
  • ✅ Configures TLS for all connections
  • ✅ Sets up Caddy reverse proxy with HTTPS
  • ✅ Configures firewall (ports 80, 443 only)
  • ✅ Network isolation (databases not exposed)

Manual steps after install:

  • Set up automated PostgreSQL backups

🏗️ Tech Stack

Layer Technology Purpose
Frontend Nuxt 3, Vue 3, Tailwind CSS SSR, Composition API
Backend Nitro Server Engine API routes, middleware
Database PostgreSQL 16 + Drizzle ORM Data persistence, full-text search
Cache Redis 7 Peer lists, sessions, rate limiting
P2P bittorrent-tracker HTTP & WebSocket announces
Crypto Web Crypto API, scrypt, AES-256-GCM ZKE auth, Panic encryption

🐳 Docker Commands

docker compose up -d              # Start services
docker compose down               # Stop services
docker compose logs -f            # View logs
docker compose down -v            # Stop + remove volumes

Health Checks

docker exec opentracker-db pg_isready           # PostgreSQL
docker exec opentracker-redis redis-cli ping    # Redis

🧪 Development

npm run dev              # Start dev server (HMR)
npm run build            # Production build
npx drizzle-kit push     # Push schema changes
npx drizzle-kit studio   # Database GUI

🤝 Contributing

  1. Fork the repository
  2. Create feature branch (git checkout -b feature/amazing)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing)
  5. Open a Pull Request

📄 License

MIT License — see LICENSE for details.


Built with ❤️ for the P2P community

⬆ Back to top

About

Run your own private tracker in less than 5min

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published