mirror of
https://github.com/unraid/webgui.git
synced 2026-05-19 04:39:52 -05:00
e289d2ad7c
- Remove exclusion from share directory from .gitignore - Add Unraid specific container hook script - Add Tailscale icon - Add helptexts for Tailscale This integration allows users to easily make use of Tailscale in their Docker containers by just clicking a switch on the Docker page. The Tailscale plugin itself is not needed for this integration but for the best user experience it is strongly recommended to install the Tailscale plugin from Community Applications. How this works: 1. Configure Tailscale in the Docker template in Unraid and click Apply 2. Unraid will extract the default Entrypoint and CMD from the container 3. The hook script will be mounted in the container to /opt/unraid/tailscale-hook and the Entrypoint from the container will be modified to /opt/unraid/tailscale-hook 4. The original Entrypoint and CMD from the container, alongside with the other necessary variables for Tailscale will be passed over to the container 5. When the container starts the hook script will be executed, install dependencies (currently Alpine, Arch and Debian based containers are supported), download the newest version from Tailscale and run it 6. After the first start with Tailscale the container will halt and wait for the user to click on the link which is presented in the log from the container to add the container to your Tailnet (alternatively one could also open up a Console from the container and issue `tailscale status` which will also present the link to authenticate the container to your Tailnet) 7. The hook script will pass over the default Entrypoint and CMD which was extracted in step 2 and the container will start as usual These steps will be repeated after Container update, force update from the Docker page and if changes in the template are made. If the container is only Started/Restarted the hook script will detect that Tailscale is installed and only start it, if one wants to update Tailscale inside the container simply hit `force update` on the Docker page in Unraid (with Advanced View Enabled) The integration will show a Tailscale icon on the Docker page for each Tailscale enabled Container and show some basic information from the container (Installed Tailscale Version, Online Status, Hostname, Main Relay, IPs, Exit Node, Auth Expiry,...) When Serve or Funnel is enabled it will also generate `Tailscale WebUI` in the drop down for the container which you can open up if Tailscale is installed from the device you are accessing Unraid.
314 lines
11 KiB
Bash
Executable File
314 lines
11 KiB
Bash
Executable File
#!/bin/sh
|
|
# Copyright 2024, Lime Technology
|
|
# Copyright 2024, Christoph Hummer
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License version 2,
|
|
# as published by the Free Software Foundation.
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
|
|
exec_entrypoint() {
|
|
echo "Starting container..."
|
|
echo
|
|
echo "======================="
|
|
echo
|
|
eval "exec ${ORG_ENTRYPOINT} ${ORG_CMD} ${ORG_POSTARGS}"
|
|
}
|
|
|
|
error_handler() {
|
|
echo "ERROR: Unraid Docker Hook script throw an error!"
|
|
echo " Starting container without Tailscale!"
|
|
echo
|
|
exec_entrypoint
|
|
}
|
|
|
|
echo "======================="
|
|
echo
|
|
echo "Executing Unraid Docker Hook for Tailscale"
|
|
echo
|
|
|
|
if [ ! -f /usr/bin/tailscale ] || [ ! -f /usr/bin/tailscaled ]; then
|
|
if [ ! -z "${TAILSCALE_EXIT_NODE_IP}" ]; then
|
|
if [ ! -c /dev/net/tun ]; then
|
|
echo "ERROR: Device /dev/net/tun not found!"
|
|
echo " Make sure to pass through /dev/net/tun to the container."
|
|
error_handler
|
|
fi
|
|
INSTALL_IPTABLES="iptables "
|
|
fi
|
|
|
|
echo "Detecting Package Manager..."
|
|
if which apt-get >/dev/null 2>&1; then
|
|
echo "Detected Advanced Package Tool!"
|
|
PACKAGES_UPDATE="apt-get update"
|
|
PACKAGES_INSTALL="apt-get -y install --no-install-recommends"
|
|
elif which apk >/dev/null 2>&1; then
|
|
echo "Detected Alpine Package Keeper!"
|
|
PACKAGES_UPDATE="apk update"
|
|
PACKAGES_INSTALL="apk add"
|
|
elif which pacman >/dev/null 2>&1; then
|
|
echo "Detected pacman Package Manager!"
|
|
PACKAGES_INSTALL="pacman -Syu --noconfirm"
|
|
else
|
|
echo "ERROR: Detection from Package Manager failed!"
|
|
error_handler
|
|
fi
|
|
|
|
if [ "${TAILSCALE_TROUBLESHOOTING}" = "true" ]; then
|
|
if which apt-get >/dev/null 2>&1; then
|
|
PACKAGES_TROUBLESHOOTING="curl dnsutils iputils-ping "
|
|
elif which apk >/dev/null 2>&1; then
|
|
PACKAGES_TROUBLESHOOTING="curl bind-tools iputils-ping "
|
|
elif which pacman >/dev/null 2>&1; then
|
|
PACKAGES_TROUBLESHOOTING="curl dnsutils iputils "
|
|
fi
|
|
echo "Tailscale Troubleshooting enabled!"
|
|
echo "Installing additional packages: $(echo "${PACKAGES_TROUBLESHOOTING}" | sed 's/[[:blank:]]*$//' | sed 's/ /, /g')"
|
|
fi
|
|
|
|
echo "Installing packages..."
|
|
echo "Please wait..."
|
|
if [ ! -z "${PACKAGES_UPDATE}" ]; then
|
|
UPDATE_LOG=$(${PACKAGES_UPDATE} 2>&1)
|
|
fi
|
|
INSTALL_LOG=$(${PACKAGES_INSTALL} jq wget ${INSTALL_IPTABLES}${PACKAGES_TROUBLESHOOTING} 2>&1)
|
|
INSTALL_RESULT=$?
|
|
|
|
if [ "${INSTALL_RESULT}" -eq 0 ]; then
|
|
echo "Packages installed!"
|
|
unset INSTALL_LOG
|
|
else
|
|
echo "ERROR: Installing packages!"
|
|
echo "${UPDATE_LOG}"
|
|
echo "${INSTALL_LOG}"
|
|
error_handler
|
|
fi
|
|
|
|
if [ "${INSTALL_IPTABLES}" = "iptables " ]; then
|
|
if ! iptables -L >/dev/null 2>&1; then
|
|
echo "ERROR: Cap: NET_ADMIN not available!"
|
|
echo " Make sure to add --cap-add=NET_ADMIN to the Extra Parameters"
|
|
error_handler
|
|
fi
|
|
fi
|
|
|
|
echo "Tailscale not found, downloading..."
|
|
echo "Please wait..."
|
|
|
|
TAILSCALE_VERSION=$(wget -qO- 'https://pkgs.tailscale.com/stable/?mode=json' | jq -r '.TarballsVersion')
|
|
|
|
if [ -z "${TAILSCALE_VERSION}" ]; then
|
|
echo "ERROR: Can't get Tailscale JSON"
|
|
error_handler
|
|
fi
|
|
|
|
if [ ! -d /tmp/tailscale ]; then
|
|
mkdir -p /tmp/tailscale
|
|
fi
|
|
|
|
if wget -q -nc --show-progress --progress=bar:force:noscroll -O /tmp/tailscale/tailscale.tgz "https://pkgs.tailscale.com/stable/tailscale_${TAILSCALE_VERSION}_amd64.tgz" ; then
|
|
echo "Download from Tailscale version ${TAILSCALE_VERSION} successful!"
|
|
else
|
|
echo "ERROR: Download from Tailscale version ${TAILSCALE_VERSION} failed!"
|
|
rm -rf /tmp/tailscale
|
|
error_handler
|
|
fi
|
|
|
|
tar -C /tmp/tailscale -xf /tmp/tailscale/tailscale.tgz
|
|
cp /tmp/tailscale/tailscale_${TAILSCALE_VERSION}_amd64/tailscale /usr/bin/tailscale
|
|
cp /tmp/tailscale/tailscale_${TAILSCALE_VERSION}_amd64/tailscaled /usr/bin/tailscaled
|
|
rm -rf /tmp/tailscale
|
|
|
|
echo "Installation Done!"
|
|
else
|
|
echo "Tailscale found, continuing..."
|
|
fi
|
|
|
|
unset TSD_PARAMS
|
|
unset TS_PARAMS
|
|
|
|
if [ ! -z "${SERVER_DIR}" ]; then
|
|
TSD_STATE_DIR="${SERVER_DIR}/.tailscale_state"
|
|
echo "Settings Tailscale state dir to: ${TSD_STATE_DIR}"
|
|
elif [ ! -z "${DATA_DIR}" ]; then
|
|
TSD_STATE_DIR="${DATA_DIR}/.tailscale_state"
|
|
echo "Settings Tailscale state dir to: ${TSD_STATE_DIR}"
|
|
else
|
|
if [ -z "${TAILSCALE_STATE_DIR}" ]; then
|
|
TAILSCALE_STATE_DIR="/config/.tailscale_state"
|
|
fi
|
|
TSD_STATE_DIR="${TAILSCALE_STATE_DIR}"
|
|
echo "Settings Tailscale state dir to: ${TSD_STATE_DIR}"
|
|
fi
|
|
|
|
if [ ! -d "${TSD_STATE_DIR}" ]; then
|
|
mkdir -p ${TSD_STATE_DIR}
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_EXIT_NODE_IP}" ]; then
|
|
echo "Disabling userspace networking! Tailscale DNS available"
|
|
echo "Using ${TAILSCALE_EXIT_NODE_IP} as Exit Node! See https://tailscale.com/kb/1103/exit-nodes"
|
|
TS_PARAMS=" --exit-node=${TAILSCALE_EXIT_NODE_IP}"
|
|
if [ "${TAILSCALE_ALLOW_LAN_ACCESS}" = "true" ]; then
|
|
echo "Enabling local LAN Access to the container!"
|
|
TS_PARAMS="${TS_PARAMS} --exit-node-allow-lan-access"
|
|
fi
|
|
else
|
|
if [ -z "${TAILSCALE_USERSPACE_NETWORKING}" ] || [ "${TAILSCALE_USERSPACE_NETWORKING}" = "true" ]; then
|
|
echo "Enabling userspace networking! Tailscale DNS not available"
|
|
TSD_PARAMS="-tun=userspace-networking "
|
|
else
|
|
if [ ! -c /dev/net/tun ]; then
|
|
echo "ERROR: Device /dev/net/tun not found!"
|
|
echo " Make sure to pass through /dev/net/tun to the container and add the"
|
|
echo " parameter --cap-add=NET_ADMIN to the Extra Parameters!"
|
|
error_handler
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_ADVERTISE_ROUTES}" ]; then
|
|
TAILSCALE_ADVERTISE_ROUTES="$(echo ${TAILSCALE_ADVERTISE_ROUTES} | sed 's/ //g')"
|
|
echo "Advertising custom routes! See https://tailscale.com/kb/1019/subnets#advertise-subnet-routes"
|
|
TS_PARAMS="${TS_PARAMS} --advertise-routes=${TAILSCALE_ADVERTISE_ROUTES}"
|
|
fi
|
|
|
|
if [ "${TAILSCALE_USE_SSH}" = "true" ]; then
|
|
echo "Enabling SSH! See https://tailscale.com/kb/1193/tailscale-ssh"
|
|
TS_PARAMS="${TS_PARAMS} --ssh"
|
|
fi
|
|
|
|
if [ "${TAILSCALE_LOG}" != "false" ]; then
|
|
TSD_PARAMS="${TSD_PARAMS} >>/var/log/tailscaled 2>&1 "
|
|
TSD_MSG=" with log file location: /var/log/tailscaled"
|
|
else
|
|
TSD_PARAMS="${TSD_PARAMS} >/dev/null 2>&1 "
|
|
TSD_MSG=" with logging disabled"
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_HOSTNAME}" ]; then
|
|
echo "Setting host name to \"${TAILSCALE_HOSTNAME}\""
|
|
TAILSCALE_HOSTNAME="$(echo "$TAILSCALE_HOSTNAME" | tr -d ' ')"
|
|
TS_PARAMS="${TS_PARAMS} --hostname=${TAILSCALE_HOSTNAME}"
|
|
fi
|
|
|
|
if [ "${TAILSCALE_EXIT_NODE}" = "true" ]; then
|
|
echo "Configuring container as Exit Node! See https://tailscale.com/kb/1103/exit-nodes"
|
|
TS_PARAMS="${TS_PARAMS} --advertise-exit-node"
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALED_PARAMS}" ]; then
|
|
TSD_PARAMS="${TAILSCALED_PARAMS} ${TSD_PARAMS}"
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_PARAMS}" ]; then
|
|
TS_PARAMS="${TAILSCALE_PARAMS}${TS_PARAMS}"
|
|
fi
|
|
|
|
echo "Starting tailscaled${TSD_MSG}"
|
|
eval tailscaled -statedir=${TSD_STATE_DIR} ${TSD_PARAMS}&
|
|
|
|
echo "Starting tailscale"
|
|
eval tailscale up ${TS_PARAMS} --reset
|
|
EXIT_STATUS="$?"
|
|
|
|
if [ "${EXIT_STATUS}" != "0" ]; then
|
|
echo "ERROR: Connecting to Tailscale not successful!"
|
|
if [ -f /var/log/tailscaled ]; then
|
|
echo "Please check the logs:"
|
|
tail -20 /var/log/tailscaled
|
|
fi
|
|
error_handler
|
|
fi
|
|
unset EXIT_STATUS
|
|
|
|
if [ ! -z "${TAILSCALE_SERVE_PORT}" ] && [ "$(tailscale status --json | jq -r '.CurrentTailnet.MagicDNSEnabled')" = "false" ] ; then
|
|
echo "ERROR: Enable HTTPS on your Tailscale account to use Tailscale Serve/Funnel."
|
|
echo "See: https://tailscale.com/kb/1153/enabling-https"
|
|
error_handler
|
|
fi
|
|
|
|
if [ "${TAILSCALE_EXIT_NODE}" = "true" ]; then
|
|
if [ "$(tailscale status --json | jq -r '.Self.ExitNodeOption')" = "false" ]; then
|
|
TSIP=$(tailscale status --json | jq -r '.Self.TailscaleIPs[0]')
|
|
echo "WARNING: Exit Node not yet approved."
|
|
echo " Navigate to https://login.tailscale.com/admin/machines/${TSIP} and approve it."
|
|
fi
|
|
fi
|
|
|
|
KEY_EXPIRY=$(tailscale status --json | jq -r '.Self.KeyExpiry')
|
|
if [ "${KEY_EXPIRY}" != "null" ]; then
|
|
EXPIRY_EPOCH=$(date -d "${KEY_EXPIRY}" +"%s" 2>/dev/null)
|
|
CUR_EPOCH=$(date -u +%s)
|
|
DIFF_EPOCH=$((EXPIRY_EPOCH - CUR_EPOCH))
|
|
DIFF_DAYS=$((DIFF_EPOCH / 86400))
|
|
HOST=$(tailscale status --json | jq -r '.Self.HostName')
|
|
if [ -n "${DIFF_DAYS}" ] && echo "${DIFF_DAYS}" | grep -Eq '^[0-9]+$'; then
|
|
echo "WARNING: Tailscale Key will expire in ${DIFF_DAYS} days."
|
|
echo " Navigate to https://login.tailscale.com/admin/machines and 'Disable Key Expiry' for ${HOST}"
|
|
else
|
|
echo "ERROR: Tailscale Key expired!"
|
|
echo " Navigate to https://login.tailscale.com/admin/machines and Renew/Disable Key Expiry for ${HOST}"
|
|
fi
|
|
echo "See: https://tailscale.com/kb/1028/key-expiry"
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_ADVERTISE_ROUTES}" ]; then
|
|
APPROVED_ROUTES="$(tailscale status --json | jq -r '.Self.PrimaryRoutes')"
|
|
IFS=','
|
|
set -- ${TAILSCALE_ADVERTISE_ROUTES}
|
|
ROUTES="$@"
|
|
for route in ${ROUTES}; do
|
|
if ! echo "${APPROVED_ROUTES}" | grep -q "${route}"; then
|
|
NOT_APPROVED="$NOT_APPROVED ${route}"
|
|
fi
|
|
done
|
|
if [ ! -z "${NOT_APPROVED}" ]; then
|
|
TSIP="$(tailscale status --json | jq -r '.Self.TailscaleIPs[0]')"
|
|
echo "WARNING: The following route(s) are not approved:${NOT_APPROVED}"
|
|
echo " Navigate to https://login.tailscale.com/admin/machines/${TSIP} and approve it."
|
|
fi
|
|
fi
|
|
|
|
if [ ! -z "${TAILSCALE_SERVE_PORT}" ]; then
|
|
if [ ! -z "${TAILSCALE_SERVE_PATH}" ]; then
|
|
TAILSCALE_SERVE_PATH="=${TAILSCALE_SERVE_PATH}"
|
|
fi
|
|
if [ -z "${TAILSCALE_SERVE_PROTOCOL}" ]; then
|
|
TAILSCALE_SERVE_PROTOCOL="https"
|
|
fi
|
|
if [ -z "${TAILSCALE_SERVE_PROTOCOL_PORT}" ]; then
|
|
TAILSCALE_SERVE_PROTOCOL_PORT="=443"
|
|
fi
|
|
if [ "${TAILSCALE_FUNNEL}" = "true" ]; then
|
|
echo "Enabling Funnel! See https://tailscale.com/kb/1223/funnel"
|
|
eval tailscale funnel --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} http://localhost:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy"
|
|
else
|
|
echo "Enabling Serve! See https://tailscale.com/kb/1312/serve"
|
|
eval tailscale serve --bg --"${TAILSCALE_SERVE_PROTOCOL}"${TAILSCALE_SERVE_PROTOCOL_PORT}${TAILSCALE_SERVE_PATH} http://localhost:"${TAILSCALE_SERVE_PORT}${TAILSCALE_SERVE_LOCALPATH}" | grep -v "To disable the proxy"
|
|
fi
|
|
if [ "${TAILSCALE_SERVE_PROTOCOL}" = "https" ]; then
|
|
TS_DNSNAME="$(tailscale status --json | jq -r '.Self.DNSName' | sed 's/\.$//')"
|
|
if [ ! -f "${TSD_STATE_DIR}/certs/${TS_DNSNAME}.crt" ] || [ ! -f "${TSD_STATE_DIR}/certs/${TS_DNSNAME}.key" ]; then
|
|
if [ ! -d "${TSD_STATE_DIR}/certs" ]; then
|
|
mkdir -p "${TSD_STATE_DIR}/certs"
|
|
fi
|
|
echo "Generating Tailscale certs! This can take some time, please wait..."
|
|
timeout 30 tailscale cert --cert-file="${TSD_STATE_DIR}/certs/${TS_DNSNAME}.crt" --key-file="${TSD_STATE_DIR}/certs/${TS_DNSNAME}.key" "${TS_DNSNAME}" >/dev/null 2>&1
|
|
EXIT_STATUS="$?"
|
|
if [ "${EXIT_STATUS}" != "0" ]; then
|
|
echo "ERROR: Can't generate certificates!"
|
|
echo "Please check the logs:"
|
|
tail -10 /var/log/tailscaled
|
|
else
|
|
echo "Done!"
|
|
fi
|
|
unset EXIT_STATUS
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
exec_entrypoint
|