AUTOMATIC1111の更新は長らく止まっており、新しいツールを探していてComfyUIを試したりしていたのだが、Hire fixに相当する機能に当たることが出来ず、どうにもイマイチだった。
そこでかつてAUTOMATIC1111からフォークされ、AUTOMATIC1111にマージされたForgeからreForgeが新たに派生していることを知ったので試してみたが、これがかなり良かった。生成速度は爆速になったし、複数キャラの絡みも自然にできるようになった。
reForgeは既に開発が停止しているようだが、逆に言えば安定していると言う事でもある。
というわけで試した結果をつづっていく。
導入
git pull
したらwebui.bat
叩いて終わりなので特筆することはない。AUTOMATIC1111とディレクトリ構造が同じなので、extentionやmodel, loraなどの環境はそのまま引っ越せる。
爆速化したベンチマーク
前回のベンチマークでは平均生成速度2.911it/s、生成時間120秒だったが、今回は平均生成速度4.352it/s、生成速度81秒まで短縮された。
これは前回最速を記録したUltra 7 265F + 4070Tiを12秒も凌ぐ速度で、極めて速い。正直コスパでNovelAIと勝負できるレベルだ。
ベンチマーク構成
ソフトウェア
reForegeにxformersは不要とのことで、xformersを入れていない。
Env | Ver |
---|---|
version | f1.0.0v2-v1.10.1RC-latest-2446-ge1dcf9b4 |
python | 3.11.9 |
torch | 2.7.1+cu128 |
xformers | N/A |
gradio | 3.41.2 |
ハードウェア
前回とマザボが変わっているが、これによる差はないだろう。
デバイス | 製品 |
---|---|
CPU | Intel Core Ultra 7 265F |
GPU | GeForce RTX 5070 Ti |
MEM | Crucial CT2K16G56C46U5 * 4 |
M/B | ASRock Z890 Pro RS |
りこベンチ
ベンチマーク用の設定
コマンドライン引数なしでwebui.bat
を実行
設定 | 値 |
---|---|
Model | ntrMIXIllustriousXL_xiii.safetensors [1207404b17] |
Clip skip | 2 |
ENSD | 31337 |
Propmpt | (illustration:1.0), masterpiece, best quality, 1girl, solo, happy, smile, theater, (perspective:1.3), from below, (looking away:1.2), (from side:1.0), {{shot_hair}}, smile, bangs, shaggy, (brown hair:1.1), swept_bangs, thick_eyebrows, skin_fang, closed mouth, {{purple eyes}}, gray {{jacket}}, white shirt, glasses, {{small breasts}}, |
Negative Prompt | nsfw, (worst quality, low quality:1.4), (depth of field, blurry, bokeh:1.5), (greyscale, monochrome:1.0), multiple views, text, title, logo, signature, (tooth, lip, nose, 3d, realistic:1.0), dutch angle,(cropped:1.4), text, title, signature, logo, (loli:1.2), school satchel, pink, school bag, school uniform, from behind |
VAE | Automatic |
Sampleing method | DPM++ 2M |
Hires. fix | True |
Upscaler | Latent |
Hires steps | 0 |
Denoising strength | 0.8 |
Upscale by | 2 |
Sampleing steps | 20 |
Width | 768px |
Height | 768px |
Batch count | 5 |
Batch size | 1 |
CFG Scale | 7 |
Seed | -1 |
生成ログ
20/20 [00:02<00:00, 6.90it/s]
20/20 [00:11<00:00, 1.70it/s]
20/20 [00:02<00:00, 6.96it/s]
20/20 [00:11<00:00, 1.71it/s]
20/20 [00:02<00:00, 7.06it/s]
20/20 [00:11<00:00, 1.70it/s]
20/20 [00:02<00:00, 7.14it/s]
20/20 [00:11<00:00, 1.70it/s]
20/20 [00:02<00:00, 6.98it/s]
20/20 [00:11<00:00, 1.67it/s]
200/200 [01:21<00:00, 2.46it/s]
200/200 [01:21<00:00, 1.66it/s]
前回のベンチマークでは平均生成速度2.911it/s、生成時間120秒だったが、今回は平均生成速度4.352it/s、生成速度81秒まで短縮された。
平均生成速度
4.352it/s (前回比 +1.441it/s)
生成時間
81秒 (前回比 -39秒)
まとめ
明らかに爆速になった。これだけ早ければ何の文句もない。総合点でNovelAIと勝負できるレベルといっても過言ではないだろう。
複数キャラを配置できるForge Coupleの力
Forge CoupleというExtentionsが出ており、これを使うと複数キャラをNovelAI並みの自然さで配置できる。安定性ではNovelAIには敵わないのだが、無料で勝負できるところに価値がある。これがあればもうRegional Prompterは窓から投げ捨てていい。
Forge Coupleを使えばこのレベルは朝飯前だ。因みにこれはサンプルプロンプトそのままに近いが、キャラ同士の絡みも実現できる。
キャラ同士の絡ませ方の例(NSFW)
例えば、以下の条件であれば、ふたなりアスナと直葉の断面図あり挿入シーンという難題さえこなして見せる。かなりドギツイのが出てくるので試したい人はプロンプトをよく確認してほしい。かなり地獄のようなワードが入りすぎている。
nsfw, hentai illust, {num: 2girls}, 1dickgirls and 1girls, wet hair, drool,wet and messy, {cup: asuna to suguha}, very aesthetic, masterpiece, no text, from side, female sex, female sex from behind, female only
{num}, {cup}, couple, girl, kirigaya suguha, sao, large breast, large areola, white skin, (bob cut), armpit hair, pubic hair, doggy style, x-ray, creampie, ahegao, full body
{num}, {cup}, couple, dick girl, asuna (sao), A adult tall beauty crossdresser,shemale, little breasts, sagging breats, (dark nipple), little long nipples,wetty hair, hentai anime , long gloves and high socks, enjoying,smile,heart eyes, erection foreskin dick,smegma, armpit hair, pubic hair, hairy, tatoo,normal dick, sex, cum in cevio, ahegao, full body,
Negative prompt: lowres, artistic error, film grain, scan artifacts, worst quality, bad quality, jpeg artifacts, very displeasing, chromatic aberration, dithering, halftone, screentone, multiple views, logo, too many watermarks, negative space, blank page, low quality, child, text, speaking, censored. male, boy, male sex, 1boy
Steps: 20, Sampler: DPM++ 2M, Schedule type: Karras, CFG scale: 6, Seed: 1605499267, Size: 768x512, Model hash: c3688ee04c, Model: waiNSFWIllustrious_v110, Denoising strength: 0.85, Clip skip: 2, Hires CFG Scale: 6, Hires upscale: 2, Hires upscaler: Latent, forge_couple: True, forge_couple_compatibility: False, forge_couple_mode: Advanced, forge_couple_separator: \n, forge_couple_mapping: "[[0, 1, 0, 1, 1], [0, 0.5, 0, 1, 1], [0.5, 1, 0, 1, 1]]", forge_couple_common_parser: { }, Pad conds: True, Version: f1.0.0v2-v1.10.1RC-latest-2446-ge1dcf9b4
ポイントは一行目のfrom side, female sex, female sex from behind, female only
と、2~3行目のキャラクター設定行にある{num}, {cup}, couple,
だ。
まずfrom side
のように構図を指定していないと破綻しやすい。NovelAIのようにいい感じにはしてくれない。
次にふたなり百合をする場合、female sex, female sex from behind, female only
辺りがあると良い。男が出てくる確率が目に見えて減る。
キャラクター設定についても{num}, {cup}
で一行目の変数を参照し、プレイスタイルや人物属性の設定を強めることで出現率が大幅に向上する。またcouple
を付けることで、二人が出てくる確率が上がる。これがないと一人しか出てこなかったり、男が出てくる確率が増える。
トラブルシューティング
ノイズ画像が生成される
この様なノイズ画像が生成される時に「Number of Couples and Masks mismatched」というエラーが出ている場合、余計な空行が入っているのが原因なので、それを消すと直る。
Empty lines are still counted; ensure you do not leave an empty line at the end;
OCNバーチャルコネクト環境でIPv6サーバーをポート443で公開した時にやったことを派生させて更にIPv4にも対応させるプラン。
OCNバーチャルコネクトのIPoEでIPv4 over IPv6のMAP-E環境だと、IPv4ではWell-known portsが開けないが、PPPoEを使って取得したIPv4であれば開けるので、これとIPoE側のIPv6の併用でデュアルスタックでWell-known portsの開放を行い、サーバーを運用できるようにするのが目的だ。
確認環境
環境 | 内容 |
---|---|
ISP | OCN光 |
ISP契約 | OCN 光 with フレッツ マンション・スーパーハイスピード 隼・プラン1・西日本 |
ISP接続方式 | OCNバーチャルコネクト(IPoE, MAP-E) |
RouterOS | OpenWrt 24.10.0 |
ServerOS | Ubuntu 24.04.3 LTS |
HTTPD | nginx 1.26.1 |
ドメインレジストラ | Value Domain |
今回の要件
- OCNバーチャルコネクト環境でIPv6サーバーを公開した時にやったことに追加でIPv4も開通させる
- IPv4はPPPoEで取得できるものを使う
- サーバーマシン以外の端末に影響を与えない
やり方
サーバー側の準備
ufwではv4にも穴が開いている状態とする
- nginxの設定を開きIPv4向けに
listen 443 ssl;
を追記して保存する - nginxを再起動する
PPPoEインターフェースの作成
- SSHでOpenWrtに入る
/etc/iproute2/rt_tables
を開き次のようにpppoeの行を追加、保存# # reserved values # 128 prelocal 255 local 254 main 253 default 300 pppoe 0 unspec # # local # #1 inr.ruhep
- 反映する
service network restart
- LuCIに入る
- Network→Interfacesを開く
- Add new interfaceから、Nameをwanppp、ProtocolをPPPoEとしたインターフェースを作成する
- General SettingsタブのDeviceにONUと疎通しているポートを指定し、PAP/CHAP usernameとPAP/CHAP passwordにISPの接続情報を入れる
- Advanced Settingsタブを開き、Use gateway metricを
10
、Override IPv4 routing tableをpppoe (300)
にする
- Saveボタンを押して保存する
- wanインターフェースのEditを押す
- Advanced Settingsタブを開き、Use gateway metricを
1
にする - Saveボタンを押して保存する
ファイアーウォールの作成
- 引き続きLuCI上で作業する
- Network→Firewallを開く
- ZonesのAddボタンを押す
- Nameを
wan_pppoe
にし、MasqueradingとMSS clampingにチェックを入れ、Covered networksでwanppp
を選択し保存する
- lan⇒wanのゾーン設定のEditボタンを押す
- Allow forward to destination zones:に
wan_pppoe
を追加し、保存する
- Network→Interfacesを開く
- wanpppインターフェースのEditボタンを押す
- Firewall Settingsタブを開き、Create / Assign firewall-zoneに
wan_pppoe
が設定されていることを確認する。設定されていなかったら設定する
サーバーだけをPPPoEのIPv4通信の対象にする
- 引き続きLuCI上で作業する
- Network→Routingを開き、IPv4 Rulesタブを開く
- General SettingsタブのIncoming interfaceを
lan
に、SourceをサーバーのIPにする(例:192.168.1.5/32
)
- Advanced Settingsタブを開く
- Tableに
pppoe (300)
を設定し、保存する
NATを設定する
- 引き続きLuCI上で作業する
- Network→Firewallを開き、Port Forwardsタブを開く
- Addボタンを押す
- Nameに適当な名前を付け、Restrict to address familyを
IPv4 only
、Source zoneをwan_pppoe
、External portを443
、Internal IP addressを転送先のサーバーIP、Internal portを443
にして、保存する
- 最後にこれまでの内容をSave & Applyする
疎通確認
- Network→Interfacesを開き、wanpppのIPv4を拾う
- ドメインレジストラの設定でAレコードにこれを登録
- 適当な外部サーバーからcurlを投げて中身が返ってきたらOK
curl -4 -v https://example.com
IP変動対策にDDNSを設定する
/etc/hotplug.d/iface
に40-pppoe
というファイルを755
で作り、以下の内容を記述する。
#!/bin/sh
[ -n "$DEVICE" ] || exit 0
[ "$ACTION" = ifup ] || exit 0
[ "$INTERFACE" = wanppp ] || exit 0
vdpw=ここにDDNS更新用のパスワード
pppoeaddr=$(ip -4 addr show pppoe-wanppp | head -2 | tail -1 | awk '{print $2}')
logger -t "DDNS - PPPoE IP" $pppoeaddr
# hoge.example.comに対して更新リクエストを飛ばす例
logger -t "DDNS - DOMAIN: hoge" $(wget -O - "https://dyn.value-domain.com/cgi-bin/dyn.fcg?d=example.com&p=$vdpw$&h=hoge&i=$pppoeaddr")
# When making requests for multiple domains, wait 60 seconds between each request
このスクリプトはhotplugイベントが発生したときにファイルパス順に呼ばれるスクリプトらしい。
ひとまずデバイスでなく、インターフェイスが起動したときで、かつインターフェース名がwanppp
の時に実行されるように組んである。
注意点として、このエンドポイントはレートリミットがシビアで、60秒以内に送ると503を返してくるようなので、複数回投げる場合はsleep 61
とかして間隔をあけると良さそうだ。数が増えてきたらバリュードメインAPIのDNS設定APIを利用した方が早いだろう。
ただしこのAPIはTTLの制御に難があり、処理方法によっては3600秒に固定される罠が潜んでいるので注意が必要だ。
トラブルシュート
curlで「Connection refused」や「接続が拒絶されました」と出る
/var/log/ufw.log
にログがあればufwで穴をあける(まずこれはない)- ファイアーウォールかルーティングかNATの設定のどこかがおかしいので見直す。
雑感:かなり苦しい
IPv4, v6のデュアルスタックに出来たのはいいが、幾つかの端末で繋いだところIPv4側に流れるケースがあった。メインのv6でなく、オプションのv4に行くという状況はやや残念だ。
構成的にもマルチセッションという微妙な形態で、v4とv6でインターフェースが二系統あり、セキュリティもNATとFWがあり、なかなか複雑な状態になってしまった。
Mastodonにおいてはv4IPのインスタンス(兵庫丼)との疎通はTLレベルでは出来たものの、画像が出なくなるという頭が痛い問題に出会った。
Misskey.ioからは疎通できず、こちらからはユーザープロフィールまではアクセスできるがフォローを押しても音沙汰がない。
結論としてはリッチなアプリケーション通信を伴う用途において、この方式は向かない気がした。恐れくこれはルーターより外側がIPoEとPPPoEで別系統になっている関係で、通信が混乱して上手くいかないパターンがあるのではないかと感じている。
DDNSも制約が厳しいし、Value DomainのAPIはあるだけマシではあるものの、超絶使いづらい問題もあり、この環境においてのデュアルスタックはあきらめようと思った。
まぁいい勉強にはなったので、そのうち何かに活かせるだろう、きっと。
ノートPCを無理なく冷やすの続き。
前回は具体的な数値結果が書けていなかったので、今夏改めて出しなおした話。
まず計測手法をある程度標準化し、CPU温度ロガーを見つけることができたので、それを出している。但し計測端末が変わっており、100度張り付きは起きなくなっている。
概略
裏蓋がまだ入手できていないので一旦通常配置と、裏返し配置のみ。残りは追って追記予定。
温度 | 通常配置 | ひっくり返し | 穴開け+ひっくり返し | ひっくり返し+穴開け+ラズパイクーラー |
---|---|---|---|---|
CPU平均 | 79.86度 | 65.66度 | 未計測 | 未計測 |
CPU最大 | 87.00度 | 87.00度 | 未計測 | 未計測 |
CPU最底 | 51.00度 | 49.00度 | 未計測 | 未計測 |
M/B平均 | 60.77度 | 55.98度 | 未計測 | 未計測 |
M/B最大 | 66.00度 | 58.00度 | 未計測 | 未計測 |
M/B最底 | 43.00度 | 41.00度 | 未計測 | 未計測 |
前回ひっくり返すだけで10度ほど下がると書いたが、実際にひっくり返しの効果は大きく、15度ほどの低下がみられる。
計測グラフ
裏蓋がまだ入手できていないので一旦通常配置と、裏返し配置のみ。残りは追って追記予定。
図は青軸がCPU使用率、橙軸がCPU温度、残りの束がマザーボードの温度である。
7月31日に立てたMastodon作成ロードマップの最後である、自宅サーバーでMastodonをセルフホスティングするのを達成したので、そのログをここに記す。
Ubuntu実機AMD64環境でDockerを使わず、IPv6シングルスタックで構成している。
自宅サーバーを使ってIPv6シングルスタックで通信を待ち受ける方法はOCNバーチャルコネクト環境でIPv6サーバーをポート443で公開した時にやったことの方に書いている。
- 確認環境
- 前提条件
- 事前準備
- 依存関係のインストールとセットアップ
- Mastodon本体のセットアップ
- なんやかんやの末に立ち上がったMastodonインスタンス
- トラブルシューティング
- Dockerを使わなかった理由
- 実際に導入して驚いた部分
- 今後やっていきたい部分
- あとがき:OSグローバルのRubyを消してみた
確認環境
Ubuntu実機AMD64環境
Env | Ver |
---|---|
Ubuntu | 24.04.3 LTS |
nginx | 1.26.1 |
Mastodon | v4.4.3 |
Ruby | 3.2.3 |
ruby-build | 20250811 |
rbenv | 1.3.2-10-gd1a19a3 |
前提条件
- 既にnginxを運用しており、IPv6シングルスタックで公開できている
- certbotを使ったLet's EncryptでのTLS証明書発行が可能
事前準備
- 公開用のドメインを検討し、生み出す
- Value Domainのコンパネから生み出したドメインをAAAAレコードで登録
- 拙作の@lycolia/value-domain-dns-cert-registerを使ってTLS証明書を発行
依存関係のインストールとセットアップ
以下のコマンドを流す
sudo apt update sudo apt install -y \ imagemagick ffmpeg libvips-tools libpq-dev libxml2-dev libxslt1-dev file git-core \ g++ libprotobuf-dev protobuf-compiler pkg-config gcc autoconf \ bison build-essential libssl-dev libyaml-dev libreadline6-dev \ zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev \ nginx redis-server redis-tools postgresql \ certbot python3-certbot-nginx libidn11-dev libicu-dev libjemalloc-dev \ # 最新版を入れないとうまくいかない wget https://github.com/rbenv/ruby-build/archive/refs/tags/v20250811.tar.gz tar -xzf v20250811.tar.gz sudo PREFIX=/usr/local ./ruby-build-20250811/install.sh rm v20250811.tar.gz rm -Rf ruby-build-20250811 # aptではサポート切れの化石が入るのとnvmで入れたのは自分しか使えないので新しいのをグローバルに入れる curl -fsSL https://deb.nodesource.com/setup_24.x -o nodesource_setup.sh sudo bash nodesource_setup.sh apt install -y nodejs rm nodesource_setup.sh corepack enable # メンテナンスでめっちゃ使うのでサービスユーザーにはせず、ログイン可能なユーザーとして作る adduser --disabled-password mastodon
/etc/redis/redis.conf
を開きrequirepass
のコメントを外し、パスワードを設定sudo service redis restart
sudo -u postgres psql
でポスグレに入り、ユーザーを作る。ポスグレは不慣れで同時にPW設定する方法が判らなかったので別建てで設定しているCREATE USER mastodon CREATEDB; ALTER ROLE mastodon WITH PASSWORD 'パスワード'; \q
Mastodon本体のセットアップ
実際にはかなり行ったり来たりしてるので一部の手順には誤りが含まれている可能性がある。
mastodonユーザーにスイッチしてインストール作業を続行
# Mastodon本体の導入 sudo su - mastodon git clone https://github.com/mastodon/mastodon.git live # 超重要、cd忘れててもなんかそれっぽく進むが、以後すべて破綻する cd live git checkout $(git tag -l | grep '^v[0-9.]*$' | sort -V | tail -n 1) git clone https://github.com/rbenv/rbenv.git ~/.rbenv echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc echo 'eval "$(rbenv init -)"' >> ~/.bashrc exec bash # 動かないやつなのでコメントアウト # 依存関係のインストールとセットアップでやった内容をこっちでやってもいいかもしれない # git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build # ここでエラーが出たら何かが間違っているのでやり直し RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install # bundleがないとか、rubyのバージョンが存在しないとかエラーが出たら何かが間違っているのでやり直し bundle config deployment 'true' bundle config without 'development test' bundle install -j$(getconf _NPROCESSORS_ONLN) yarn install # 色々尋ねられるので適当に進める RAILS_ENV=production bin/rails mastodon:setup
デーモン周りの設定をする
# 静的ファイルをnginxに見させるために権限を設定 sudo chmod o+x /home/mastodon # デーモンの登録と起動 sudo cp /home/mastodon/live/dist/mastodon-*.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming sudo service mastodon-web start sudo service mastodon-sidekiq start sudo service mastodon-streaming start
nginxの設定を書く
map $http_upgrade $connection_upgrade { default upgrade; '' close; } upstream backend { server 127.0.0.1:3000 fail_timeout=0; } upstream streaming { # Instruct nginx to send connections to the server with the least number of connections # to ensure load is distributed evenly. least_conn; server 127.0.0.1:4000 fail_timeout=0; # Uncomment these lines for load-balancing multiple instances of streaming for scaling, # this assumes your running the streaming server on ports 4000, 4001, and 4002: # server 127.0.0.1:4001 fail_timeout=0; # server 127.0.0.1:4002 fail_timeout=0; } proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g; server { listen [::]:443 ssl http2; server_name <ドメイン>; ssl_certificate /etc/letsencrypt/live/<証明書のパス>/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/<証明書のパス>/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; # You can use https://ssl-config.mozilla.org/ to generate your cipher set. # We recommend their "Intermediate" level. ssl_ciphers CDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA84:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA38:DHE-RSA-CHACHA20-POLY1305; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_tickets off; keepalive_timeout 70; sendfile on; client_max_body_size 99m; root /home/mastodon/live/public; gzip on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xmlrss text/javascript image/svg+xml image/x-icon; gzip_static on; location / { try_files $uri @proxy; } # If Docker is used for deployment and Rails serves static files, # then needed must replace line `try_files $uri =404;` with `try_files $uri @proxy;`. location = /sw.js { add_header Cache-Control "public, max-age=604800, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/assets/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/avatars/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/emoji/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/headers/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/packs/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/shortcuts/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/sounds/ { add_header Cache-Control "public, max-age=2419200, must-revalidate"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; try_files $uri =404; } location ~ ^/system/ { add_header Cache-Control "public, max-age=2419200, immutable"; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; add_header X-Content-Type-Options nosniff; add_header Content-Security-Policy "default-src 'none'; form-action 'none'"; try_files $uri =404; } location ^~ /api/v1/streaming { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Proxy ""; proxy_pass http://streaming; proxy_buffering off; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; add_header Strict-Transport-Security "max-age=63072000; includeSubDomains"; tcp_nodelay on; } location @proxy { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Proxy ""; proxy_pass_header Server; proxy_pass http://backend; proxy_buffering on; proxy_redirect off; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $connection_upgrade; proxy_cache CACHE; proxy_cache_valid 200 7d; proxy_cache_valid 410 24h; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; add_header X-Cached $upstream_cache_status; tcp_nodelay on; } error_page 404 500 501 502 503 504 /500.html; }
なんやかんやの末に立ち上がったMastodonインスタンス
なんやかんやあり色々苦戦したが、無事立ち上がってくれて何よりだった。
立ち上がった直後。
そして現在。こうやって動いているのを見ると感慨深い。
実は中学生のころから自宅サーバーを立てるという夢を持っており、こうやって実際に公開できたことは感慨深い。実際のところ、実験用の小規模サーバーや、SHOUTcastサーバーだとか、シンクライアント用のSSHサーバーみたいなのは作った経験があり、いずれも外に出していたのでサーバーを作った経験が全くない、というわけではないのだが、監視環境を整えたり、IPv4が実用困難な環境で、IPv6に挑戦してみたりと、ここまで本格的にやったことはなかったのもあり、個人的には結構達成感がある。
トラブルシューティング
Mastdonのlistenしているポートを変更する
3000番はGrafanaをはじめ、様々なNode.js系のポートと干渉するため変えておく。
/etc/systemd/system/mastodon-web.service
のEnvironment="PORT=3000"
を変えることでWeb側のポートが変えられる/etc/systemd/system/mastodon-streaming.service
のWants=mastodon-streaming@4000.service
の4000
の部分を変えることで、Streaming側のポートも変えられる- サービスを再起動する
sudo systemctl daemon-reload sudo service mastodon-web restart sudo service mastodon-streaming restart
- nginxの設定も対応する箇所を変える
- nginxを再起動する
sudo service nginx restart
Mastodonのエラーページが表示される・Rubyがないとか出るなどセットアップ時のエラー全般
基本的にどこかの手順が間違ってるのでしつこくやり直すことで改善する。
投稿可能な文字数を増やす
以下の内容で修正すると増やせる。
app/validators/status_length_validator.rb
class StatusLengthValidator < ActiveModel::Validator
- MAX_CHARS = 500
+ MAX_CHARS = 50000
app/javascript/mastodon/features/compose/containers/compose_form_container.js
正直このファイルは直さなくても動くし、直しても、ほぼ意味がなさそうなので、直す必要はないかもしれない。
- maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 500),
+ maxChars: state.getIn(['server', 'server', 'configuration', 'statuses', 'max_characters'], 50000),
備考
変更直後は投稿画面の初期表示に500
と出ていて、数文字打つと50000文字に変化する状態だったが、一日くらい経過すると初期値が50000に変わっていたのでキャッシュか何かが悪さをしていた可能性がある。
フォローできるが、フォロー一覧にもTLにも出てこないユーザーが出る
IPv6と疎通してないところは仕方がないね。AAAAレコード持ちでcurl -6 -v https://example.com
しても疎通する場所でも起きることがあるが原因は不明。
兵庫丼でも偶に遭遇してたので、そういうものだと割り切るしかない。IPv4滅ぶべし、慈悲はない。
「制限に達しました1:35:00 以降に再度実行してください。」とエラーが出る
APIのレートリミットにかかっているせいっぽい。5分間に300リクエストまでと、かなり渋い。信用するIPを指定することで回避可能らしい。
.env.production
を開き、前述の資料に書かれている信頼できるIPを列挙した後に、自分のIPv6プレフィクス(aaaa:bbbb:cccc:dddd::/64を自分のプレフィクスに置き換え)を追加し、再起動しておいた。これで緩和されると良いのだが、出先では使えないと思うのでどうするか…。
TRUSTED_PROXY_IP=127.0.0.1/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7,aaaa:bbbb:cccc:dddd::/64
ドキュメントを読む限り、アカウントIDで縛る処理がどこかにあるようなので、自分のIDを除外できれば出先でも起きなくなり、更に良さそうだが、やり方はよくわからなかった。
調べた限りconfig/initializers/rack_attack.rb
の中でやっているようなので、暇なときに見てみたいとは思う。
Prometheusでメトリクスを取得する
Mastodonは標準でPrometheusに対応しているので、Exporterの有効化設定を見ながら設定していく。
まず.env.production
を開き、以下の二行を追記し、再起動する。これによってMastodonWebのExporterが有効化され、ローカルホストで動くようになるようだ。Streamingの方は設定せずとも、元から有効になっている模様。
MASTODON_PROMETHEUS_EXPORTER_ENABLED=true
MASTODON_PROMETHEUS_EXPORTER_LOCAL=true
再起動したらcurl http://localhost:{Streamingのポート番号}/metrics
とcurl http://localhost:9394/metrics
で動いていることを確認。
次にPrometheusのscrape_configs
に以下を追記し、Prometheusを再起動する。
- job_name: 'mastodon-web'
static_configs:
- targets: ['localhost:9394']
- job_name: 'mastodon-streaming'
static_configs:
- targets: ['localhost:5001']
Prometheusの管理画面を開き、Target healthに出て動いていればOK。
【未解決】プロフィールを更新すると更新前の状態にぶり返したり、更新後の状態になったりして安定しない
大まかには、このような感じ。再現したりしなかったりでいい感じの動画が撮れなかった…。
キャッシュ周りで何かの問題が起きている可能性があるが原因はよくわかっていない。3分も待てば改善するので一旦気にしないことにした。
Dockerを使わなかった理由
Dockerがあれば一瞬で立ち上がって便利といえば便利なのだが、Ubuntuのネイティブ環境にPrometheusとGrafanaをIPv6スタックで導入した時に、DockerとIPv6の相性が余りにも悪すぎたのが最大の要因。
後はまぁ変なレイヤー隔ててない方が管理楽だし、リソースも抑えられるかなとか。
実際に導入して驚いた部分
簡単な監視ツールがある
Mastodon自体に監視の仕組みがあること。Sidekiqという名前自体はよく聞くので知っていたが、今まではなんとなくジョブ管理システムだと思っていた。これはTLで見かけていた管理人の人たちがトラブルが起きた時にジョブを殺したりしているのを見かけたためだ。
とはいえ、公式サイトの説明にはRuby's fastest job systemとあるので、あながち認識としては間違ってなかったようだ。ジョブ管理システムのついでにメトリクスとかも見れる機能があるのかもしれない。
Webベースの管理画面がある
環境変数周りの設定項目が多く、コンソールから設定を操作するイメージが強く、コンソールベースなのかと思っていたが実際にはWebベースのGUI管理コンソールもあり、中々便利だ。管理面の操作や、サーバー本体への影響がない簡単な設定はここで出来るだろう。
死ぬほど早い
アップロードが爆速だったり、画面遷移もかなり早い。家で繋ぐ分にはLAN環境だから早いのかと思っていたが、外から5Gで繋いでも早い。
今のところ大したアクセスや負荷もなく、リソースがしこたま余ってるお陰かもしれない。あとは単純に手前にCDNがないとか、VPSといった共有資源とかと比べた時のスペックの差だろうか?
スペックは結構ある方だと思う。具体的にはCPUはAMD Ryzen 5 5600G、メモリはDDR4 32GB、SSDもCrucial P1 CT500P1SSD8JPでNVMeといった感じで、そんなハチャメチャに高スペックというわけではないが、よくある?安い中古ノートPCを流用したサーバーと比べたら充実している。
今後やっていきたい部分
主に監視周りの強化をしていきたい。現在のロードマップは以下のような感じだ。
- Grafanaでnginxのダッシュボードを整備
- Lokiの導入
- GrafanaからMastodonのメトリクスを見れるように
- OpenWrt本体でメトリクスをとれるようにしたい
- 本体が死ぬとテレメトリ取れないので鯖側のPrometheusだと役不足
- 問題はストレージどうするか…
- 寿命の関係でeMMCには書けないからNVMe拡張するのか
- OpenWrtのメトリクスを鯖側でも取れるようにする(いるかこれ?
- 外部ステータスページの用意
- 簡単な外形監視の導入?(やるならさくらに乗せる)
まず、Grafanaをセットアップしたもののnginxのダッシュボードが空っぽなので作っていく必要がある。
次にLokiを入れてログ監視もできた方がいい。個別のログファイルを見るのは割とつらい。
Grafanaで統合管理できると便利なのでMastodonのメトリクスも取れると良いので、これもやっていきたい。
他にも今回のセットアップ中にOpenWrtがOutOfMemoryで落ちるケースがあり、原因不明のネットワーク切断が多発したため、こちらのメトリクス収集も必要だ。ネットワーク自体が死ぬと中身が見れないため、基本的に本体側で、収集して見れるようにしたい。今でも簡単なものは入れているが情報量が少なく、役不足だ。
ストレージ寿命の問題もありeMMCにログを吐くとストレージの寿命がマッハになる恐れがあるため、メモリ管理や追加でストレージを用意するなど、手法についても検討する必要がある。
OpenWrtのメトリクスを鯖側でも取れるようにするのはオプションプランだが、これは別にどうでもいい気はする。平時は統合的に見れて便利かもしれない。
あとは外部環境にステータスページを配置したいと考えている。実用性があるかどうかは謎だが、あるとそれっぽいから。ツールとしてはCachetを採用し、さくらのレンタルサーバー側で運用する予定だ。
簡単な外形監視の導入についても、Cachetで担える可能性がある。
監視面以外ではセルフホスティング方式のWAFであるAnubisに興味があり、これも入れていきたいと考えている。
更に中長期では、現在運用しているlycolia.info配下の全サイトを自宅サーバーへ移行し、メールサーバーやネームサーバーなど、現在あるWebサイトの一切を移行する野望も抱いている。
とにかくやることが沢山あるので、当面は暇になることはなさそうで、充実した生活を送れそうだ。
あとがき:OSグローバルのRubyを消してみた
本来手順になく、私の勘違いで追加して作業してしまっていたOSグローバルのRubyを消しても動くのか試してみた。
# 通常ユーザー作業
ls -la /usr/local/bin | grep ruby
rm /usr/local/bin/ruby-build
sudo rm -Rf /usr/local/bin/ruby-build
ls -la /usr/local/share
sudo rm -Rf /usr/local/share/ruby-build
sudo rm -Rf /usr/local/share/man/man1/ruby-build*
ruby -v
sudo apt remove ruby
sudo su - mastodon
# mastodonユーザー作業
mkdir -p "$(rbenv root)"/plugins/ruby-build
cp ruby-build-20250811/. "$(rbenv root)"/plugins/ruby-build
ls -la "$(rbenv root)"/plugins/ruby-build
cd live
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install
ruby -v
exit
# 通常ユーザー作業
sudo service mastodon-web restart
sudo service mastodon-sidekiq restart
sudo service mastodon-streaming restart
一旦ここまでは上手くいったので、上の方にある手順よりこっちでやった方がいいかもしれない。Mastodonのビルドが通るかまでは試してないので、実際に動くかどうかまでは不明だが、まぁ次回考えればよいだろう。