TSDProxyを利用する方法は、Dockerで提供しているサービスを手軽にhttps化出来るので便利ですが、サービスの数だけTailscaleのノードを使用してしまいます。個人用途なら制限には引っかからないでしょうが、今度はTailscale側の管理が大変になります。
その場合は、以前にも紹介したCaddyを利用するほうが、Tailscaleへの登録は1つで済むのですっきりしますね。
前提
- TailscaleでHTTPS証明書が使える状態(管理コンソールでHTTPS Certificates有効化済み)
- Tailscaleを止めるとSSH接続が切れる可能性があるため、Tailscaleは常に動かしたまま作業する
1. Caddyインストール
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy -y
2. tailscale serveが動いていたら止める
先にCaddyを起動する前に確認・停止する。
(tailscale serveが443を占有しているとCaddyが起動できない)
# 確認
tailscale serve status
# 動いていたら停止(Tailscale自体は止めない)
sudo tailscale serve reset
3. Tailscaleのドメイン名を確認
# operator設定(以後sudoなしで使える)
sudo tailscale set --operator=$USER
# ドメイン確認
tailscale status --json | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('CertDomains','') or d.get('MagicDNSSuffix',''))"
# 例: ['dellnt.tailf682b.ts.net']
4. TLS証明書の取得
# カレントディレクトリに証明書が生成される
sudo tailscale cert ホスト名.tailXXXXX.ts.net
# Caddy用ディレクトリに移動
sudo mkdir -p /etc/caddy/certs
sudo mv ホスト名.tailXXXXX.ts.net.crt ホスト名.tailXXXXX.ts.net.key /etc/caddy/certs/
sudo chown -R caddy:caddy /etc/caddy/certs
sudo chmod 600 /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.key
sudo chmod 644 /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.crt
5. 使用中ポートの確認
# 追加したいポート帯が空いているか確認
sudo ss -tlnp | grep -E '443|4443|4444|4445'
LXDコンテナのIPも確認:
lxc list
6. Caddyfileの設定
sudo nano /etc/caddy/Caddyfile
caddyfile
# サービス1つめ(例:Linkwarden)
ホスト名.tailXXXXX.ts.net:4443 {
tls /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.crt /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.key
reverse_proxy コンテナIP:サービスのポート
}
# サービス2つめ以降は同じパターンでポートを増やす
ホスト名.tailXXXXX.ts.net:4444 {
tls /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.crt /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.key
reverse_proxy コンテナIP:サービスのポート
}
ポイント:
- ポートは
4443, 4444, 4445...と連番で増やす - LXDコンテナ内のサービスは
lxc listで確認したIPを使う - ホスト自身のサービス(Cockpitなど)はTailscale IP(
100.x.x.x:ポート)を使う - CockpitのようにHTTPS動作しているサービスは
tls_insecure_skip_verifyが必要:
caddyfile
ホスト名.tailXXXXX.ts.net:4443 {
tls /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.crt /etc/caddy/certs/ホスト名.tailXXXXX.ts.net.key
reverse_proxy https://100.x.x.x:9090 {
transport http {
tls_insecure_skip_verify
}
}
}
7. 反映・起動
# 構文チェック
sudo caddy validate --config /etc/caddy/Caddyfile
# 初回起動
sudo systemctl start caddy
sudo systemctl enable caddy
# 2回目以降の設定変更時はreload(サービスを止めずに反映)
sudo systemctl reload caddy
# 状態確認
sudo systemctl status caddy
8. サービス追加時のルーティン
# 1. 空きポート確認
sudo ss -tlnp | grep -E '4443|4444|4445|4446'
# 2. コンテナIP確認
lxc list
# 3. Caddyfileに追記
sudo nano /etc/caddy/Caddyfile
# 4. チェックして反映
sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy
トラブルシュート
| 症状 | 原因 | 対処 |
|---|---|---|
| Caddyが起動しない | ポートが使用中 | sudo ss -tlnpで確認して別ポートに変更 |
| 「安全でない」と表示 | tailscale serveが残っている | sudo tailscale serve reset |
| パスで飛ばされる | tailscale serveが443を占有 | 同上 |
| Cockpitに繋がらない | CockpitがHTTPSで動いている | tls_insecure_skip_verifyを追加 |
| 証明書エラー | 証明書の期限切れ | sudo tailscale certで再取得してreload |
おまけ:1コピペで
nano caddy-tailscale-setup.sh
# 下記を貼り付け
bash caddy-setup.sh
cat << 'SCRIPT' > caddy-setup.sh
#!/bin/bash
set -e
echo "=== Caddy + Tailscale HTTPS セットアップ ==="
# --- 1. tailscale serve 停止 ---
echo "[1/6] tailscale serve を確認・停止..."
if tailscale serve status 2>/dev/null | grep -q "proxy"; then
echo " -> tailscale serve が動いています。停止します。"
sudo tailscale serve reset
else
echo " -> tailscale serve は動いていません。スキップ。"
fi
# --- 2. Caddy インストール ---
echo "[2/6] Caddy をインストール..."
if command -v caddy &>/dev/null; then
echo " -> Caddy は既にインストール済みです。スキップ。"
else
# 壊れたリポジトリを一時退避
sudo find /etc/apt/sources.list.d/ -name "*.list" -exec grep -l "Release ファイルがありません\|InRelease\|amdgpu\|rocm" {} \; 2>/dev/null | while read f; do
sudo mv "$f" "/tmp/$(basename $f).bak" && echo " -> 退避: $f"
done
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update && sudo apt install caddy -y
fi
# --- 3. フルドメイン取得 ---
echo "[3/6] Tailscale ドメインを取得..."
sudo tailscale set --operator=$USER 2>/dev/null || true
DOMAIN=$(tailscale status --json | python3 -c "
import sys, json
d = json.load(sys.stdin)
certs = d.get('CertDomains') or d.get('MagicDNSSuffix')
if isinstance(certs, list) and certs:
print(certs[0].strip(\"[]\").strip(\"'\").strip())
elif isinstance(certs, str):
print(certs.strip())
" 2>/dev/null)
if [ -z "$DOMAIN" ]; then
echo " -> ドメイン取得に失敗しました。Tailscaleが起動しているか確認してください。"
exit 1
fi
echo " -> ドメイン: $DOMAIN"
# --- 4. TLS証明書の取得・配置 ---
echo "[4/6] TLS証明書を取得..."
sudo mkdir -p /etc/caddy/certs
cd /tmp
sudo tailscale cert "$DOMAIN"
sudo mv "/tmp/${DOMAIN}.crt" "/tmp/${DOMAIN}.key" /etc/caddy/certs/
sudo chown -R caddy:caddy /etc/caddy/certs
sudo chmod 600 "/etc/caddy/certs/${DOMAIN}.key"
sudo chmod 644 "/etc/caddy/certs/${DOMAIN}.crt"
echo " -> 証明書を /etc/caddy/certs/ に配置しました。"
# --- 5. 空きポートとDockerサービスを自動検出 ---
echo "[5/6] Dockerサービスと空きポートを検出..."
# 使用中ポートを取得
USED_PORTS=$(sudo ss -tlnp | awk '{print $4}' | grep -oE '[0-9]+$' | sort -n | uniq)
# 4443から空きポートを順番に割り当てる関数
NEXT_PORT=4443
get_next_port() {
while echo "$USED_PORTS" | grep -q "^${NEXT_PORT}$"; do
NEXT_PORT=$((NEXT_PORT + 1))
done
echo $NEXT_PORT
USED_PORTS="$USED_PORTS
$NEXT_PORT"
NEXT_PORT=$((NEXT_PORT + 1))
}
# Dockerが使えるか確認
DOCKER_BLOCKS=""
if command -v docker &>/dev/null && docker ps &>/dev/null 2>&1; then
echo " -> Dockerコンテナを検出中..."
while IFS= read -r line; do
CONTAINER=$(echo "$line" | awk '{print $NF}')
PORTS=$(echo "$line" | grep -oE '0\.0\.0\.0:[0-9]+->[0-9]+' | head -1)
if [ -n "$PORTS" ]; then
HOST_PORT=$(echo "$PORTS" | cut -d: -f2 | cut -d- -f1)
CADDY_PORT=$(get_next_port)
DOCKER_BLOCKS="${DOCKER_BLOCKS}
# ${CONTAINER}
# ${DOMAIN}:${CADDY_PORT} {
# tls /etc/caddy/certs/${DOMAIN}.crt /etc/caddy/certs/${DOMAIN}.key
# reverse_proxy localhost:${HOST_PORT}
# }
"
echo " -> ${CONTAINER}: localhost:${HOST_PORT} -> :${CADDY_PORT}"
fi
done < <(docker ps --format "table {{.Ports}}\t{{.Names}}" | tail -n +2 | grep "->")
else
DOCKER_BLOCKS="# (Dockerが見つかりませんでした。手動で追加してください。)"
fi
# --- 6. Caddyfile テンプレート生成 ---
echo "[6/6] Caddyfile を生成..."
sudo tee /etc/caddy/Caddyfile > /dev/null <<EOF
# ============================================================
# Caddy リバースプロキシ設定
# ドメイン : ${DOMAIN}
# 証明書 : /etc/caddy/certs/${DOMAIN}.crt
#
# サービス追加手順:
# 1. 空きポート確認 : sudo ss -tlnp | grep 444
# 2. コンテナIP確認 : lxc list または docker ps
# 3. 下のブロックのコメントを外して編集
# 4. sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy
#
# テンプレート(コピーして使う):
# ------------------------------------------------------------
# # サービス名
# ${DOMAIN}:XXXX {
# tls /etc/caddy/certs/${DOMAIN}.crt /etc/caddy/certs/${DOMAIN}.key
# reverse_proxy localhost:ホストポート
# }
#
# # Cockpitなどホスト上のHTTPSサービスの場合:
# ${DOMAIN}:XXXX {
# tls /etc/caddy/certs/${DOMAIN}.crt /etc/caddy/certs/${DOMAIN}.key
# reverse_proxy https://TailscaleIP:9090 {
# transport http {
# tls_insecure_skip_verify
# }
# }
# }
# ============================================================
# ---- 自動検出されたDockerサービス(コメントを外して有効化) ----
${DOCKER_BLOCKS}
EOF
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl enable caddy
sudo systemctl restart caddy
sudo systemctl --no-pager status caddy | head -20
echo ""
echo "======================================"
echo "✅ セットアップ完了!"
echo " ドメイン : ${DOMAIN}"
echo " 証明書 : /etc/caddy/certs/${DOMAIN}.crt"
echo " Caddyfile: /etc/caddy/Caddyfile"
echo ""
echo "次のステップ:"
echo " sudo nano /etc/caddy/Caddyfile でコメントを外して有効化"
echo " sudo caddy validate --config /etc/caddy/Caddyfile && sudo systemctl reload caddy"
echo "======================================"
SCRIPT
chmod +x caddy-setup.sh
echo "作成完了: ./caddy-setup.sh"
完了後は sudo nano /etc/caddy/Caddyfile を開くとコメント付きテンプレートが入っています。Dockerコンテナを自動検出してポートマッピングを読み取り、全部コメントアウト済みでCaddyfileに書き出します。使いたいサービスの#を外して reload するだけです。
Outline
なお、OutlineはDexで認証しているため、内部の設定を変更しないとうまく通信が出来ません。
Outlineの例で言えば、下記あたりで対処出来ると思います。
・docker-compose.yml で 127.0.0.1:内部ポート:コンテナポート にする
・Caddyで外部ポート → 内部ポートに中継する
・反映は reload がダメなら restart
Cockpit
Cockpitを他のマシンにも追加する場合は同じ /etc/cockpit/cockpit.conf の設定が必要です。
ログイン画面は出るけどログイン後に落ちるパターンになる可能性があります。
CockpitはWebSocketを使うので、Caddyにヘッダー設定が必要です。
また、/etc/cockpit/cockpit.conf でOriginsを許可しないとCockpit側がプロキシ経由のアクセスを拒否します。
Caddyfileのcockpitブロック
sudo nano /etc/caddy/Caddyfile
sudo mkdir -p /etc/cockpit
sudo tee /etc/cockpit/cockpit.conf > /dev/null <<EOF
[WebService]
Origins = https://ser5.tailf682b.ts.net:5557
ProtocolHeader = X-Forwarded-Proto
AllowUnencrypted = true
EOF
sudo systemctl reload cockpit


