Glue Logic LLC logo

BitTorrent is a peer-to-peer (P2P) protocol intended to speed up retrieval (downloading) of large offerings. More information can be found in the BitTorrent FAQ and Guide written by Brian Dessent.

To use BitTorrent, you need the software (free and open source) written by Bram Cohen. It does not contain spy or adware. The Installing BitTorrent section of the FAQ lists other clients.

To serve torrents, you need a BitTorrent tracker. There are some public trackers that you might use instead. Alternatively, you can run your own tracker by using Bram's software or by using the BitTorrent::TrackerCGI that runs

BitTorrent::TrackerCGI is Free and Open Source.

It is the software behind

BitTorrent::TrackerCGI is written in Perl and can run as a mod_perl handler (fast) or as a CGI program (slow). It is licensed under the GNU Public License (GPL) and requires a web server, a standard Perl installation, a MySQL database account, and the additional Perl modules DBI, DBD::mysql, and Digest::SHA1. The extra Perl modules are all available from CPAN if your distributor does not already provide these as extra packages (e.g. they are RedHat RPMs with RedHat 9). Apache::DBI is recommended, but not required, if running under mod_perl.


  • Download (right-click and choose "Save Link Target As...")
  • Edit and fill in the required configuration information at the top, which includes the base URL for the torrents, the filesystem path to the torrents, and the MySQL database account information. If you installed any of the required Perl modules in a non-standard location, add a 'use lib' line containing the install path. If running as a CGI with tracker.cgi in a separate cgi-bin, make sure that the tracker URL is also specified correctly.
  • Create the torrent directory specified above and create two files for use by the tracker in writing out statistics and RSS feed.
      mkdir path/to/torrents
      cd path/to/torrents

    If not running under suEXEC or CGIwrap, also do  chmod a+w bt_{stats,rss}.inc (You should NOT make the directory world-writable, only these two files, and only if you are not running suEXEC or CGIwrap or the like.)
  • In a shell, type   perl -Tw refresh  to set up the database tables
    (If you do not have shell access and are running as a CGI, skip this for now)

  • If running as a mod_perl handler
    • Tell Apache about it. This might be as little as placing the script in a location that runs scripts with Apache::Registry*. However, to make it run as quickly as possibly, emulate some of the configuration, which is included for reference at the bottom of this page.
  • If running as a CGI
    • Rename to tracker.cgi and place it in your cgi-bin
    • Make tracker.cgi executable (chmod a+x tracker.cgi).
    • If you do not have shell access, you can attempt to perform the install with a URL. Use the URL you configured in and add a query string, something like:  <>  (This will only work if the admin has not set "CGICommandArgs off" in the Apache configuration, but most haven't, even though they should. If the admin has disabled this, you'll need to set up the database tables manually. See the code in for table details.)

  • Tell the web server the MIME type of .torrent files by adding the following to httpd.conf or to an appropriate .htaccess file.
      AddType application/x-bittorrent .torrent
  • Create your own custom index.shtml page that uses a server-side include to include the HTML table output placed in Create your own rss.xml file and include via server-side include. For examples of finished products, view the source of and rss.xml
  • (Optional) Run  perl refresh every half hour or so via a cron job. On low-traffic sites, this will keep the status page up to date when there are no active torrents. Sample crontab entry:
    */30 * * * * /usr/bin/perl -Tw /web/p/e/perl/lib/BitTorrent/ refresh
  • (Optional) Run  perl force-refresh whenever you want to force the refresh to run. It may temporarily cause the statistics to be skewed, but will immediately pick up, or delete, changes to torrents in the torrent directory hierarchy. snippet (not complete config) from httpd.conf:

HostnameLookups off
UseCanonicalName on
KeepAlive Off
CGICommandArgs off

LoadModule config_log_module  modules/
LoadModule mime_module        modules/
LoadModule includes_module    modules/
LoadModule dir_module         modules/
LoadModule access_module      modules/
LoadModule expires_module     modules/
LoadModule perl_module        modules/
LoadModule gzip_module        modules/

#  Reconstruction of the complete module list from all available modules
#  (static and shared ones) to achieve correct module execution order.
AddModule mod_log_config.c
AddModule mod_mime.c
AddModule mod_include.c
AddModule mod_dir.c
AddModule mod_access.c
AddModule mod_expires.c
AddModule mod_so.c
AddModule mod_perl.c
AddModule mod_gzip.c

TypesConfig /etc/mime.types

DirectoryIndex index.html

<Directory />
    AllowOverride None
    Options FollowSymLinks
    deny from all
