The big picture

The Tails build system downloads a set of Tor Browser tarballs from a location specified in config/chroot local-includes/usr/share/tails/tbb-dist-url.txt, and compares their hash with previously verified ones found in config/chroot local-includes/usr/share/tails/tbb-sha256sums.txt.

Once released officially, Tor Browser tarballs can be found in a permanent (?) location. However, when upgrading Tor Browser for an imminent Tails release, we generally have to use Tor Browser tarballs that are under QA and not officially released yet. So, we have to retrieve them from another, temporary location, such as If we hard-coded this temporary URL in tbb-dist-url.txt, then our release tag would only be buildable for as long the tarballs stay in that place, which at best is a few months.

To solve this, we host ourselves the Tor Browser tarballs we need, and point to this permanent location for anything that we tag.

Still, one can set an arbitrary download location in tbb-dist-url.txt, which should provide all the flexibility needed for development purposes.

Occasionally, the new Tor Browser requires adjustments to the corresponding AppArmor profile: AppArmor policy.

Upgrade Tor Browser in Tails


To check if the desired version is available:

  1. Set TBB_VERSION to the version of Tor Browser you are waiting for, e.g. 42.0.12.

  2. Run this script:

         set -eu
         typeset -a tbbUrls
         tbbUrls=( ';O=D' ';O=D' ';O=D' ';O=D' ';O=D' ';O=D' '' '' )
         while true
             if (for u in "${tbbUrls[@]}"; do
                     echo "query ${u}" >&2
                 elinks -no-numbering  -dump "$u" | sed -e "s+^+[${u//+/ }]+" ; done
                 ) | grep -F -e "${TBB_VERSION?}" -e "$(date +%F)"  -e "$(date +%F -d yesterday)" --color=always
                 echo FOUND
                 notify-send "Release dir" 'found'
             sleep 10m


Set TBB_DIST_URL to the chosen URL, and set TBB_VERSION to the desired Tor Browser version, for example:

TBB_VERSION="$(basename "${TBB_DIST_URL:?}")"
Ensure you include the "-buildN" part. Add it if it's missing.

Set TBB_TAILS_TICKET to the number of the ticket about updating Tor Browser, and TBB_IMPORT_BRANCH to the branch we'll work on, which must include the -force-all-tests suffix:


Check out the new branch:

git checkout -b ${TBB_IMPORT_BRANCH:?} origin/stable

Set TBB_SIGNER_SUFFIX to the nickname of the Tor Browser developer who signed the sha256sums-unsigned-build.txt file, preceeded by a dash; the detached signature at $TBB_DIST_URL is named sha256sums-unsigned-build.txt.asc${TBB_SIGNER_SUFFIX}:


Note: Nowadays it's quite common that the detached signature is called sha256sums-unsigned-build.txt.asc, with no suffix. If that's the case, just set it to an empty string:


Fetch the version's hash file and its detached signature, and verify with GnuPG:

    set -e
    for f in sha256sums-unsigned-build.txt{.asc${TBB_SIGNER_SUFFIX?},}; do
        wget "${TBB_DIST_URL:?}/$f" -O "$f"
    gpg --verify sha256sums-unsigned-build.txt{.asc${TBB_SIGNER_SUFFIX?},}

Build the list of tarballs we want and their hashes, so this information is available at build time, when the tarballs are fetched:

    grep --color=never -E \
        "\stor-browser-linux-x86_64-${TBB_VERSION%-build*}\.tar\.xz$" \
) > config/chroot_local-includes/usr/share/tails/tbb-sha256sums.txt

Set download url

If TBB_DIST_URL supports http

Then update the URL to the one chosen above:

echo "${TBB_DIST_URL:?}" | sed "s,^https://,http://," > \

We cannot use HTTPS: building Tails uses a caching HTTP proxy by default and there's no way such a proxy caches data without MitM'ing connections. However, it is of no consequence since we verify the checksum file.


Nowadays, tarballs are usually put on a web server, such as https://tb-build-*, that doesn't support http: it will redirect to https.

If this is the case, you must put those tarballs on a server that allows us to use plain HTTP.

We cannot use such a server directly, so we need to (at least temporarily) self-host this.

If you can access torbrowser-archive.git

echo "${TBB_DIST_URL:?}" > \
git commit config/chroot_local-includes/usr/share/tails/tbb-*.txt \
    -m "Upgrade Tor Browser to ${TBB_VERSION:?} (refs: tails#${TBB_TAILS_TICKET})" && \
git show

Please refer to Self-hosted Tor Browser tarballs archive section.

If you can't access it

Download the relevant files:

    grep --color=never -Eo \
        '\stor-browser-linux-x86_64-${TBB_VERSION%-build*}\.tar\.xz$' \
        sha256sums-unsigned-build.txt \
) | sed -re "s@^\s*@${TBB_DIST_URL:?}@" | xargs wget -c

Now, put them on some webserver that you can control. Let's say you uploaded them to Put that URL in config/chroot_local-includes/usr/share/tails/tbb-dist-url.txt


Lastly, commit:

git commit config/chroot_local-includes/usr/share/tails/tbb-*.txt \
    -m "Upgrade Tor Browser to ${TBB_VERSION:?} (refs: tails#${TBB_TAILS_TICKET})" && \
