どっかの元高専生の技術備忘録

10割自分の備忘録用のブログ。

tailscaleをDocker上で動かして、tsdproxyでSSL化する方法

やりたいこと

tailscaleを使っているので、せっかくなら自宅鯖のDocker上で動かしているサービスを全部SSL化したい

目次

tsdproxyについて

公式からの引用

TSDProxyはTailscaleネットワークの仮想アドレスへのプロキシを自動的に作成するアプリケーションです。Dockerコンテナのラベルまたはシンプルなプロキシリストファイルに基づいて、簡単に設定およびデプロイできます。サービスごとに個別のTailscaleコンテナを用意することなく、Dockerコンテナ内で実行されているサービスへのトラフィックのリダイレクトを簡素化します。

今回は、tsdproxyをDocker上で動作させ、新たにproxyという名前のdocker networkを作成します。
このネットワークに参加し、tsdproxy用のラベルをつけられたコンテナは自動的にtailnetにノードとして参加します。
tailnet間をSSLで通信させるため、tsdproxyを介してサービスのSSL化しようという魂胆です。 また、コンフィグファイルで設定しない限り、80, 443以外でリバースしないので注意してください。

環境

  • OS: Ubuntu Server 24.04.2 LTS
  • tailnet name: hoge-fuga.ts.net

0. Dockerのインストール

すでにインストールされている人は読み飛ばしてください
以下のコマンドを叩いてDocker EngineとDocker Composeをインストールします

0.1 リポジトリの登録

$ sudo apt update
$ sudo apt install ca-certificates curl
$ sudo install -m 0755 -d /etc/apt/keyrings
$ sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
$ sudo chmod a+r /etc/apt/keyrings/docker.asc
$ echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
$ sudo apt update

0.2 Dockerのインストール

$ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

1. tailcaleの設定

1.1 API鍵の作成

tsdproxyで使用するAPI鍵を作成します
これは、コンテナをtailnetに参加させる際、ノードとして登録する際に使用されます
tailscaleのダッシュボードの、Settings->Personal Settings->KeysからGenerate auth key...を押します
そうすると、以下の画面になるので各項目に値を入れていきます

  • Description: このAPI鍵の説明になるのでわかりやすい名前をいれてください
  • Reusable: 1度きりの使い捨てでなく、何回も使用できるようにする設定です。dockerコンテナを立ち上げるたびに鍵を使用して登録しに行くのでON推奨です
  • Expiration: 鍵が使用できる有効期限です。無期限にはできないので1~90日でお好きに決めてください
  • Ephemeral: ノードがオフラインになった際に自動的にノードを削除するかの設定です。dockerコンテナを削除した際に手動での削除が必要になるので、ON推奨です
  • Tags: この鍵を使用して登録されたノードに、タグを割り当てる設定です。タグベースでACLを設定したい等の場合に設定してください

これでGenerateをクリックすると tskey-auth-XXXXXXXの形式でAPI鍵が発行されるので、コピーしておきます

1.2 MagicDNSとHTTPS Certificatesの有効化

すでに有効化されている人は読み飛ばしてください
tailscaleのダッシュボードの、DNSからMagicDNSとHTTPS CertificatesをEnable...を押して有効化してください

MagicDNSとは

tailnet内のIPアドレス(100.X.X.X)だけでなく、各ノードに割り当てられた名前だけでアクセスできるようにする機能です
例えば、以下のようなノードが登録されていた場合、 - 名前: test - IP: 100.100.100.100 tailnetに参加している各ノードは 100.100.100.100, test, test.hoge-fuga.ts.netどれでもアクセスできるようになります
(省略してるけどもちろんIPv6でも可能)

HTTPS Certificates

tailnet内に参加しているマシンでSSL通信を行うために、証明書を作成することができるようになります
公式ドキュメントには、tailscale certコマンドを使用して証明書を作成できる旨が書かれていますが、tsdproxyが勝手にやってくれます

2. tsdproxyのデプロイ

2.1 proxyネットワークの作成

以下のコマンドを叩いてproxyという名前のdocker networkを作成します
これは、物理NICのブリッジアダプタとして動作します

