導入済みのCockpitをTailscale serve経由に変更

導入済みのCockpitをTailscale serve機能でHTTPS化し、Tailnet内のみ公開に変更する場合のスクリプトを用意しました。HTTPS化をTailscaleで行う事によりChromeでもパスワードを保存出来るようになるほか、LAN内からのアクセスを受け付けなくすることでセキュリティも強化されます。

導入済みのCockpitをTailscale serve経由に

nano setup_cockpit_tailscale.sh
chmod +x setup_cockpit_tailscale.sh
sudo ./setup_cockpit_tailscale.sh
#!/bin/bash
# ============================================================
# 既存の Cockpit 環境を Tailscale serve 経由 HTTPS 公開に変更
#
# 方針:
#   - UFW は一切触らない(既存サービスを壊さない)
#   - BindTo + systemd socket で 127.0.0.1:19090 のみ待ち受け
#   - LAN からの直接アクセスはバインドアドレスで物理的に遮断
#   - TLS は tailscale serve が担当
#   - 既存の tailscale serve 設定は保持する
# ============================================================
set -euo pipefail

info()  { echo -e "\033[1;32m[INFO]\033[0m  $*"; }
warn()  { echo -e "\033[1;33m[WARN]\033[0m  $*"; }
error() { echo -e "\033[1;31m[ERROR]\033[0m $*" >&2; exit 1; }

# ============================================================
# 前提チェック
# ============================================================
command -v tailscale >/dev/null 2>&1 || error "tailscale が見つかりません。先にインストールしてください。"

info "tailscale の状態を確認しています..."