git show

If this new Tor Browser is meant to be included in a Tails release, then that's not enough: as explained above, we need to host the corresponding tarballs ourselves, so read on the next section.

Sync with the upstream wrapper scripts

Adapt our config/chroot_local-includes/usr/local/bin/tor-browser and/or config/chroot_local-includes/usr/local/lib/tails-shell-library/ for recent changes made in the Tor Browser build Git repo (git clone, on the maint-X.Y-desktop branch (if it does not exist, fall back to maint-X.Y):

git log -p \
    projects/firefox/ \
    projects/firefox/start-firefox \

Then apply any relevant change, e.g. to:

  • environment variables;

  • commandline options passed to the firefox executable;

  • required libstdc++6 version bumps; if there's been any change upstream, look for abicheck in config/chroot_local-hooks/10-tbb and adjust that hook as needed.

We also document (as code comments that includes the analysis, in config/chroot_local-includes/usr/local/lib/tails-shell-library/ each such environment variable (and similar) that we consider irrelevant and skip, both to avoid others duplicating the analysis and to make it explicit during the review so it can be validated.

Self-hosted Tor Browser tarballs archive

Initial setup

First, install git-annex.

Then, make sure you have an entry for in your ~/.ssh/config. For details, see ISO_history.mdwn in tails/rm.

Then, clone the metadata repository and initialize git-annex:

git clone && \
cd torbrowser-archive && \
git annex init

You now have a lot of (dangling) symlinks in place of the files that are available in this git-annex repo.

To synchronize your local git-annex metadata with the remote, run:

git annex sync --no-content

Set up environment variables

  1. Make sure you still have the environment variables defined in the previous section set.

  2. Make TAILS_GIT_REPO point to the main Tails Git repository checkout where tbb-dist-url.txt is being worked on, for example:

  3. Make TBB_ARCHIVE point to your local git annex working copy of our Tor Browser archive, for example:


Import a new set of Tor Browser tarballs

  1. Download and verify all the tarballs we need:

     DL_DIR=$(mktemp --tmpdir -d "tor-browser-${TBB_VERSION}.XXXXXXXXXX")
     cd "${TAILS_GIT_REPO:?}" && git checkout "${TBB_IMPORT_BRANCH:?}"
     TBB_TARBALLS_BASE_URL="$(cat "${TBB_DIST_URL_FILE:?}" | sed "s,^http://,https://,")"
     current_branch=$(git -C "${TAILS_GIT_REPO:?}" branch | awk '/^\* / { print $2 }')
     for branch in "$current_branch" ; do
        git -C "${TAILS_GIT_REPO:?}" show "$branch:${TBB_SHA256SUMS_FILE:?}" \
        | while read expected_sha256 tarball; do
              cd "$DL_DIR"
              echo "Retrieving '${TBB_TARBALLS_BASE_URL:?}/${tarball:?}'..."
              curl --remote-name --retry 20 --continue-at - \
           cd "${DL_DIR:?}" && \
           git -C "${TAILS_GIT_REPO:?}" show "$branch:${TBB_SHA256SUMS_FILE:?}" \
              | sha256sum -c -
  2. Import the tarballs into your local Git annex:

     cd "${TBB_ARCHIVE:?}" && \
     mkdir "${TBB_VERSION:?}" && cd "${TBB_VERSION:?}" && \
     git annex import --duplicate "${DL_DIR:?}/"* "${TAILS_GIT_REPO:?}/"sha256sums-*

Commit and push your changes

cd "${TBB_ARCHIVE:?}" && \
git commit -m "Add Tor Browser ${TBB_VERSION:?}" && \
git annex sync --no-content && \
git annex copy --to origin -- "${TBB_VERSION:?}" && \
git annex sync --no-content

Adjust the URL in the main Git repository

cd "${TAILS_GIT_REPO:?}" && \
git checkout "${TBB_IMPORT_BRANCH:?}"
current_branch=$(git branch | awk '/^\* / { print $2 }')
for branch in "${current_branch:?}" ; do
   git checkout "${branch:?}" && \
   echo "${TBB_VERSION:?}/" > \
        config/chroot_local-includes/usr/share/tails/tbb-dist-url.txt && \
   git commit config/chroot_local-includes/usr/share/tails/tbb-dist-url.txt \
       -m "Fetch Tor Browser from our own archive" && \
   git show

Wait for the synchronization

Before you can build Tails using Tor Browser from our own archive, you need to wait for the tarballs to appear on This can take up to 10 minutes:

url="$(cat config/chroot_local-includes/usr/share/tails/tbb-dist-url.txt)"
while [ -z "$(elinks -dump -no-references -no-numbering "$url"   | grep 'tor-browser-linux-x86_64.*MiB')" ]
    sleep 5

Push the updated branch

git push -o merge_request.create --set-upstream \
   origin "${TBB_IMPORT_BRANCH:?}"

Clean up

cd "${TBB_ARCHIVE:?}" && \
git annex drop -- "${TBB_VERSION:?}" && \
git annex sync --no-content && \
rm -rf "${DL_DIR:?}" && \
cd "${TAILS_GIT_REPO:?}" && \
rm -f sha256sums-unsigned-build.txt{,.asc${TBB_SIGNER_SUFFIX}}