Closed5

Docker + Tailscale で Fediverse Instances のテスト環境を構築する

にゃるら / カラクリスタにゃるら / カラクリスタ

追記: 2024-03-01

ここでの内容は、

https://zenn.dev/nyarla/articles/how-to-setup-fediverse-inside-tailscale

にまとめているので、この Scrap は close しています。

始めに

この Scrap は、

  • Docker コンテナに Tailscale を詰め込む
  • Mastodon, Misskey and GoToSocial を Docker コンテナで動かす
  • Mastodom, Misskey and GoToSocial 間で ActivityPub S2S 通信を動作させる

と言う事を実現するために何をやったか、と言うメモです。

色々と試行錯誤した結果を書いているメモなので、たぶん間違いとか色々あると思います。

ここのメモの内容を完了するとどうなるか

  • https://{software}.tail{id}.ts.net と言う URL で各インスタンスにアクセスできる
  • Mastodon と Misskey、GoToSocial 間で ActivityPub による相互通信ができる
  • アカウントを作ったり動作テストをやったりと色々できる

注意点

Tailscale 環境下で Fedivese Software を動かす際の重要な注意点

下記コメントでの 前提 でも書いてありますが、Fediverse Software のいくつか(?)は Server-Side Request Forgery を防ぐために、Private Network での S2S 通信を禁止しています。

そのため Tailscale 環境下でこの点を回避するためにはこの禁止規定を解除する必要がありますが、当然セキュアでは無いので、本番環境で使わないで下さい。

ちなみに今回は S2S 通信の挙動改善のためのローカル環境構築なので、セキュリティチェックは無効にしています。

Misskey と GoToSocial の ActivityPub 通信について

Misskey と GoToSocial の ActivityPub 通信については、Misskey 側で、

.config/default.yml
# Sign to ActivityPub GET request (default: true)
signToActivityPubGet: true

の設定が無いとそもそも通信が上手くいかない。

※ ちなみに今回の環境構築はこの点を GoToSocial 側の改変なんとかするのが目的です

にゃるら / カラクリスタにゃるら / カラクリスタ

前提

Tailscale 下で Fediverse Software を動かすための注意点

  • まず Fediverse Software の中には private network での S2S を禁止しているものがある
    • 手持ちの環境で確認したのは以下
      • Mastodon
      • GoToSocial
    • これは Server-Side Request Forgery を攻撃を防ぐため
    • なんだけど、Tailscale の IP range は 100.64.0.0/10 である
      • そのため Tailscale 下でこの辺りを動かそうとするとこれに引っ掛かる
    • そのため今回の Scrap の中ではこの制約にパッチを当てて回避している
      • しかしこれはローカルでのテストを目的としたもの
      • なので 公開環境では絶対にやってはいけない

Tailscale を Docker コンテナ内で動かすための Dockerfile など

参考にしたリポジトリ

https://github.com/lpasselin/tailscale-docker/

Dockerfile

Dockerfile
FROM tailscale/tailscale:unstable

