diff --git a/scripts/installer.sh b/scripts/installer.sh new file mode 100755 index 000000000..488690873 --- /dev/null +++ b/scripts/installer.sh @@ -0,0 +1,384 @@ +#!/bin/sh +# Copyright (c) 2021 Tailscale Inc & AUTHORS All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. +# +# This script detects the current operating system, and installs +# Tailscale according to that OS's conventions. + +set -eu + +# All the code is wrapped in a main function that gets called at the +# bottom of the file, so that a truncated partial download doesn't end +# up executing half a script. +main() { + # Step 1: detect the current linux distro, version, and packaging system. + # + # We rely on a combination of 'uname' and /etc/os-release to find + # an OS name and version, and from there work out what + # installation method we should be using. + # + # The end result of this step is that the following three + # variables are populated, if detection was successful. + OS="" + VERSION="" + PACKAGETYPE="" + + if [ -f /etc/os-release ]; then + # /etc/os-release populates a number of shell variables. We care about the following: + # - ID: the short name of the OS (e.g. "debian", "freebsd") + # - VERSION_ID: the numeric release version for the OS, if any (e.g. "18.04") + # - VERSION_CODENAME: the codename of the OS release, if any (e.g. "buster") + . /etc/os-release + case "$ID" in + ubuntu) + OS="$ID" + VERSION="$VERSION_ID" + PACKAGETYPE="apt" + ;; + debian) + OS="$ID" + VERSION="$VERSION_CODENAME" + PACKAGETYPE="apt" + ;; + raspbian) + OS="$ID" + VERSION="$VERSION_CODENAME" + PACKAGETYPE="apt" + ;; + centos) + OS="$ID" + VERSION="$VERSION_ID" + PACKAGETYPE="dnf" + if [ "$VERSION" = "7" ]; then + PACKAGETYPE="yum" + fi + ;; + rhel) + OS="$ID" + VERSION="$(echo "$VERSION_ID" | cut -f1 -d.)" + PACKAGETYPE="dnf" + ;; + fedora) + OS="$ID" + VERSION="" + PACKAGETYPE="dnf" + ;; + amzn) + OS="amazon-linux" + VERSION="$VERSION_ID" + PACKAGETYPE="yum" + ;; + opensuse-leap) + OS="opensuse" + VERSION="leap/$VERSION_ID" + PACKAGETYPE="zypper" + ;; + opensuse-tumbleweed) + OS="opensuse" + VERSION="tumbleweed" + PACKAGETYPE="zypper" + ;; + arch) + OS="$ID" + VERSION="" # rolling release + PACKAGETYPE="pacman" + ;; + manjaro) + OS="$ID" + VERSION="" # rolling release + PACKAGETYPE="pacman" + ;; + alpine) + OS="$ID" + VERSION="$VERSION_ID" + PACKAGETYPE="apk" + ;; + nixos) + echo "Please add Tailscale to your NixOS configuration directly:" + echo + echo "services.tailscale.enable = true;" + exit 1 + ;; + void) + OS="$ID" + VERSION="" # rolling release + PACKAGETYPE="xbps" + ;; + gentoo) + OS="$ID" + VERSION="" # rolling release + PACKAGETYPE="emerge" + ;; + freebsd) + OS="$ID" + VERSION="$(echo "$VERSION_ID" | cut -f1 -d.)" + PACKAGETYPE="pkg" + ;; + # TODO: wsl? + # TODO: synology? qnap? + esac + fi + + # If we failed to detect something through os-release, consult + # uname and try to infer things from that. + if [ -z "$OS" ]; then + if type uname >/dev/null 2>&1; then + case "$(uname)" in + FreeBSD) + # FreeBSD before 12.2 doesn't have + # /etc/os-release, so we wouldn't have found it in + # the os-release probing above. + OS="freebsd" + VERSION="$(freebsd-version | cut -f1 -d.)" + PACKAGETYPE="pkg" + ;; + OpenBSD) + OS="openbsd" + VERSION="$(uname -r)" + PACKAGETYPE="" + ;; + Darwin) + OS="macos" + VERSION="$(sw_vers -productVersion | cut -f1-2 -d.)" + PACKAGETYPE="appstore" + ;; + Linux) + OS="other-linux" + VERSION="" + PACKAGETYPE="" + ;; + esac + fi + fi + + # Step 2: having detected an OS we support, is it one of the + # versions we support? + OS_UNSUPPORTED= + case "$OS" in + ubuntu) + if [ "$VERSION" != "16.04" ] && \ + [ "$VERSION" != "18.04" ] && \ + [ "$VERSION" != "19.10" ] && \ + [ "$VERSION" != "20.04" ] && \ + [ "$VERSION" != "20.10" ] && \ + [ "$VERSION" != "21.04" ] + then + OS_UNSUPPORTED=1 + fi + ;; + debian) + if [ "$VERSION" != "stretch" ] && \ + [ "$VERSION" != "buster" ] && \ + [ "$VERSION" != "bullseye" ] && \ + [ "$VERSION" != "sid" ] + then + OS_UNSUPPORTED=1 + fi + ;; + raspbian) + if [ "$VERSION" != "buster" ] + then + OS_UNSUPPORTED=1 + fi + ;; + centos) + if [ "$VERSION" != "7" ] && \ + [ "$VERSION" != "8" ] + then + OS_UNSUPPORTED=1 + fi + ;; + rhel) + if [ "$VERSION" != "8" ] + then + OS_UNSUPPORTED=1 + fi + ;; + amazon-linux) + if [ "$VERSION" != "2" ] + then + OS_UNSUPPORTED=1 + fi + ;; + opensuse) + if [ "$VERSION" != "leap/15.1" ] && \ + [ "$VERSION" != "leap/15.2" ] && \ + [ "$VERSION" != "tumbleweed" ] + then + OS_UNSUPPORTED=1 + fi + ;; + arch) + # Rolling release, no version checking needed. + ;; + manjaro) + # Rolling release, no version checking needed. + ;; + alpine) + # All versions supported, no version checking needed. + # TODO: is that true? When was tailscale packaged? + ;; + void) + # Rolling release, no version checking needed. + ;; + gentoo) + # Rolling release, no version checking needed. + ;; + freebsd) + if [ "$VERSION" != "12" ] && \ + [ "$VERSION" != "13" ] + then + OS_UNSUPPORTED=1 + fi + ;; + openbsd) + OS_UNSUPPORTED=1 + ;; + macos) + # We delegate macOS installation to the app store, it will + # perform version checks for us. + ;; + other-linux) + OS_UNSUPPORTED=1 + ;; + *) + OS_UNSUPPORTED=1 + ;; + esac + if [ "$OS_UNSUPPORTED" = "1" ]; then + case "$OS" in + other-linux) + echo "Couldn't determine what kind of Linux is running." + echo "You could try the static binaries at:" + echo "https://pkgs.tailscale.com/stable/#static" + ;; + "") + echo "Couldn't determine what operating system you're running." + ;; + *) + echo "$OS $VERSION isn't supported by this script yet." + ;; + esac + echo + echo "If you'd like us to support your system better, please email support@tailscale.com" + echo "and tell us what OS you're running." + echo + echo "Please include the following information we gathered from your system:" + echo + echo "OS=$OS" + echo "VERSION=$VERSION" + echo "PACKAGETYPE=$PACKAGETYPE" + if type uname >/dev/null 2>&1; then + echo "UNAME=$(uname -a)" + else + echo "UNAME=" + fi + echo + if [ -f /etc/os-release ]; then + cat /etc/os-release + else + echo "No /etc/os-release" + fi + exit 1 + fi + + # Step 3: work out if we can run privileged commands, and if so, + # how. + CAN_ROOT= + SUDO= + if [ "$(id -u)" = 0 ]; then + CAN_ROOT=1 + SUDO="" + elif type sudo >/dev/null; then + CAN_ROOT=1 + SUDO="sudo" + elif type doas >/dev/null; then + CAN_ROOT=1 + SUDO="doas" + fi + if [ "$CAN_ROOT" != "1" ]; then + echo "This installer needs to run commands as root." + echo "We tried looking for 'sudo' and 'doas', but couldn't find them." + echo "Either re-run this script as root, or set up sudo/doas." + exit 1 + fi + + # Step 3: run the installation. + echo "Installing Tailscale for $OS $VERSION, using method $PACKAGETYPE" + case "$PACKAGETYPE" in + apt) + # TODO: use newfangled per-repo signature scheme + set -x + curl -fsSL "https://pkgs.tailscale.com/stable/$OS/$VERSION.gpg" | $SUDO apt-key add - + curl -fsSL "https://pkgs.tailscale.com/stable/$OS/$VERSION.list" | $SUDO tee /etc/apt/sources.list.d/tailscale.list + $SUDO apt-get update + $SUDO apt-get install tailscale + set +x + ;; + yum) + set -x + $SUDO yum install yum-utils + $SUDO yum-config-manager --add-repo "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo" + $SUDO yum install tailscale + $SUDO systemctl enable --now tailscaled + set +x + ;; + dnf) + set -x + $SUDO dnf config-manager --add-repo "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo" + $SUDO dnf install tailscale + $SUDO systemctl enable --now tailscaled + set +x + ;; + zypper) + set -x + $SUDO zypper ar -g -r "https://pkgs.tailscale.com/stable/$OS/$VERSION/tailscale.repo" + $SUDO zypper ref + $SUDO zypper in tailscale + $SUDO systemctl enable --now tailscaled + set +x + ;; + pacman) + set -x + $SUDO pacman -S tailscale + $SUDO systemctl enable --now tailscaled + set +x + ;; + apk) + set -x + $SUDO apk add tailscale + $SUDO rc-update add tailscale + set +x + ;; + xbps) + set -x + $SUDO xbps-install tailscale + set +x + ;; + emerge) + set -x + $SUDO emerge net-vpn/tailscale + set +x + ;; + appstore) + set -x + open "https://apps.apple.com/us/app/tailscale/id1475387142" + set +x + ;; + *) + echo "unexpected: unknown package type $PACKAGETYPE" + exit 1 + ;; + esac + + echo "Installation complete! Log in to start using Tailscale by running:" + echo + if [ -z "$SUDO" ]; then + echo "tailscale up" + else + echo "$SUDO tailscale up" + fi +} + +main