Setting Up An Anonymous Headless BittTorrent Downloader On FreeBSD

I recently moved countries, and being unfamiliar with ISP attitudes towards commonly used download protocols, decided to upgrade my home FreeBSD server to allow me to anonymously use BitTorrent.

For those of you instantly screaming “pirate!”, be aware that BitTorrent is a protocol that is extremely practical for fast downloads of large files.  In recent weeks, I’ve used it for

– an open source operating system install DVD (5+ GB)

– a collection of Left 4 Dead 2 community maps (10+ GB)

– a large patch collection for software I own (god-knows-how-many-GB)

In addition to speeding up your own downloads, bittorrent takes load off the provider’s systems, by distributing downloads, lets you schedule when and how fast you download, and allows you to provide out-of-date or difficult to find files to others.  So all the hysteria aside, saying “bittorrent = piracy” is about the same as claiming “the Internet = child pornography” because people use it for that.  But you already knew that.

It’s not rocket science, but took me a bit of tinkering to figure out.  This article assumes that you have a basic idea of what you are doing.

I. Operating system installation – FreeBSD

So, we start with a FreeBSD system.  I recently upgraded mine to 9.0-Release, the latest production version at time of writing.  Get it here.  Instructions on installing from scratch or updating from source are linked from the page.  I like FreeBSD because in my view it’s the most UNIX-like of the free *NIX systems, and I learned on BSD-related OS, so there.  People who start operating system religious wars are not worth listening to – so use whatever works for you.

If you go with FreeBSD, this assumes that you have an updated system source tree and have done a buildworld / installworld.  If there is any confusion on this, handbook, handbook, handbook.

Please note that in 9.0, cvsup is deprecated, if you’re using this to update your sources – use csup and make your life easier.

Make sure your ports tree is also up to date.  Running portmaster -a or something similar can be a big help.

II. Building the kernel

You’ll need to add a few devices to your kernel configuration file in /usr/src/sys/i386/conf/.

I have the following:

options         IPFIREWALL
options         IPFIREWALL_VERBOSE (more on these later)
device          tun             # Packet tunnel. (just make sure it’s present and uncommented)

Build your kernel:

cd /usr/src && make KERNCONF=<yourkernelfilename> buildkernel && make KERNCONF=<yourkernelfilename> installkernel

Reboot.  If you need help building a new kernel, make sure you’ve read the FreeBSD handbook first.

III. Anonymity – OpenVPN

Because of the frequent association of BitTorrent with piracy, I’d rather not have to deal with nosy providers.  After all, you close the door when you’re on the toilet, regardless of what you’re doing in there, right?

There are two major options for this – use a seedbox, or a virtual private network (VPN) to a non-busybody country via a provider that supposedly does not keep any log files.  Both have advantages and disadvantages – the seedbox tends to cost a bit more, and only uses your bandwidth when you’re actually downloading files, while a VPN lets you use it for all kinds of Internet traffic, and lets you have the downloaded files directly at hand once they’re finished downloading.

I’m using Mullvad – they’re cheap, fast, have a good reputation, and seem to take users’ privacy seriously.

III.a. Setting up OpenVPN

First, install OpenVPN from ports.  It’s a TLS-based VPN.  Mullvad supports MacOS, Windows, Linux, and Android natively, but allows you connect via OpenVPN if you configure it yourself.

cd /usr/ports/net/security/openvpn && make install

Next, add the following lines to /etc/rc.conf to start the VPN at boot.

# OpenVPN

III.b. Setting up Mullvad

Sign up for Mullvad (or your own provider) here -> and click on “create a new account”.  You won’t give them any money just yet.

Download the .zip file with your customer ID (this is important as it identifies you for billing and whether you’re allowed to connect).  You’ll want to extract the following files into a directory called /etc/openvpn:

