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

Have a look at

and see if the desired version is available. If it's not, and you want to "poll", you can use this:

  • copy the URLs above in /tmp/tbb-urls.txt
  • export TBB_VERSION=
  • run this snippet (bash only!)

        set -eu
        typeset -a tbbUrls
        mapfile -t tbbUrls < <(grep -F --no-filename https: /tmp/tbb-urls.txt |sed -e 's+^ *++;s+ *$++')
        while true
            if (for u in "${tbbUrls[@]}"; do
                elinks -no-numbering -no-references -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.
Unfortunately, some of the servers that the Tor project uses will automatically redirect to HTTPS, and our build system does _not_ support that. `` is one of those. When this happens, you must put those tarballs on a server that allows us to use plain HTTP. Unfortunately, we have no standardized procedure for that, and every RM is going freestyle.

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: sometimes, 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-linux64-[0-9].*_en-US\.tar\.xz$" \
        sha256sums-unsigned-build.txt \
    && grep --color=never -E \
        "\slangpacks-tor-browser-linux64-.*\.tar\.xz$" \
        sha256sums-unsigned-build.txt \
) > config/chroot_local-includes/usr/share/tails/tbb-sha256sums.txt

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.

Lastly, commit:

git commit config/chroot_local-includes/usr/share/tails/tbb-*.txt \
    -m "Upgrade Tor Browser to ${TBB_VERSION:?}" && \
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.

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

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 && \
git annex copy --to origin -- "${TBB_VERSION:?}" && \
git annex sync

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.

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 && \
rm -rf "${DL_DIR:?}" && \
cd "${TAILS_GIT_REPO:?}" && \
rm -f sha256sums-unsigned-build.txt{,.asc${TBB_SIGNER_SUFFIX}}