TS_INFO=$(tailscale status --json 2>/dev/null | python3 -c "
import sys, json
d = json.load(sys.stdin)
state = d.get('BackendState', '')
name  = d.get('Self', {}).get('DNSName', '').rstrip('.')
ip    = (d.get('Self', {}).get('TailscaleIPs') or [''])[0]
print(state)
print(name or ip)
" 2>/dev/null) || error "tailscale status の取得に失敗しました。"

TS_STATE=$(echo "$TS_INFO" | sed -n '1p')
TAILSCALE_HOST=$(echo "$TS_INFO" | sed -n '2p')

info "BackendState: ${TS_STATE}"
info "Tailscale ホスト: ${TAILSCALE_HOST}"

if [[ "$TS_STATE" != "Running" ]]; then
  error "tailscale が Running 状態ではありません(現在: ${TS_STATE})。'sudo tailscale up' を実行してください。"
fi
if [[ -z "$TAILSCALE_HOST" ]]; then
  error "Tailscale のホスト名/IPを取得できませんでした。"
fi

# Cockpit がインストールされているか確認
if ! systemctl list-unit-files cockpit.socket &>/dev/null; then
  error "cockpit.socket が見つかりません。Cockpit がインストールされているか確認してください。"
fi

# ============================================================
# 1. cockpit.conf を更新
# ============================================================
info "Cockpit の設定を書き込みます..."

sudo mkdir -p /etc/cockpit
sudo tee /etc/cockpit/cockpit.conf > /dev/null << EOF
[WebService]
Origins = https://${TAILSCALE_HOST}:9090 https://localhost:9090
AllowUnencrypted = true
EOF

# ============================================================
# 2. systemd socket を 127.0.0.1:19090 に上書き
#
#    cockpit.conf の Port/BindTo より systemd socket の
#    ListenStream が優先されるため、socket 側で確実に制御する
# ============================================================
info "cockpit.socket を 127.0.0.1:19090 に設定します..."

sudo mkdir -p /etc/systemd/system/cockpit.socket.d
sudo tee /etc/systemd/system/cockpit.socket.d/override.conf > /dev/null << EOF
[Socket]
ListenStream=
ListenStream=127.0.0.1:19090
EOF

# daemon-reload → socket を完全停止 → 再起動(設定確実反映のため stop が重要)
sudo systemctl daemon-reload
sudo systemctl stop cockpit.socket cockpit.service 2>/dev/null || true
sudo systemctl enable --now cockpit.socket

info "Cockpit を 127.0.0.1:19090 で起動しました。"

# 本当に 127.0.0.1:19090 だけで LISTEN しているか確認
LISTEN_CHECK=$(sudo ss -tlnp | grep "19090" || true)
if [[ -z "$LISTEN_CHECK" ]]; then
  warn "19090 で LISTEN していません。'sudo systemctl status cockpit.socket' を確認してください。"
elif echo "$LISTEN_CHECK" | grep -qv "127.0.0.1:19090"; then
  warn "19090 が 127.0.0.1 以外でも LISTEN しています!設定を確認してください。"
  echo "$LISTEN_CHECK"
else
  info "確認OK: 127.0.0.1:19090 のみで LISTEN しています。"
fi

# ============================================================
# 3. tailscale serve に :9090 → localhost:19090 を追加
#    既存の設定は保持する
# ============================================================
info "tailscale serve の設定を確認・追加します..."

echo ""
echo "----- 既存の tailscale serve 設定 -----"
tailscale serve status 2>/dev/null || echo "(設定なし)"
echo "----------------------------------------"
echo ""

if tailscale serve status 2>/dev/null | grep -q "proxy http://localhost:19090"; then
  info ":9090 → localhost:19090 はすでに設定されています。スキップします。"
elif tailscale serve status 2>/dev/null | grep -q ":9090"; then
  warn ":9090 に別の設定があります。上書きします..."
  sudo tailscale serve --bg --https=9090 http://localhost:19090
else
  sudo tailscale serve --bg --https=9090 http://localhost:19090
  info "tailscale serve に :9090 を追加しました。"
fi

# funnel(インターネット公開)が有効なら警告
if tailscale funnel status 2>/dev/null | grep -q ":9090"; then
  warn "!!! :9090 に tailscale funnel が設定されています(インターネット公開状態)!!!"
  warn "無効化するには: sudo tailscale funnel --https=9090 off"
fi

# ============================================================
# 4. 動作確認
# ============================================================
echo ""
info "最終確認..."
echo ""

echo "----- LISTEN ポート確認 -----"
sudo ss -tlnp | grep -E "19090|9090" || true

echo ""
echo "----- tailscale serve 設定 -----"
tailscale serve status

echo ""
echo "======================================================"
echo " 設定完了!"
echo "======================================================"
echo ""
echo " アクセス先(Tailnet 内のみ):"
echo "   https://${TAILSCALE_HOST}:9090/"
echo ""
echo " セキュリティ:"
echo "   - Cockpit バックエンド : 127.0.0.1:19090(LAN 到達不可)"
echo "   - TLS 終端            : tailscale serve (:9090)"
echo "   - インターネット公開  : tailscale funnel 未設定"
echo "   - UFW                 : 変更なし(既存サービス影響なし)"
echo "======================================================"

最初からTailscale経由のみに設定してCockpitをインストールする

#!/bin/bash
# ============================================================
# Cockpit を Tailscale serve 経由で HTTPS 公開するスクリプト
#
# 方針:
#   - UFW は一切触らない(既存サービスを壊さない)
#   - BindTo + systemd socket で 127.0.0.1:19090 のみ待ち受け
#   - LAN からの直接アクセスはバインドアドレスで物理的に遮断
#   - TLS は tailscale serve が担当
# ============================================================
set -euo pipefail

info()  { echo -e "\033[1;32m[INFO]\033[0m  $*"; }
warn()  { echo -e "\033[1;33m[WARN]\033[0m  $*"; }
error() { echo -e "\033[1;31m[ERROR]\033[0m $*" >&2; exit 1; }

# ============================================================
# 前提チェック
# ============================================================
command -v tailscale >/dev/null 2>&1 || error "tailscale が見つかりません。先にインストールしてください。"

info "tailscale の状態を確認しています..."

TS_INFO=$(tailscale status --json 2>/dev/null | python3 -c "
import sys, json
d = json.load(sys.stdin)
state = d.get('BackendState', '')
name  = d.get('Self', {}).get('DNSName', '').rstrip('.')
ip    = (d.get('Self', {}).get('TailscaleIPs') or [''])[0]
print(state)
print(name or ip)
" 2>/dev/null) || error "tailscale status の取得に失敗しました。"

TS_STATE=$(echo "$TS_INFO" | sed -n '1p')
TAILSCALE_HOST=$(echo "$TS_INFO" | sed -n '2p')

info "BackendState: ${TS_STATE}"
info "Tailscale ホスト: ${TAILSCALE_HOST}"

if [[ "$TS_STATE" != "Running" ]]; then
  error "tailscale が Running 状態ではありません(現在: ${TS_STATE})。'sudo tailscale up' を実行してください。"
fi
if [[ -z "$TAILSCALE_HOST" ]]; then
  error "Tailscale のホスト名/IPを取得できませんでした。"
fi

# ============================================================
# 1. Cockpit インストール
# ============================================================
info "Cockpit をインストールします..."
sudo apt install -y cockpit cockpit-machines

# ============================================================
# 2. cockpit.conf を配置(systemd 起動前に済ませる)
# ============================================================
info "Cockpit の設定を書き込みます..."

sudo mkdir -p /etc/cockpit
sudo tee /etc/cockpit/cockpit.conf > /dev/null << EOF
[WebService]
Origins = https://${TAILSCALE_HOST}:9090 https://localhost:9090
AllowUnencrypted = true
EOF

# ============================================================
# 3. systemd socket を 127.0.0.1:19090 に上書き
#
#    cockpit.conf の Port/BindTo より systemd socket の
#    ListenStream が優先されるため、socket 側で確実に制御する
# ============================================================
info "cockpit.socket を 127.0.0.1:19090 に設定します..."

sudo mkdir -p /etc/systemd/system/cockpit.socket.d
sudo tee /etc/systemd/system/cockpit.socket.d/override.conf > /dev/null << EOF
[Socket]
ListenStream=
ListenStream=127.0.0.1:19090
EOF

# daemon-reload → socket を完全停止 → 再起動(設定確実反映のため stop が重要)
sudo systemctl daemon-reload
sudo systemctl stop cockpit.socket cockpit.service 2>/dev/null || true
sudo systemctl enable --now cockpit.socket

info "Cockpit を 127.0.0.1:19090 で起動しました。"

# 本当に 127.0.0.1:19090 だけで LISTEN しているか確認
LISTEN_CHECK=$(sudo ss -tlnp | grep "19090" || true)
if [[ -z "$LISTEN_CHECK" ]]; then
  warn "19090 で LISTEN していません。'sudo systemctl status cockpit.socket' を確認してください。"
elif echo "$LISTEN_CHECK" | grep -qv "127.0.0.1:19090"; then
  warn "19090 が 127.0.0.1 以外でも LISTEN しています!設定を確認してください。"
  echo "$LISTEN_CHECK"
else
  info "確認OK: 127.0.0.1:19090 のみで LISTEN しています。"
fi

# ============================================================
# 4. tailscale serve に :9090 → localhost:19090 を追加
#    既存の設定は保持する
# ============================================================
info "tailscale serve の設定を確認・追加します..."

echo ""
echo "----- 既存の tailscale serve 設定 -----"
tailscale serve status 2>/dev/null || echo "(設定なし)"
echo "----------------------------------------"
echo ""

if tailscale serve status 2>/dev/null | grep -q "proxy http://localhost:19090"; then
  info ":9090 → localhost:19090 はすでに設定されています。スキップします。"
elif tailscale serve status 2>/dev/null | grep -q ":9090"; then
  warn ":9090 に別の設定があります。上書きします..."
  sudo tailscale serve --bg --https=9090 http://localhost:19090
else
  sudo tailscale serve --bg --https=9090 http://localhost:19090
  info "tailscale serve に :9090 を追加しました。"
fi

# funnel(インターネット公開)が有効なら警告
if tailscale funnel status 2>/dev/null | grep -q ":9090"; then
  warn "!!! :9090 に tailscale funnel が設定されています(インターネット公開状態)!!!"
  warn "無効化するには: sudo tailscale funnel --https=9090 off"
fi

# ============================================================
# 5. 動作確認
# ============================================================
echo ""
info "最終確認..."
echo ""

echo "----- LISTEN ポート確認 -----"
sudo ss -tlnp | grep -E "19090|9090" || true

echo ""
echo "----- tailscale serve 設定 -----"
tailscale serve status

echo ""
echo "======================================================"
echo " セットアップ完了!"
echo "======================================================"
echo ""
echo " アクセス先(Tailnet 内のみ):"
echo "   https://${TAILSCALE_HOST}:9090/"
echo ""
echo " セキュリティ:"
echo "   - Cockpit バックエンド : 127.0.0.1:19090(LAN 到達不可)"
echo "   - TLS 終端            : tailscale serve (:9090)"
echo "   - インターネット公開  : tailscale funnel 未設定"
echo "   - UFW                 : 変更なし(既存サービス影響なし)"
echo "======================================================"
タイトルとURLをコピーしました