behemoth# ls -l /etc/openvpn
-rwxr-xr-x  1 root  wheel  6296 Mar  7 20:05 ca.crt
-rwxr-xr-x  1 root  wheel  6296 Mar  7 20:05
-rwxr-xr-x  1 root  wheel  1143 Mar  9 12:05 mullvad.conf (this was originally called mullvad_linux.conf but I renamed it for simplicity’s sake)
-rwxr-xr-x  1 root  wheel  4905 Mar  7 20:05 mullvad.crt
-rw——-  1 root  wheel  1675 Mar  7 20:05 mullvad.key (make sure the permissions on this are correct)

Here’s my mullvad.conf, minus blank lines and comments:

dev tun
proto udp
remote 1194
resolv-retry infinite
verb 3
remote-cert-tls server
ping-exit 60
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
ping 10
cert mullvad.crt
key mullvad.key

III.c. Setting up resolvconf

This was a bit of a pain to figure out.  Mullvad requires the resolvconf package, or an equivalent, to allow it to manipulate your /etc/resolv.conf (nameserver configuration) for when the VPN goes up and down – you want all of your DNS queries to go via Mullvad while your VPN is up.

I used the openresolv package for this:

cd /usr/ports/dns/openresolv && make install

 You will then need to make sure you have the update-resolv-conf script handy – I put it in /etc/openvpn.  Please note that this may not be the tidiest way of doing things, but I spent so long tracking down how openresolv did things, that as soon as I found a way to make it just work, halleluja.  There are a few versions out there – here’s the one that works for me:

# Parses DHCP options from OpenVPN to update resolv.conf.
# To use set as ‘up’ and ‘down’ script in your openvpn config:
# up /etc/openvpn/update-resolv-conf
# down /etc/openvpn/update-resolv-conf
# credit:
# * Thomas Hood <>
# * Chris Hanson
# *
# Licensed under the GNU GPL

[ -x /sbin/resolvconf ] || exit 0

case $script_type in
    for optionname in ${!foreign_option_*} ; do
      echo $option
      part1=$(echo “$option” | cut -d ” ” -f 1)
      if [ “$part1″ == “dhcp-option” ] ; then
        part2=$(echo “$option” | cut -d ” ” -f 2)
        part3=$(echo “$option” | cut -d ” ” -f 3)
        if [ “$part2″ == “DNS” ] ; then
        if [ “$part2″ == “DOMAIN” ] ; then
    if [ “$IF_DNS_SEARCH” ] ; then
      R=”${R}search $IF_DNS_SEARCH”
    for NS in $IF_DNS_NAMESERVERS ; do
      R=”${R}nameserver $NS”
    echo -n “$R” | /sbin/resolvconf -a “${dev}.inet”
    /sbin/resolvconf -d “${dev}.inet”
    cp /etc/openvpn/resolv.bak /etc/resolv.conf <– NOTE THIS LINE.  IMPORTANT.

See that bit about “NOTE THIS LINE.  IMPORTANT” up there?  Remove that (and the arrow).

create a file called /etc/openvpn/resolv.bak:

nameserver <IP of your nameserver here>
nameserver <IP of your secondary NS here>

I use Google’s nameservers, and, because my own firewall’s DNS forwarder is unreliable.

Again, there is probably a better way to do this, but it’s the only way I could ensure that update-resolv-conf left me with a working DNS setup whenever I killed the VPN tunnel.

IV. BitTorrent – Transmission

I screwed around with several web-based BitTorrent packages before settling on Transmission; it was one of the few that’s still actively maintained and which installed right off the bat.

Note that there are a ton of other decent-looking BitTorrent clients out there – a friend swears by rtorrent + xmlrpc as much more capable of automating tasks.  Perhaps – use whatever works for you.  I needed something simple and robust, and have been using Transmission on OSX for a while.

Assuming you stick with Transmission, you will need the transmission-daemon package:

cd /usr/ports/net-p2p/transmission-daemon && make install

The default config is in /usr/local/etc/transmission/home/settings.json.  The only line you should have to change is:

“rpc-whitelist”:  “,<Your client IP address(es) here>“,

