TL;DR
この記事は、フラッシュメモリの容量がそこそこ(潤沢でも極少でもない)の OpenWrt 機器で Tailscale のアップデートをするための手順です。
(具体的には、 df -h /overlay
での Size
表示が、 40MB ~ 80MB の OpenWrt 機器を想定しています。)
より厳しい容量環境下の場合、以下の記事を参考にしてください。
- Tailscale をインストールすると、ほとんど空き容量に余裕がなくなる → OpenWrt で縮小版 Tailscale を使用する
- Tailscale をインストールしなくても、10MB 程度の空き容量しかない → フラッシュメモリの空き容量が 10MB しかない OpenWrt で Tailscale を使用する
この記事の概要
フラッシュメモリの空き容量に余裕があれば、 OpenWrt 機器でも tailscale update
で簡単に Tailscale のアップデートができるのですが、多くの OpenWrt 機器では tailscale update
を実行するのに必要なフラッシュメモリがありません。
そこで以下の手順を実行するコードを作成したので紹介します。
- Tailscale の停止 (
service tailscale stop
の実行) - バイナリファイルを削除 (
/usr/sbin/tailscale
,/usr/sbin/tailscaled
の削除) - https://pkgs.tailscale.com/stable/#static から tgz ファイルをダウンロード
- tgz ファイルを解凍しバイナリファイル (
tailscale
,tailscaled
) を/usr/sbin/
に保存 - Tailscale の再開 (
service tailscale start
の実行)
参考にしたコード
もともとは @myurar1a さんが書かれたコードを使って Tailscale のアップデートをしていたのですが、 Tailscale 再開時のオプション指定は不要なため、そこを考慮して @hide_seki さんが書かれた改良部分を取り入れてアップデートしました。
手順としては、Perplexity に相談しながらコードを書き、最終的には GPT-4o に英文への翻訳・校正とリファクタリングをしてもらっています。🎉
👉 公式のアップデート手順の `tailscale update` を実行し、 `no space left on device` が表示されてしまった場合の対応手順 😱
以下のコマンドを実行
rm /root/.cache/tailscale-update/tailscale*.tgz
rm /usr/sbin/tailscale*.new
ファイルの削除前後に df -h
を実行して、空き容量が回復することを確認してください。🎉
注意事項
-
今回のコードは 64-bit ARM CPU でしか動作しません。
64-bit ARM CPU に限定した理由は以下の通り。- MIPS 系の CPU では Tailscale の実行は重すぎるはずなので、MIPS 系の CPU は除外
- 32-bit ARM CPU は世代的に古く、現行の MIPS 以上に演算能力が低いので、こちらも除外
- AMD64 の CPU であれば、
tailscale update
が実行できる程度に容量に余裕があるはずなので、これも除外
-
Tailscale を使って SSH 接続していても今回のコードの実行はできますが、以下の表示が出た後 1 分程度反応がなくなるはずです。
(Subnet route 経由でも同様です。)👉
service tailscale stop
が実行された時点でいったん接続が切れますが、そのまま待っていれば回復するはずです。logpolicy: using system state directory "/var/lib/tailscale" dns: [rc=unknown ret=direct] dns: using "direct" mode dns: using *dns.directManager dns: inotify addwatch: context canceled linuxfw: clear ip6tables: exec: "ip6tables": executable file not found in $PATH flushing log. logger closing down
-
コードの最後で実行される
tailscale set --auto-update=false
によって、 Tailscale の自動アップデートを無効化しています。👉
auto-update
を無効化する理由は、Auto-updates
のOn
/Off
は Tailnet ごとに設定されるため、誤って適用されてしまい、知らないうちにno space left on device
となってしまうことを避けるためです。
-
curl
もjq
も使っていないので、素の OpenWrt で動作します。🎉
使用方法
以下のコードを
-
/etc/config/update_tailscale.sh
に保存して -
chmod +x /etc/config/update_tailscale.sh
で実行権限を付与します
#!/bin/sh
ARCH=arm64
# Determine if the device is running OpenWrt by checking for the existence of `/etc/openwrt_release`
openwrt_exists=false
if [ -f /etc/openwrt_release ]; then
openwrt_exists=true
fi
# Determine if the CPU architecture is ARM64 by checking if `aarch64` is part of `uname -a` output
is_arm64=false
if uname -a | grep -q 'aarch64'; then
is_arm64=true
fi
# Verify compatibility: Must be an OpenWrt device running on a 64-bit ARM CPU
if [ "$openwrt_exists" = false ] || [ "$is_arm64" = false ]; then
echo "This program can only be executed on OpenWrt devices running on 64-bit ARM CPUs."
exit 1
fi
API_URL="https://api.github.com/repos/tailscale/tailscale/releases/latest"
# Retrieve the currently installed Tailscale version
current_version=$(tailscale version | head -1)
echo "Current Tailscale version: $current_version"
# Fetch the latest available Tailscale version
latest_version=$(wget -q -O - "$API_URL" | sed -n 's/.*"tag_name":"v\([^"]*\)".*/\1/p')
echo "Latest Tailscale version: $latest_version"
# Compare versions and handle the update process
if [ "$current_version" = "$latest_version" ]; then
echo "You are already using the latest Tailscale version ($latest_version)."
exit 0
fi
package_name="tailscale_${latest_version}_${ARCH}"
package_url="https://pkgs.tailscale.com/stable/${package_name}.tgz"
# Check availability of the latest package
if wget --spider "$package_url" 2>/dev/null; then
echo "An update to Tailscale $latest_version is available."
else
echo "The latest version $latest_version is not available."
exit 0
fi
# Prompt the user for an update confirmation
echo "Do you want to update? (y/n)"
read -r answer
case $answer in
[nN])
echo "Update canceled."
exit 0
;;
*)
echo "Proceeding with the update."
;;
esac
# Uninstall current Tailscale
echo "Uninstalling current version of Tailscale..."
service tailscale stop
rm /usr/sbin/tailscale /usr/sbin/tailscaled
echo "Uninstall complete."
# Download the latest package
echo "Downloading Tailscale $latest_version..."
wget "$package_url" -O /tmp/tailscale.tgz
echo "Extracting package..."
# Install the new version
echo "Installing Tailscale $latest_version..."
tar zxvf /tmp/tailscale.tgz ${package_name}/tailscale -C /tmp
cp /tmp/${package_name}/tailscale /usr/sbin
rm -r /tmp/${package_name}
tar zxvf /tmp/tailscale.tgz ${package_name}/tailscaled -C /tmp
cp /tmp/${package_name}/tailscaled /usr/sbin
rm -r /tmp/${package_name}
rm /tmp/tailscale.tgz
echo "Installation complete."
# Start and configure Tailscale
service tailscale start
tailscale set --auto-update=false
echo
echo "Now you are using the latest Tailscale version ($latest_version)!"
👉 コードを /etc/config/
内に保存する理由は、System
> Backup
で設定のバックアップ(archive)を作成する際、 /etc/config/
はバックアップファイルに含まれるためです。
ちなみに OpenAI o1 に書いてもらったコードはこちら。
- tgz ファイルを 1 回で解凍しているため、@hide_seki さんの改良部分が無効化されています。😱
- そのままでは動かなかったため、2 箇所修正しています。 (
CURRENT_VERSION
とLATEST_VERSION
の取得)
#!/bin/sh
# Script to update Tailscale on OpenWrt devices with 64-bit ARM CPUs
# Constants
ARCH="arm64"
API_URL="https://api.github.com/repos/tailscale/tailscale/releases/latest"
PACKAGE_BASE_URL="https://pkgs.tailscale.com/stable"
# Function to check system requirements
check_requirements() {
# Ensure the script is running on OpenWrt
if [ ! -f /etc/openwrt_release ]; then
echo "Error: This script must be run on an OpenWrt device."
exit 1
fi
# Ensure the CPU architecture is 64-bit ARM
if [ "$(uname -m)" != "aarch64" ]; then
echo "Error: This script can only be executed on devices with 64-bit ARM CPUs (aarch64)."
exit 1
fi
}
# Function to get the current Tailscale version
get_current_version() {
CURRENT_VERSION=$(tailscale version | head -1)
if [ -z "$CURRENT_VERSION" ]; then
echo "Error: Could not determine the current Tailscale version."
exit 1
fi
echo "Current Tailscale version: ${CURRENT_VERSION}"
}
# Function to get the latest Tailscale version from GitHub
get_latest_version() {
LATEST_VERSION=$(wget -q -O - "$API_URL" | sed -n 's/.*"tag_name":"v\([^"]*\)".*/\1/p')
if [ -z "$LATEST_VERSION" ]; then
echo "Error: Unable to retrieve the latest Tailscale version."
exit 1
fi
echo "Latest Tailscale version available: ${LATEST_VERSION}"
}
# Function to compare versions and decide if an update is needed
compare_versions() {
if [ "$CURRENT_VERSION" = "$LATEST_VERSION" ]; then
echo "You are already using the latest Tailscale version (${LATEST_VERSION})."
exit 0
fi
PACKAGE_NAME="tailscale_${LATEST_VERSION}_${ARCH}"
PACKAGE_URL="${PACKAGE_BASE_URL}/${PACKAGE_NAME}.tgz"
# Check if the package for the latest version is available
if ! wget --spider "$PACKAGE_URL" 2>/dev/null; then
echo "Error: Tailscale version ${LATEST_VERSION} is not available for architecture ${ARCH}."
exit 1
fi
echo "An update to Tailscale ${LATEST_VERSION} is available."
}
# Function to prompt the user for an update
prompt_update() {
echo -n "Do you want to update to Tailscale ${LATEST_VERSION}? (y/N): "
read -r ANSWER
case "$ANSWER" in
[yY][eE][sS]|[yY])
echo "Proceeding with the update..."
;;
*)
echo "Update canceled."
exit 0
;;
esac
}
# Function to uninstall the current Tailscale version
uninstall_tailscale() {
echo "Uninstalling the current Tailscale version..."
service tailscale stop
rm -f /usr/sbin/tailscale /usr/sbin/tailscaled
echo "Uninstallation complete."
}
# Function to install the new Tailscale version
install_tailscale() {
echo "Downloading Tailscale ${LATEST_VERSION}..."
TEMP_TGZ="/tmp/tailscale.tgz"
PACKAGE_NAME="tailscale_${LATEST_VERSION}_${ARCH}"
PACKAGE_URL="${PACKAGE_BASE_URL}/${PACKAGE_NAME}.tgz"
if ! wget "$PACKAGE_URL" -O "$TEMP_TGZ"; then
echo "Error: Failed to download Tailscale package."
exit 1
fi
echo "Extracting package..."
if ! tar -zxf "$TEMP_TGZ" -C /tmp; then
echo "Error: Failed to extract Tailscale package."
exit 1
fi
echo "Installing Tailscale binaries..."
if ! cp "/tmp/${PACKAGE_NAME}/tailscale" "/usr/sbin/"; then
echo "Error: Failed to install 'tailscale' binary."
exit 1
fi
if ! cp "/tmp/${PACKAGE_NAME}/tailscaled" "/usr/sbin/"; then
echo "Error: Failed to install 'tailscaled' binary."
exit 1
fi
# Clean up temporary files
rm -rf "/tmp/${PACKAGE_NAME}"
rm -f "$TEMP_TGZ"
echo "Installation of Tailscale ${LATEST_VERSION} complete."
}
# Function to start Tailscale service
start_tailscale() {
echo "Starting Tailscale service..."
service tailscale start
tailscale set --auto-update=false
echo "Tailscale is up and running."
}
# Main script execution
check_requirements
get_current_version
get_latest_version
compare_versions
prompt_update
uninstall_tailscale
install_tailscale
start_tailscale
Tailscale の設定の確認方法
方法 1. tailscale debug prefs
以下のコマンドで Tailscale の設定状況を確認できます。
tailscale debug prefs
方法 2. tailscale status --json | sed -n '/Self/,/}/p'
tailscale status --json
を以下のように整形すると、現在のノードの設定状況が確認できます。
tailscale status --json | sed -n '/Self/,/}/p'
Tailscale が外部に対してどのポートを使用しているかは、 tailscale status --json | sed -n '/Self/,/}/p' | sed -n '/Addrs/,/]/p'
で確認できます。
👉 Nested tailscale では、ポートが競合して通信が不能になってしまう場合があります。
Tailscale の設定方法
稼働中の Tailscale で設定の変更を行う場合は、 tailscale up
ではなく tailscale set
を使用する
実行例.
tailscale set --advertise-routes=10.0.0.0/8,192.168.0.0/24 --accept-routes --advertise-exit-node
# 以下のように一つずつ設定することもできます。
tailscale set --accept-routes
tailscale set --advertise-exit-node
tailscale set --advertise-routes=10.0.0.0/8,192.168.0.0/24
# 初めて `tailscale up` を実行する時は、以下のように実行して大丈夫です。
tailscale up --advertise-routes=10.0.0.0/8,192.168.0.0/24 --accept-routes --advertise-exit-node
tailscale set
は 2022 年 12 月に 1.34.0 で導入されました。
全ての設定をデフォルト値に戻す場合は tailscale up --reset
を使用する
--reset
オプションは tailscale set
にはなく、tailscale up
にしかないため、全ての設定をデフォルト値に戻したい場合は tailscale up --reset
を使用します。
Tailscale 導入後に OpenWrt で opkg update
ができなくなった場合 (DNS 解決エラー)
私の場合は、 Network
> Interfaces
で wan6
を停止したところ、
正常に opkg update
が実行できるようになったため、 wan6
を削除しました。
OpenWrt Forum や Reddit でも、 Tailscale インストール後に DNS が使えなくなったというスレッドがあります。
OpenWrt の時刻がずれている場合も opkg update
に失敗します
OpenWrt の時刻がずれていても opkg update
に失敗するので、 ntpd -q -p 0.openwrt.pool.ntp.org
を System
> Startup
> Local Startup
に追記して、OpenWrt を再起動した後でも時刻がずれないように設定しましょう。