tor-install-script/tor_install.sh
2025-09-07 14:37:46 +02:00

128 lines
5.1 KiB
Bash

#!/usr/bin/env bash
# SPDX-License-Identifier: CC0-1.0
# Dedicated to the public domain under CC0 1.0 Universal.
# See https://creativecommons.org/publicdomain/zero/1.0/
# This script is not affiliated with or endorsed by The Tor Project.
set -Eeuo pipefail
IFS=$'\n\t'
# ------------------------------- logging --------------------------------------
# Plain ASCII, no icons or emojis.
c_green() { printf '\033[0;32m%s\033[0m\n' "$*"; }
c_yellow() { printf '\033[1;33m%s\033[0m\n' "$*"; }
c_red() { printf '\033[0;31m%s\033[0m\n' "$*"; }
log() { c_green "INFO: $*"; }
warn() { c_yellow "WARN: $*"; }
die() { c_red "ERROR: $*"; exit 1; }
# Print a helpful line number on failure.
trap 'die "Error on or near line $LINENO. Exiting."' ERR
# ------------------------------- root check -----------------------------------
# We must be root to modify APT sources and install packages.
if [[ ${EUID:-0} -ne 0 ]]; then
if command -v sudo >/dev/null 2>&1; then
exec sudo -E -- "$0" "$@"
else
die "Please run as root (or install sudo)."
fi
fi
# Make APT non-interactive and a bit more resilient.
export DEBIAN_FRONTEND=noninteractive
APT_FLAGS=(-y -o Dpkg::Use-Pty=0 -o Acquire::Retries=3 -o Acquire::http::No-Cache=true)
# --------------------------- detect codename ----------------------------------
# We need the Debian/Ubuntu codename (e.g., bookworm, bullseye, noble, jammy).
OS_ID='' CODENAME=''
if [[ -r /etc/os-release ]]; then
# shellcheck disable=SC1091
. /etc/os-release
OS_ID="${ID:-}"
CODENAME="${VERSION_CODENAME:-}"
fi
if [[ -z ${CODENAME} ]]; then
if command -v lsb_release >/dev/null 2>&1; then
CODENAME="$(lsb_release -cs 2>/dev/null || true)"
fi
fi
[[ -z ${CODENAME} ]] && die "Could not determine distro codename. Aborting."
log "Distro ID: ${OS_ID:-unknown}, Codename: ${CODENAME}"
# ------------------------------ prerequisites ---------------------------------
# Minimal tools to fetch keys and manage repos.
log "Ensuring prerequisites..."
apt-get update "${APT_FLAGS[@]}"
apt-get install "${APT_FLAGS[@]}" --no-install-recommends \
ca-certificates gnupg curl lsb-release
# ------------------------ configure Tor Project repo --------------------------
# This section is the whole point: always use the Tor Project APT repository.
log "Configuring Tor Project APT repository..."
# Create a dedicated system keyring directory if needed.
install -d -m 0755 /usr/share/keyrings
# Download the Tor Project archive signing key to a temporary file.
# Official key fingerprint:
# A3C4 F0F9 79CA A22C DBA8 F512 EE8C BC9E 886D DD89
KEY_URL="https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc"
TMP_KEY="$(mktemp)"
curl -fsSL "$KEY_URL" -o "$TMP_KEY"
# Verify the fingerprint before trusting the key.
FPR_EXPECTED="A3C4 F0F9 79CA A22C DBA8 F512 EE8C BC9E 886D DD89"
FPR_SEEN="$(gpg --show-keys --with-colons "$TMP_KEY" 2>/dev/null | awk -F: '/^fpr:/ {print $10; exit}' | sed 's/.\{4\}/& /g' | sed 's/ $//')"
if [[ "$FPR_SEEN" != "$FPR_EXPECTED" ]]; then
rm -f "$TMP_KEY"
die "Tor Project key fingerprint mismatch. Expected '$FPR_EXPECTED' but saw '$FPR_SEEN'."
fi
# Install the verified key into a dedicated keyring file.
gpg --dearmor < "$TMP_KEY" > /usr/share/keyrings/torproject-org-archive.gpg
rm -f "$TMP_KEY"
# Write the source list entry, pinned to the keyring.
# Note: if the Tor Project does not publish packages for your codename or arch,
# APT operations will fail, which is intentional for this script.
SRC_LINE="deb [signed-by=/usr/share/keyrings/torproject-org-archive.gpg] https://deb.torproject.org/torproject.org ${CODENAME} main"
SRC_FILE="/etc/apt/sources.list.d/torproject-org.list"
printf '%s\n' "$SRC_LINE" > "$SRC_FILE"
# Refresh APT indices from the Tor Project repo.
apt-get update "${APT_FLAGS[@]}"
# ------------------------------- installation ---------------------------------
# Install Tor from the Tor Project repository, plus their keyring package
# to keep keys maintained via APT.
log "Installing tor and deb.torproject.org-keyring from the Tor Project repo..."
apt-get install "${APT_FLAGS[@]}" --no-install-recommends tor deb.torproject.org-keyring
# ------------------------------- post-install ---------------------------------
# Show version and attempt to enable and start the service on systemd systems.
if command -v tor >/dev/null 2>&1; then
log "Tor installed. Version:"
tor --version || true
if command -v systemctl >/dev/null 2>&1; then
# Try common service names. Ignore errors if a given unit does not exist.
systemctl enable --now tor.service >/dev/null 2>&1 || true
systemctl enable --now tor@default.service >/dev/null 2>&1 || true
# Print a simple status hint if neither service is active.
if ! systemctl is-active --quiet tor.service 2>/dev/null \
&& ! systemctl is-active --quiet tor@default.service 2>/dev/null; then
warn "Tor service is not active. You can start it with:"
warn " systemctl start tor.service"
warn " or"
warn " systemctl start tor@default.service"
fi
else
warn "Systemd not detected. Use your init system to manage the Tor daemon."
fi
else
die "Tor did not install correctly."
fi