<Directory /web/?/?/*/*>
    allow from all

## mod_gzip
<IfModule mod_gzip.c>
    ## Written for mod_gzip v -- code()
    ## Aggressive.  Compress everything except images.

    ## DISable mod_gzip
    mod_gzip_on no
    ## intercept chunked encoding type (to allow for possible compression)
    mod_gzip_dechunk yes
    ## use this dir for creating work files
    mod_gzip_temp_dir /tmp
    ## do not preserve work files (only enable for debugging)
    mod_gzip_keep_workfiles no
    ## max file size to compress in memory before using work file
    ## (default, and max allowed)
    mod_gzip_maximum_inmem_size 60000
    ## min file size to compress (default)
    mod_gzip_minimum_file_size 300
    ## max file size to compress (2 MB generous, but a sanity check)
    mod_gzip_maximum_file_size 2000000
    ## check for already-compressed files (*.gz)
    mod_gzip_can_negotiate No
    ## include header size (always uncompressed) in Apache logs
    mod_gzip_add_header_count Yes

    ## By default mod_gzip compresses only things included AND not excluded.

    ## include everything (that is not excluded below)
    mod_gzip_item_include uri .
    #mod_gzip_item_include mime .
    #mod_gzip_item_include handler perl-script

    ## exclude images/*
    ## (commented out more general to use 'file' and avoid sending Vary header)
    #mod_gzip_item_exclude mime ^image/
    mod_gzip_item_exclude file \.gif$


## mod_perl

PerlRequire /web/p/e/perl/lib/
PerlFixupHandler Apache::SizeLimit
PerlFreshRestart on
PerlSetupEnv off
PerlSendHeader off
PerlTaintCheck on
PerlWarn on
# Turn PerlWarn on for debugging and whenever a new module is added

## Virtual Hosts

NameVirtualHost *

    <VirtualHost *>
	PerlTransHandler 'sub { return shift->uri() =~ m|^/tracker| \
				  ? Apache::OK \
				  : Apache::DECLINED; }'
	<Location /tracker>
	    SetHandler perl-script
	    PerlHandler BitTorrent::TrackerCGI
	DocumentRoot /web/p/e/perl/
	<Directory /web/p/e/perl/>
	    Options +IncludesNoEXEC
	DirectoryIndex index.shtml index.html
	AddType application/x-bittorrent .torrent
	AddType text/html .shtml
	AddType text/xml .xml
	AddHandler server-parsed .shtml .xml

	ExpiresActive on
	ExpiresDefault A900
	ExpiresByType application/x-bittorrent A3600

	## enable mod_gzip
	mod_gzip_on yes
    </VirtualHost> (sample):

#!/usr/bin/perl -Tw

## gs()

## Be very careful with what is called from this script.  At Apache startup,
## it will be included into the Apache mod_perl server.  Anything run at
## that point is run under user root.  (You should only be including libraries
## here.)  Therefore, do not include here any code to which a non-root and 
## non-admin user has write privileges.

use strict;

## ----------
## ----------

## This section is similar in scope to Apache::Debug.
## Delivers a stack backtrace to the error log when perl code dies.

## Allocate 64K as an emergency memory pool for use in out of memory situation
$^M = 0x00 x 65536;

## Little trick to initialize this routine here so that in the case of OOM,
## compiling this routine doesn't eat memory from the emergency memory pool $^M
use CGI::Carp ();
eval { CGI::Carp::confess('init') };

## Importing CGI::Carp sets $main::SIG{__DIE__} = \&CGI::Carp::die;
## Override that to additionally give a stack backtrace
$main::SIG{__DIE__} = \&CGI::Carp::confess;

## ----------
## ----------

## Preload often-used modules into the main httpd server 
## so that they are shared between all httpd children.

## Need these two in specific order to avoid segv in mod_perl 1.2.6 + Perl 5.6.1
use DynaLoader ();
use XSLoader ();

use Exporter ();
use POSIX ();
use Socket ();
use Symbol ();

use Apache ();

# Make sure Apache children do not grow too large (memory usage)
# Set generous memory size limit and do not check too often
use Apache::SizeLimit ();
$Apache::SizeLimit::MAX_PROCESS_SIZE       = 16384;
$Apache::SizeLimit::CHECK_EVERY_N_REQUESTS = 16;
$Apache::SizeLimit::MIN_SHARE_SIZE         = 2048;
$Apache::SizeLimit::MAX_UNSHARED_SIZE      = 8192;

## Load a Perl interface to the Apache API
## (unused)
#use Apache::RegistryBB ();

## This is SO chunky.  It adds > 2 MB to Apache children!
## This is the recommended way to call v2.46 and up for use in mod_perl.
## (unused)
#use CGI qw(-compile :all);

## ----------
## ----------

## install database driver and preload database modules
## adds about 3 MB to memory usage, but it will be shared.
## However, these drivers seem to leak on USR1 signal,
## so perform a shutdown/restart when updating the server
use Apache::DBI ();  ## (MUST be before
use DBI ();
use DBD::mysql ();
	PrintError => 1,	# warn() on errors
	RaiseError => 0,	# do not die on error
	AutoCommit => 1		# commit executes immediately

## ----------
## ----------

## Local libraries

## Add local library directory to Perl's @INC library search path
use lib '/web/p/e/perl/lib';

## BitTorrent tracker
use BitTorrent::TrackerCGI ();

# The __END__ and __DATA__ tags may NOT be used in any Apache::Registry 
# scripts, but are allowed in server configuration files.

Home    |    Projects    |    Contact Us
© 2004 Glue Logic LLC