This entry accepts wildcards, so for example 192.168.1.* will grant access to all machines on that subnet.

Add the following lines to your /etc/rc.conf:

# transmission
transmission_download_dir=”/data2/Download/Bittorrent” (or whatever works for you)

Once you have that, you can run

/usr/local/etc/rc.d/transmission start

and connect to


Transmission will now run at boot.

Note that the package does some shenanigans with your config files – i.e. it will overwrite certain entries when stopping or starting.  Check your config file (settings.json) after starting/stopping transmission the first few times to make sure this is not the case – I don’t know which entries are overwritten (for example the line “download-dir”: is overwritten, but “bind-address-ipv4″: is not.)

V. Blocklists and ipfw

This is not strictly necessary, but I’m paranoid.  I want to avoid the following:

– accidentally starting bittorrent when the tunnel’s down (and going over my non-encrypted interface)

– peering with known nasties

I get a bunch of blocklists from BlueTack, but they appear to have restricted registrations.  Look around a bit – there are plenty of ipfw-compatible blocklists out there.

I followed Alex Kruijff’s guide to setting up p2p firewalls – some of the blocklists in do not always work or are outdated, you will have to experiment a bit.

Next, I want to avoid having transmission make any connections when the tunnel is down.  My non-OpenVPN interface is called re0.

Alex’ blog instructs you to add a line to your crontab to update your blocklist.conf.  I simply created the file blocklist.local with my own firewall rules to avoid connections to my peer port configured in transmission (default is 51413) and change the crontab entry to append blocklist.local to blocklist.conf:

behemoth# crontab -l
0       20      *       *       6       /usr/local/sbin/ && /usr/local/sbin/ > /usr/local/behemoth/etc/blocklist.conf; cat /usr/local/bbehemoth/etc/blocklist.local >> /usr/local/behemoth/etc/blocklist.conf

Obviously your directories will vary.

Even though I have a dedicated Internet-facing firewall, I added this extra bit because I permit bittorrent connections from and to my home network (I occasionally get lazy and download stuff onto my laptops or desktop and I keep forgetting who has which IP).  Read up on ipfw syntax for what the local blocklist should look like.

VI. Activate the VPN

Lastly, you will have to give Mullvad some money.  I am currently on a 5 Euro / 1 month trial (just until I see how this holds up, and it seems to be working beautifully thus far).  Go to their page, log in with your customer number (see section III.b. above), and pay them.  Your VPN will work shortly thereafter.  Give it a little time, then start OpenVPN:

/usr/local/etc/rc.d/openvpn start

If it’s working, you will see something like this:

behemoth# ifconfig tun0
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500
        inet –> netmask 0xffffffff
        nd6 options=1<PERFORMNUD>
        Opened by PID 1365

behemoth# cat /etc/resolv.conf
# Generated by resolvconf

And that’s it.  You can now open your transmission instance and start torrenting.

VII. More Stuff

JKT has a blog post up on configuring FlexGet.  If you’re so inclined, this will allow automated transfer setups – mainly of use if you are interested in downloads of regularly published items that are announced via RSS.

For those of you who don’t want to screw around with FreeBSD or Linux, here is a Lifehacker guide on setting up utorrent + web UI on Windows.  Ideal if you have a spare derelict old laptop lying around.  Configure it to not go to sleep when you close the lid, install RealVNC or similar software for remote access in case you ever need to log in, connect a nice big external hard drive, install the Mullvad (or equivalent) VPN client (in my provider’s case, a one-click installation, no configuration needed) and you’re good to go.  Old Apple laptops are equally simple to set up, with web access to the OSX Transmission client.

You may wish to make sure that the tunnel does not close due to inactivity – to that end, you can put something like this in crontab:

# crontab -e

* * * * * /sbin/ping -c 5

This will send 5 pings every minute to an IP or hostname of your choice.

Please be aware, as always, that you’re entirely responsible for what you do with your new toy.  Anonymity and security are good, but nothing is 100% guaranteed anonymous or secure.


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>