opentracker – An open and free bittorrent tracker
Overview
opentracker is an open and free bittorrent tracker project. It aims for minimal resource usage and is intended to run at your wlan router. Currently it is deployed as an open and free tracker instance. Read our free and open tracker blog and announce your torrents there (but do not hesitate to setup your own free trackers!).
Version History
Use git clone git://erdgeist.org/opentracker to check it out. An opentracker gitweb is available.
-
V2.2.1 opentracker-2.2.1.tar.bz2 (2026-11-10
be4318e50affa65000e80963a6d05245d32cd4b73875df19aeec2aeee81c8fc7)Fix man pages in preparation of a debian port.
Take last potentially blocking syscall out of the locked region.
-
V2.2.0 opentracker-2.2.0.tar.bz2 (2026-11-08
a6de9dd09ad69a721be2e50ae4d0c56f4909c6b58738180bd754d0ecd701a0e7)This release aggressively addresses memory consumption and fixes audit findings.
A torrent now only keeps one peer list covering both address families, created only when its first peer arrives. For a long tail of idle torrents, this roughly halves the fixed memory per torrent.
The per-torrent peer count is not cached anymore, the last-seen time and download count moved onto the torrent, and the remaining counters shrank to 32 bit, so an empty torrent costs little more than its hash.
A torrent kept only for its download count can be expired ahead of the usual day with the new tracker.empty_torrent_timeout option, for operators who would rather have the memory back than to keep precise stats.
Retire the s24s busy-network report. A /24 stopped identifying abusers years ago, the v6 variant never worked, and the full-table sweep it cost was not worth keeping.
opentracker now refuses to start when an essential worker thread cannot be created, instead of running on without a cleaner or an accesslist reader.
Fix a full scrape that carried on with a gzip stream whose initialization had failed.
Harden config file parsing: cast bytes before handing them to isspace, and bound a listen-option token read that could step past its string.
Several smaller fixes: a work buffer leaked when a worker fails to start, an unchecked error-counter index, a torrent-count underflow at shutdown, and a few format-string corrections.
-
V2.1.1 opentracker-2.1.1.tar.bz2 (2026-11-06
93cacaefe404f30d28a2b8f8526c7a99da344d7d35f47296fb6ac33f92d97730)Closed several OOB read accesses in the request path.
Fix a state dump export/import asymmetric introduced in 2.1.0.
Fix a livesync overrun caused by a too optimistic watermark check.
Fix a UAF in the keep-alive case where an inline handler closes a fd early.
opentracker now builds with a complete set of stack protector, pic, fortified libc calls.
On startup, opentracker now drops supplementary groups, too.
Several smaller bug fixes found by extensive fuzzing and augmenting the test suite.
Shout-out to TryHackX (tracker.tryhackx.org) for extensive alpha and stress testing. Their reports and patches were a valuable basis for many changes beginning in v2.0.0.
-
V2.1.0 opentracker-2.1.0.tar.bz2 (2026-11-05
0d65ad97e45171b434e6653bbb0775f9732eb7a31851a635833c033cc55096ef)Implement a guard that needs blessing ip ranges before they can retrieve fullscrapes, using the
WANT_RESTRICT_FULLSCRAPEfeature flag.Make opentracker robust against time skews, taking all clocks off the wall.
Accesslists are now read before any consumers consult them, so no more spurious rejections or errornous announces.
Fix one error handler that would free memory from an uninitialized pointer.
Announcing to blacklisted torrents via udp now yields a properly formatted reply that carries a timeout. The error we sent before couldn't transport one.
-
V2.0.0 opentracker-2.0.0.tar.bz2 (2026-11-03
fbac9eeaeb6ae81a24f89390cd09839e6e477f13b2bb9ac176e7b786003a750f)Dedicated to Felix von Leitner — see DEDICATION.
opentracker no longer depends on libowfat. In fact, it compiles and runs on vanilla FreeBSD and most off-the-shelf linux installations. The only library a default build links is zlib, for compressed full scrapes.
UDP connection ids never expired. The key that was meant to rotate them hourly was mixed into a buffer the encryption then did not use. This led to the id being a plain function of the source address, staying valid for as long as the tracker ran, when the protocol intended it to be short lived. Fourteen years of it. Thanks to Tracy Rogers for the report.
Announces are served by worker threads. UDP workers take a socket each where the kernel will spread datagrams over a group, TCP workers answer a connection on the thread that accepted it. Both counts are set in the config file and both default to one.
Where the kernel offers it, opentracker waits for a request to arrive before accepting the connection, using
TCP_DEFER_ACCEPTon Linux and thedatareadyaccept filter on FreeBSD.HTTP keep alive works again.
Statistics are counted per thread and summed when asked for, so announces no longer contend over a shared tally.
opentracker no longer reports its version or its tracker id over http. Run
opentracker -vfor the version, the event mechanism in use and the feature flags the binary was built with.Live sync now picks its own multicast group with
livesync.cluster.group, and sends to the port it listens on. Before, it would use the default one by mistake. A binary built with it starts without a cluster configured.A config file line that names a listen address or a multicast group and gets it wrong now stops opentracker rather than quietly leaving it on a default.
The batch syncer and the live network logging are gone, both long superseded. The proxy did not survive the move to dual stack and is out of service until it is ported.
Several security fixes a user cannot see but should know about. A use after free when a connection expired while its reply was queued, an out of bounds read in the accesslist parser, and a buffer overrun when terminating a request.
make installobeysPREFIXandDESTDIRand installs the man pages, so a port or package needs no patching.The tree now carries unit tests, black box tests that drive the binary over the wire, and runs of both under the address, undefined behaviour and thread sanitizers.
make check-allruns the lot.
-
V1.0 opentracker-1.0.tar.bz2 (2025-01-01)
After 18 years of development, a v1.0 was released.
It requires libowfat version >= 0.34.
-
Since April 2024, opentracker supports IPv4 and IPv6 peers in a single tracker.
With TCP announces, both IPv4 and IPv6 peers will now be returned.
Proxy addresses can be networks in CIDR notation now.
For trackers with many insertions and deletions in black/white lists, dynamic access lists were introduced, with fifo allowing to add or delete torrents.
Full scrapes and other data intense queries are now delivered using chunked http transfers, allowing generating them on the fly, saving a lot of memory. Also they are compressed by default now.
UDP replies on the IPv6 side are now limited to amounts of peers that will not cause fragmentation on most routers.
Better prevent expensive stats operations to be triggered by accident. Some torrents included a stats URL as announce URL.
Build instructions
opentracker builds with a C compiler and make, and nothing else:
git clone git://erdgeist.org/opentracker cd opentracker make
That should leave you with an executable called opentracker and one debug version opentracker.debug. make install puts the binary and the two man pages under PREFIX, which defaults to /usr/local.
Some variables in opentracker's Makefile control features and behaviour of opentracker. Here they are:
-DWANT_V4_ONLYmakes opentracker bind an IPv4 address when no address was given.-
opentracker can deliver gzip compressed full scrapes. This is on by default, through
include Mk/gzip.mk, which is the one line that also links zlib.To make opentracker compress even where the client did not ask, uncomment
-DWANT_COMPRESSION_GZIP_ALWAYSinMk/gzip.mk. The same file has a zstd counterpart inMk/zstd.mk, which is off by default and would add a dependency on libzstd.
-
Normally opentracker tracks any torrent announced to it. You can change that behaviour by enabling ONE of
-DWANT_ACCESSLIST_BLACKor-DWANT_ACCESSLIST_WHITE. Note, that you have to provide a whitelist file in order to make opentracker do anything in the latter case. More in the closed mode section below.-DWANT_DYNAMIC_ACCESSLISTadds two fifos through which torrents can be added to or removed from that list while the tracker runs.
opentracker can run in a cluster. Enable this behaviour by enabling
-DWANT_SYNC_LIVE. A tracker built this way runs with or without a cluster configured; configure one in the config file to join it.Some statistics opentracker can provide are sensitive. You can restrict access to these statistics by enabling
-DWANT_RESTRICT_STATS. See section statistics for more details.Fullscrapes is bittorrent's way to query a tracker for all tracked torrents. Since it's in the standard, it is enabled by default. Disable it by commenting out
-DWANT_FULLSCRAPE.By default opentracker will only allow the connecting endpoint's IP address to be announced. Bittorrent standard allows clients to provide an IP address in its query string. You can make opentracker use this IP address by enabling
-DWANT_IP_FROM_QUERY_STRING, or read it from a reverse proxy's header with-DWANT_IP_FROM_PROXY.-DWANT_KEEPALIVElets a client reuse a tcp connection for its next request.-DOT_BUCKET_COUNT_BITSsets how many buckets the torrent table is split into, as a power of two, 10 by default. Raising it makes inserting a new torrent cheaper and costs memory, which is worth it for a tracker carrying millions of torrents and not for one carrying thousands.Smaller switches exist for syslog output, counting numwants, rate limiting full scrapes and spotting woodpeckers. The Makefile lists them all with a line of explanation each.
Currently there is some packages for some linux distributions and OpenBSD around, but some of them patch Makefile and default config to make opentracker closed by default. I explicitly don't endorse those packages and will not give support for problems stemming from these missconfigurations.
Invocation
opentracker can be run by just typing ./opentracker. This will make opentracker bind one dual stack socket on port 6969, reachable over IPv4 and IPv6 on every interface, and happily serve all torrents presented to it. If ran as root, opentracker will immediately chroot to . (or any directory given with the -d option) and drop all privileges after binding to whatever tcp or udp ports it is requested.
When options were few, opentracker used to accept all of them from command line. While this still is possible for most options, using them is quite unhandy: an example invocation would look like ./opentracker -i 23.23.23.7 -p 80 -P 80 -p 6969 -i 23.23.23.8 -p 80 -r http://www.mytorrentsite.com/ -d /usr/local/etc/opentracker -w mytorrents.list -A 127.0.0.1.
opentracker now uses a config file that you can provide with the -f switch.
Config file
opentracker's config file is very straight forward and a very well documented example config can be found in the file opentracker.conf.sample. There are man pages for both the binary and the config file format, opentracker(1) and opentracker.conf(5).
Closed mode
While personally I like my tracker to be open, I can see that there's people that want to control what torrents to track – or not to track. If you've compiled opentracker with one of the accesslist-options (see Build instructions above), you can control which torrents are tracked by providing a file that contains a list of human readable info_hashes. An example whitelist file would look like
0123456789abcdef0123456789abcdef01234567 890123456789abcdef0123456789abcdef012345
To make opentracker reload it's white/blacklist, send a SIGHUP unix signal.
Statistics
Given its very network centric approach, talking to opentracker via http comes very naturally. Besides the /announce and /scrape paths, there is a third path you can access the tracker by: /stats. This request takes parameters, for a quick overview just inquire /stats?mode=everything.
Statistics have grown over time and are currently not very tidied up. Most modes were written to dump legacy-SNMP-style blocks that can easily be monitored by MRTG. These modes are: peer, conn, scrp, udp4, tcp4, torr, fscr, completed, syncs. I'm not going to explain these here.
The statedump mode dumps non-recreatable states of the tracker so you can later reconstruct an opentracker session with the -l option. This is beta and wildly undocumented.
Which build you are running is not something the tracker tells the network. Ask the binary instead: opentracker -v reports the version, the event mechanism it will use and the feature flags it was built with.
Philosophy
A torrent tracker basically is an http server that collects all clients ip addresses into pools sorted by one of the request strings parameters and answers all other clients that specified this exact same parameter a list of all other recent clients. All technologies to implement this are around for more than twenty years. Still most implementations suck performancewise.
opentracker talks to the kernel directly, through epoll, kqueue or poll, whichever the platform offers, and keeps everything it knows in memory. It can easily serve multiple thousands of requests on a standard plastic WLAN-router, limited only by your kernels capabilities ;)
One important design decision of opentracker was to not store any data persistently. This reduces wear&tear on hard disks and eliminates problems with corrupt databases.
Thanks
A project like this one is impossible without lots of help from friends. It is powered by beer, much energy and love, batches of bug reports and support on the operating system integration side by denis, taklamakan, cryx, supergrobi and – whose libowfat carried opentracker for its first eighteen years – Fefe. Thanks are also due to Hannes for helping me out with designing internal data representation.
License
opentracker is considered beer ware.