COPY bin /opt/bin
RUN chmod +x /opt/bin/*.sh

bin 以下

何をしているか

基本的には /usr/local/bin/containerboot &tailscale/tailscale:unstable のコンテナ内の tailscale 一式を動かし、次いで tailscale serve で http への reverse proxy を動かしている。

今のところこう言う感じのスクリプトを置いている

bin/gotosocial.sh
#!/bin/ash
trap 'kill -TERM $PID' TERM INT
echo "Starting Tailscale daemon"

/usr/local/bin/containerboot &
PID=$!
wait ${PID}

until tailscale --socket /tmp/tailscaled.sock serve https:443 / http://127.0.0.1:3000 ; do
  sleep 0.1
done

wait ${PID}
bin/mastodon.sh
#!/bin/ash
trap 'kill -TERM $PID' TERM INT
echo "Starting Tailscale daemon"

/usr/local/bin/containerboot &
PID=$!
wait ${PID}

until tailscale --socket /tmp/tailscaled.sock serve https:443 / http://127.0.0.1:3000 ; do
  sleep 0.1
done

until tailscale --socket /tmp/tailscaled.sock serve https:443 /api/v1/streaming http://127.0.0.1:4000 ; do
  sleep 0.1
done

wait ${PID}
bin/misskey.sh
#!/bin/ash
trap 'kill -TERM $PID' TERM INT
echo "Starting Tailscale daemon"

/usr/local/bin/containerboot &
PID=$!
wait ${PID}

until tailscale --socket /tmp/tailscaled.sock serve https:443 / http://127.0.0.1:3000 ; do
  sleep 0.1
done

wait ${PID}

docker-compose.yml での使い方

今のところはこう:

docker-compose.yml
services:
  tailscale:
    build: ../tailscale
    environment:
      TS_AUTHKEY: "tskey-auth-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
      TS_STATE_DIR: /var/lib/tailscale
      TS_USERSPACE: 1
      TS_EXTRA_ARGS: --hostname=gotosocial
      TS_OUTBOUND_HTTP_PROXY_LISTEN: "127.0.0.1:1055"
      TS_SOCKS5_SERVER: "127.0.0.1:1055"
    volumes:
      - ../tailscale/state/gotosocial:/var/lib/tailscale
    command:
      - /opt/bin/gotosocial.sh

なお volumescommand は各実行環境毎に調整していて、かつ TS_AUTHKEY は Tailscale の dashboard から発行したものを使っている。

またこの設定を加えた docker-compose.yml では各サービスの network 系の設定を削除し、その上で network_mode: "service:tailscale" を指定する。

注意事項

  • tailscale serve で https を使うためには tailscale での設定が必要
にゃるら / カラクリスタにゃるら / カラクリスタ

Mastodon 編

事前準備

$ git clone -b refs/tags/v4.1.2 https://github.com/mastodon/mastodon

Mastodon へのパッチ

disable-private-address-check.patch
diff --git a/app/lib/request.rb b/app/lib/request.rb
index 0508169dc..17e24f12e 100644
--- a/app/lib/request.rb
+++ b/app/lib/request.rb
@@ -273,9 +273,7 @@ class Request
       alias new open

       def check_private_address(address, host)
-        addr = IPAddr.new(address.to_s)
-        return if private_address_exceptions.any? { |range| range.include?(addr) }
-        raise Mastodon::PrivateNetworkAddressError, host if PrivateAddressCheck.private_address?(addr)
+        return
       end

       def private_address_exceptions

Masatodon のセットアップ

https://docs.joinmastodon.org/admin/install/#setup

をコンテナ環境に読み替えてやっていく。

注意点

postgres

これは下記の様な感じでやっていく

$ docker compose run postgres bash
# su - postgres
# psql
> CREATE USER mastodon CREATEDB;
> \q
# exit
# exit
$ 

Mastodon のセットアップ

$ docker compose run web bash

でコンテナに入る。

ただし RAILS_ENV=production bundle exec rake mastodon:setup を打つときには Postgres や Redis が立っている必要があるので、別の Terminal などから、

$ docker compose up db redis

あたりをやっておく。

Mastodon のドメイン

tsnet のドメインは、

  • https://{hostname}.tail{Id}.ts.net/

と言う感じになっているので、基本的にはこのドメインを指定しておく。

にゃるら / カラクリスタにゃるら / カラクリスタ

Misskey 編

事前準備

$ git clone -b master https://github.com/misskey-dev/misskey

初期設定

基本的には、

https://misskey-hub.net/docs/install/docker.html

の順番通りにやってく。

ただしドメインは Mastodon と同じく {hostname}.tail{Id}.ts.net を指定し、.config/default.yml に下記を設定しておく。

.config/default.yml
allowedPrivateNetworks: [
  '127.0.0.1/32',
  '100.64.0.0/10'
]

あとの残りは、

  • servicestailscale を足す
  • ネットワーク周りを network_mode: "service:tailscale" と指定する

と言った辺りをやっておく。

にゃるら / カラクリスタにゃるら / カラクリスタ

GoToSocial 編

事前準備

$ git clone https://github.com/superseriousbusiness/gotosocial

GoToSocial へのパッチ

結構差分がデカい。

disable-private-network-check.patch
diff --git a/internal/httpclient/sanitizer.go b/internal/httpclient/sanitizer.go
index 46540fd8..19ee8865 100644
--- a/internal/httpclient/sanitizer.go
+++ b/internal/httpclient/sanitizer.go
@@ -20,8 +20,6 @@ package httpclient
 import (
 	"net/netip"
 	"syscall"
-
-	"github.com/superseriousbusiness/gotosocial/internal/netutil"
 )
 
 type sanitizer struct {
@@ -32,7 +30,7 @@ type sanitizer struct {
 // Sanitize implements the required net.Dialer.Control function signature.
 func (s *sanitizer) Sanitize(ntwrk, addr string, _ syscall.RawConn) error {
 	// Parse IP+port from addr
-	ipport, err := netip.ParseAddrPort(addr)
+	_, err := netip.ParseAddrPort(addr)
 	if err != nil {
 		return err
 	}
@@ -41,27 +39,5 @@ func (s *sanitizer) Sanitize(ntwrk, addr string, _ syscall.RawConn) error {
 		return ErrInvalidNetwork
 	}
 
-	// Seperate the IP
-	ip := ipport.Addr()
-
-	// Check if this is explicitly allowed
-	for i := 0; i < len(s.allow); i++ {
-		if s.allow[i].Contains(ip) {
-			return nil
-		}
-	}
-
-	// Now check if explicity blocked
-	for i := 0; i < len(s.block); i++ {
-		if s.block[i].Contains(ip) {
-			return ErrReservedAddr
-		}
-	}
-
-	// Validate this is a safe IP
-	if !netutil.ValidateIP(ip) {
-		return ErrReservedAddr
-	}
-
 	return nil
 }

GoToSocial のビルド

これは手元に Go 言語環境を整えた上でこうやる:

$ VERSION=0.9.0-mod ./script/build.sh

Docker container のビルド

docker-compose.yml を用意した上でこうする:

$ docker compose build gotosocial

なお docker-compose.yml については

https://docs.gotosocial.org/en/latest/getting_started/installation/container/

を参考に構築して行くと良い。

このスクラップは2024/03/01にクローズされました