$ sudo docker network create -d bridge proxy

2.2 compose.yamlの作成

適当なフォルダにcompose.yamlを作成し、以下のコードを貼り付けます 今回は説明のために、 ~/tsdproxyフォルダに作成した体で進めていきます

$ mkdir ~/tsdproxy
$ touch ~/tsdproxy/compose.yaml
$ nano ~/tsdproxy/compose.yaml
version: "3.8"
services:
  tsdproxy:
    image: almeidapaulopt/tsdproxy:latest
    container_name: tsdproxy
    restart: unless-stopped # dockerの起動ポリシー設定, docker compose stopを叩かない限り基本的に再起動してくる
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./tsdproxy_data:/data
      - ./tsdproxy_config:/config
    networks:
      - proxy # 外部ネットワークへの参加, 別途networksで定義する必要がある
    labels:
      - tsdproxy.name=tsdproxy # [ここに入力した名前].hoge-fuga.ts.netでアクセスできるようになる
      - tsdproxy.enable=true # tsdproxyの有効化
      - tsdproxy.container_port=8080 # コンテナ内でリッスンしているポート、tsdproxyのダッシュボードは8080でリッスンするので8080を設定
    environment:
      - TS_AUTHKEY=${TS_AUTHKEY} # tailsclaeのAPI鍵を.envから設定する
volumes:
  tsdproxy_data: null
networks:
  proxy:
    external: true # 外部ネットワークの設定, tsdproxyと同じネットワークを定義する

2.3 .envファイルの作成

次に、TS_AUTHKEYを設定するための.envファイルを作成します

$ touch ~/tsdproxy/.env
$ nano ~/tsdproxy/.env
TS_AUTHKEY=[コピーしてきたtailscaleのAPI鍵]

2.4 tsdproxyの起動

以下のコマンドでcompose.yamlからtsdporxyを起動させます

$ cd ~/tsdproxy
$ sudo docker compose up

3. tsdproxyのダッシュボードについて

tsdproxyが起動すると、[ラベルに入力した名前].hoge-fuga.ts.net (例通りならtsdporxy.hoge-fuga.ts.net)にアクセスすると、ダッシュボードが表示されます
アドレスバーを見ると、HTTPSで通信していることが確認できます
tsdproxyでプロキシするサービスを追加すると、勝手にこのダッシュボード上に表示されるようになります

4. tsdproxyでプロキシするコンテナの追加方法

tsdproxyでプロキシするコンテナを追加するには、対象のコンテナをtsdproxyと同じdocker networkに参加させ、
規定のラベルを設定する必要があります
例として、DockerコンテナをWeb GUIから管理できるDockgeを導入し、tsdproxyでプロキシしてみようと思います

version: "3.8"
services:
  dockge:
    image: louislam/dockge:1
    restart: unless-stopped
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./data:/app/data
      # Stacks Directory
      # ⚠️ READ IT CAREFULLY. If you did it wrong, your data could end up writing into a WRONG PATH.
      # ⚠️ 1. FULL path only. No relative path (MUST)
      # ⚠️ 2. Left Stacks Path === Right Stacks Path (MUST)
      - /home/hogefuga/Docker:/home/hogefuga/Docker
    environment:
      # Tell Dockge where to find the stacks
      - DOCKGE_STACKS_DIR=/home/hogefuga/Docker
    networks:
      - proxy # 外部ネットワークへの参加, 別途networksで定義する必要がある
    labels:
      - tsdproxy.name=dockge # [ここに入力した名前].hoge-fuga.ts.netでアクセスできるようになる
      - tsdproxy.enable=true # tsdproxyの有効化
      - tsdproxy.container_port=5001 # コンテナ内でリッスンしているポート、dockgeのダッシュボードは5001でリッスンするので5001を設定
networks:
  proxy:
    external: true # 外部ネットワークの設定, tsdproxyと同じネットワークを定義する

使用できるラベルについては、公式ドキュメントを参考にしてください

almeidapaulopt.github.io

5. HTTPS接続を前提とするサービスに接続しようとしたとき、502エラーが帰ってくる場合

こちらの記事を参考にしてください

datsuka-qwerty.hatenablog.com