b-shock. Fortress

FreeBSDにGROWIをセットアップする

ある目的で、Mastodonと連携させる為のGROWIが必要になった。

対象はFreeBSD。
GROWIにはportsもパッケージもない為、以下、gitから手作業で導入していく 大まかな流れ。不明点があれば、適宜ググって頂ければと。

動作環境

  • nginx
  • Node.js 8.x以上
  • Ruby 2.4.x以上

が適切にセットアップされているものとする。

リポジトリのクローン

GROWIの実行ユーザーを仮に growi として。

1
2
3
4
5
cd ~growi
git clone https://github.com/weseek/growi.git
cd growi
git checkout release
yarn

release ブランチが運用に適すると判断した。

MongoDBの導入

これ以降の操作は、すべてroot権限で行う。
GROWIのストレージとなる、MongoDBを導入。

1
2
3
4
pkg install mongodb36
pkg install mongodb36-tools
sysrc mongod_enable=YES
sysrc mongod_flags="--setParameter=disabledSecureAllocatorDomains=*"

3.6系は、今日時点での最新安定版。
toolsパッケージにはバックアップの為の mongodump コマンド等が入っており、 事実上必須。
mongod_flags を設定しているのは、ログをsyslogに出したい為で、 そうでなければデフォルトのままでも可。

/usr/local/etc/mongodb.conf

これもログの出力先をsyslogに変更する為の対応で、ほかはデフォルト。
不要ならばデフォルトのままの mongodb.conf でも可。

最後に、MongoDBのデーモンを起動。

1
service mongod restart

Godの導入

Godを未導入の環境に新規導入するものとして。
既に導入されている場合は、うまく辻褄をあわせていただきたい。

対象システムであるGROWIはNode.js製なのだから、 本来であればPM2 あたりを使うべきであるというご指摘はごもっとも。

1
2
gem install god
mkdir /usr/local/etc/god

/usr/local/etc/local.god

以下、設定例 。(ファイル名はたぶん何でもいい)
めちゃ強引だが、とくに反省はしないw

/usr/local/etc/god/growi.god

GROWIの実行ユーザー growi のホームディレクトリが、 先ほど同様 /home/growi であるとして。

ポートをデフォルトの3000から3012にずらしているのは、 Mastodonインスタンスと同じホストへの導入を想定している為。 3012に深い意味はない。

停止コマンドが汚すぎる。ちょっと反省してる…。
機会あったら直したい。

/usr/local/etc/rc.d/god

Godを自動起動するには、以下のようなファイルを作成。

FreeBSDのrc.dスクリプト、実は細かいところはよく知らない。
見様見真似で上記のように書いて、一応動いてはいるけど。

ここまでできたら、Godを起動。

1
service god restart

リバースプロキシ

以下、Let’s Encryptの証明書を利用する、nginxの設定例。
詳細な説明は割愛。設定後、nginxの再起動。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 443 ssl;
server_name growi.example.com;

ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_ecdh_curve prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_certificate /usr/local/etc/letsencrypt/live/growi.example.com/fullchain.pem;
ssl_certificate_key /usr/local/etc/letsencrypt/live/growi.example.com/privkey.pem;
add_header Strict-Transport-Security max-age=63072000;

location / {
proxy_pass http://localhost:3012;
}
}

監視

以下の項目を監視している。

  • https://growi.example.com/ 上の適当なページが200を返すこと。
  • TCPのポート27017が開いていること。

バックアップ

以下、実行例。

1
mongodump --port 27017 --out /tmp/destdir

このあと /tmp/destdir をアーカイブして、他のホストにrsyncする手順等 の自動化を行う。

以上。

Xubuntu 18.10

リリース直前だが空気を読まず、Xubuntu 18.10をMacBook Airに適用していくのである。
MacBook AirとXubuntuという組み合わせにニーズなどあるのか?などとは考えないことにする。

18.04の時の記事はこちら→ Xubuntu 18.04

基本的な更新の手順

1
sudo do-release-upgrade -d

-d は開発版を含めるという意味。
今回のように、リリース前のものでも適用したい場合はこのオプションが必要。

トラックパッドの2本指スクロールの向きを上下逆に

毎度のことだが、過去記事と 同じ手順で再設定可能。

結論から言うと、今回は xinput set-prop 12 289 -200 -200 だった。この289が毎回変わるのである。

以下、調べる手順を説明していく。
xinput list を実行して、トラックパッドのデバイスIDを調べるところまではよいとして。

1
2
3
4
5
6
7
8
9
10
11
12
% xinput list
⎡ Virtual core pointer id=2 [master pointer (3)]
⎜ ↳ Virtual core XTEST pointer id=4 [slave pointer (2)]
⎜ ↳ bcm5974 id=12 [slave pointer (2)]
⎣ Virtual core keyboard id=3 [master keyboard (2)]
↳ Virtual core XTEST keyboard id=5 [slave keyboard (3)]
↳ Power Button id=6 [slave keyboard (3)]
↳ Video Bus id=7 [slave keyboard (3)]
↳ Power Button id=8 [slave keyboard (3)]
↳ Sleep Button id=9 [slave keyboard (3)]
↳ FaceTime HD Camera (Built-in): id=10 [slave keyboard (3)]
↳ Apple Inc. Apple Internal Keyboard / Trackpad id=11 [slave keyboard (3)]

一見11が正解に見えるが、実際には12である!
「マウスとタッチパッド」の設定を開いてデバイス名を確認するのがよいと思う。

余談だけど、この画面には「スクロール方向を反転する」というチェックボックスがある。
これを使えば、一見面倒な手順を踏まず全て解決に見えるけど、実際には使ってはいけない地雷なので要注意。 この設定項目、アプリによっては効かなかったりする。

閑話休題。トラックパッドのデバイスIDが12とわかったら、そのあとは

1
xinput list-props 12 | grep "Synaptics Scrolling Distance"

を実行して、プロパティIDを知ることが出来る。

ウチの環境では、セッションと起動→自動開始アプリケーションに以下のコマンドを書き加えて終了。

1
xinput set-prop 12 289 -200 -200

その他

使い始めたばかりなので、まだわかっていないことが多いが。

  • Guakeはテーマの切り替えが必要だった。一度設定すれば以降は正常動作。
  • Node.jsのリポジトリ https://deb.nodesource.com/node_8.x/ は、今日時点で18.10に未対応。

個人的にはこのあと、GPD Pocketにも18.10を適用の予定。

FreeBSDでUserminをセットアップ(リバースプロキシを利用)

以前、Userminに関する記事を書いたが、その後別のサーバにセットアップした。
20000/tcpを直接晒すのではなく、リバースプロキシを通して普通に443で公開したかったので、手順を修正。

以下、 usermin.example.com にUserminをセットアップする例。
全てroot権限で行う。

パッケージインストール

1
2
pkg install usermin
sysrc usermin_enable="YES"

セットアップスクリプト

1
2
cd /usr/local/lib/usermin
./setup.sh

対話形式で設問に回答すると、 /usr/local/etc/usermin が作成される。

設定ファイルを編集

/usr/local/etc/usermin/miniserv.conf に、以下の項目の更新・追記が必要。

1
2
3
4
log=0
syslog=1
denyusers=root
allow=127.0.0.1 localhost
  • rootアカウントの利用は許可するべきではない。
  • localhostのみ許可しているのは、リバースプロキシを通じた利用だから。
  • 通常ログを止めてsyslogにしているのは、単なる好みw お好みに合わせて。

/usr/local/etc/usermin/config にも要追記。

1
referers=localhost usermin.example.com

usermin.example.com は実際には、ユーザーから見たドメイン名。
証明書のコモンネームと合わせておけば間違いないと思う。

許可するモジュールの選択

そのまま /usr/local/etc/usermin で、以下実行。

1
echo 'user: changepass' > webmin.acl
  • パスワード変更機能だけ必要。以前の記事では procmail も入れてたが、 結局使わなかったので削除。

Apacheにリバースプロキシを設定

1
2
3
4
5
6
7
8
<VirtualHost *:443>
ServerName usermin.example.com
SSLEngine on
SSLCertificateFile /usr/local/etc/letsencrypt/live/usermin.example.com/fullchain.pem
SSLCertificateKeyFile /usr/local/etc/letsencrypt/live/usermin.example.com/privkey.pem
ProxyPass / http://localhost:20000/
ProxyPassReverse / http://localhost:20000/
</VirtualHost>

certbot(Let’s Encrypt)の使い方については省略。
nginxの場合も、似たような感じで。

変更を反映

1
2
service usermin restart
service apache24 restart

ZFSスナップショットを削除する

ZFSで、スナップショットの削除を行う為には、特別な権限付与が必要。

以下、postgresユーザーに対して、 zroot/postgres におけるスナップショットの作成と削除を 許可する設定。

1
zfs allow postgres snapshot,destroy,mount zroot/postgres

destroy権限の他にmount権限も必要なのがハマりどころ。

PostgreSQLのデータディレクトリに対し、ZFSのスナップショットを撮る

Mastodonの運用…に限らないけど、データベースのバックアップを取る必要がある。 pg_dump を行って rsync なりでリモートに送るのが簡単、実際その方法で1時間ごとに バックアップを取っていた。

Mastodonのデータベースを1年も運用すると、お一人様インスタンスでも1GB超のダンプファイルになる。
この大きさになると、1時間ごとに実行するのは困難。 1時間ごとに pg_dump を実行するお手軽バックアップ、1年にして破綻。
頻度を1日ごとに落とした。

個人的に、正規のバックアップは論理バックアップであるべきと考えており、この1日ごとの pg_dump は 辞められない。
一方で、今まで通りの1時間粒度のバックアップも、やはり続けたいと思っている。

それを実現するアイディアが、ZFSのスナップショット。
地雷運用と言われようとあえてFreeBSDを使い続けてきたが、その真価がついに。

以下の手順、全てroot権限にて。

マウントポイント

FreeBSDで通常のセットアップを行うと、PostgreSQLのデータディレクトリは /var/db/postgres の配下に 置かれるだろう。
ZFSのスナップショットはマウントポイントの単位で行われる為、このディレクトリを独立したマウントポイントに 分ける必要がある。

以下を実行すると、 /var/db/postgres既にあるファイルが削除される。
必要なら、それこそ pg_dump 等でバックアップしてから!

1
2
3
zfs create zroot/postgres
zfs set mountpoint=/var/db/postgres zroot/postgres
zfs set snapdir=visible zroot/postgres

zfstoolsを導入

スナップショットの保存、古いスナップショットの破棄、DBの一時停止等をひと通りやってくれる gemがある。
Mastodonインスタンスが置かれたサーバにRubyがインストールされてないはずはなく、 zfstoolsは以下の手順で導入可能。

1
2
gem install zfstools
zfs set com.sun:auto-snapshot=postgresql zroot/postgres

この手順で、 /usr/local/bin/zfs-auto-snapshot がインストールされる。

実行時ユーザーにsnapshot権限を付与

zfs-auto-snapshot は、OSのpostgresユーザーで実行するのが手っ取り早い。
このユーザーにはZFSのスナップショット作成の権限が与えられてない為、対応が必要。

1
zfs allow postgres snapshot zroot/postgres

追記(2018-09-24)
訂正あり。削除権限の付与も必要。 ZFSスナップショットを削除する

wal_levelを設定

PostgreSQL側で、 wal_level を設定する必要がある。
/var/db/postgres/data96/postgresql.conf 等に以下追記。 (data96のところ、PostgreSQLのバージョンによって変わるから適用に読み替えて)

1
wal_level = replica

反映させる為には、恐らく再起動が必要。

1
service postgresql restart

スナップショットを撮る!

ここまでで準備終わり。以下のコマンドでスナップショットが撮れる。

1
sudo -u postgres /usr/local/bin/zfs-auto-snapshot hourly 24

実際の実行はcron等で。

おまけ

スナップショットの一覧を表示。

1
zfs list -t snapshot

誤って作りまくったスナップショットの破棄。

1
zfs destroy スナップショット名

Mastodon 2.5.0 @ FreeBSD

Mastodon 2.5.0がリリースされた。
FreeBSDで動作させるために必要な箇所、言い換えれば地雷が若干ある。

以下、FreeBSD 11.2での話ではあるけど、他のバージョンでも同様だと思います。

カスタムテーマ

いつものように、カスタムテーマが以前のものと互換性がない。
標準テーマから色を替えただけのものであるなら、作り直したほうが手っ取り早いです。

追記
これ、よく考えたらFreeBSDと関係ない話ですが。

ストリーミングAPIが動かない。

uwsが新しくなった為です。
これにFreeBSDのバイナリが含まれていない為、Mastodonでは動作しない模様。 2.4系で使われていた8.14.1ならば問題なし。

ためらうことなく、package.jsonを書き換え、 yarn upgrade しましょう!

貼れない画像がある。

「ある」などというレベルではなく、大半貼れない感じです。
日本語ファイル名が問題なのか、JPEGならよいのか。色々検証しましたが、全く切り分けできませんでした。

paperclipを6.1.0から 6.0.0に落とせば正常動作しますので、 ためらうことなくGemfileを書き換え、 bundle update ましょう。

所感

FreeBSDがハブにされてる感、はんぱないです!

パッケージのバージョンを落とす対応は有効と知りました。
これも修行なのです。自力解決しましょう!

mulukhiya-toot-proxy 1.2

しばらく間が空いたが、気にせず進行する流れw
一応、月ごとのアーカイブを途切れさせたくないとは思ってる。

書きたいネタはそれなりにあるのだけどね。
需要があるかはあんまり気にしてない。このブログの継続的な読者は多分いないのはわかってて、 たまたま同じことで困ってる人の問題解決を手伝えればよいという程度のもの。

本題。
拙作ツール mulukhiya-toot-proxyには ちょくちょく修正を加えており、先日1.2系という新バージョンをリリースした。

新バージョン事実上唯一の機能は、Mastodonでのトゥートにamazonの商品URLが含まれていた場合に、 商品画像を添付すること。
よって、Amazon Product APIへの対応を行う必要がある。

Amazon Product API

主にこちらを参考にした。

[Ruby] Amazon Product APIで商品検索してみた

特にトークンの取得等の手順が簡潔に説明されており、大いに助かった。感謝。

但し、今回必要なのは、事前にわかってるASINから商品画像のURLを引く機能。 記事の通りではなく若干アレンジが必要。

以下、要点のみ抜粋。

例外捕捉をしているのは、amazon側が割と頻繁に503を返すから。

この問題への対応は、単純にやり直すだけで問題なしと思ってる。 但し、このまんまじゃ無限ループになりかねないからw、回数の上限等を設ける必要は当然ある。
参考にしてる人がもしいたらw、各自対応よろしくです。

マルチパートなアップロード

Mastodonに画像をアップする際、マルチパート対応なHTTPクライアントが必要。 RubyではHTTPartyを好んで使ってましたが。 ひょっとして対応してないんじゃないですか?(調べが足りないだけかも)
HTTMultiPartyなるラッパーもあったが、最近メンテナンスされてないようだ。 普通に動きそうではあったけど、試してない。
メンテナンスされてないことを承知で使いたいひとはググってください。簡単に見つかるから。

結局、該当部分だけREST Clientなる クライアントで実装しました。
要点抜粋するとこんな感じ。

HTTPartyとREST Clientを意味もなく使い分けるのもアレだし、HTTPartyで実装された箇所をあとで REST Clientで書き直すかも。

以上、モロヘイヤにはこんな技術(というほど大層ではない)が使われているのでございます。

新しいMastodonの周辺ツール "mulukhiya-toot-proxy" の紹介

mulukhiya-toot-proxyという新しいツールを書いたので、そのご紹介。
縮めて「モロヘイヤ」とお呼び頂ければ。

mulukhiya-toot-proxy

通常はMastodonインスタンスと同じサーバにインストールし、Mastodon本体と並列に配置。 nginxのリバースプロキシを通して利用する。

Mastodonへのトゥート(/api/v1/statuses リクエスト)を横取りし、以下の改変を行って Mastodonに送り直す。


日本語を含むURLを適切にエンコードする。

ホスト名、パス、クエリー等に日本語を含むケースが該当。
この処理によって、各種クライアントでそのURLがクリックできるようになる可能性がある。 (人が作ったクライアントがどんな動作を動作するかまでは保証できない。だから「可能性」w)

各種短縮URLを元に戻す

この処理により、怪しい短縮URLのリンク先が明らかになる。
意図せず貼り付けてしまったt.coのリンク等も元通り。

アマゾンの商品URLから必要な部分だけを残し、他を全て削除

アマゾンの商品URLはSEO対策の為か、日本語の商品名を含んだ非常に長いものになるケースが多い。 ご存知の方も多いだろうが、シェアには不向き。
トゥートに無加工でコピペしてしまった場合にも、必要な部分だけを残して、他を全て削除する。


これらの処理は、nginxがトゥート要求を受け取ったあとに実行される。 Webクライアント以外のクライアント(BOT等)であっても、 /api/v1/statuses を利用する 全てのトゥートに適用される。

興味をお持ちの方は、リンク先をご覧頂ければ。
そして、もし使ってくれるなら★をつけてくれるとうれしいです。 よろしくお願いします!

XubuntuをOpenVPNクライアントに。(Xubuntu 18.04)

訳あって、GPD PocketをOSインストールから再構築した。
この話は近々するとして…。OpenVPNクライアントにする手順が若干変わっていた様だったので、 以前の記事と重複する内容も含め、改めてまとめておく。

パッケージの導入

1
sudo apt install openvpn

以前必要だったtunneldiggerは不要!
このツール、Ubuntu 18.04のリポジトリに含まれなくなったが、理由をやっと理解した。 そもそも要らなくなったのだ。

設定

1
2
cd /etc/openvpn
sudo cp ~/Dropbox/Documents/OpenVPN/bshock.ovpn ./client.conf

設定ファイルはDropboxに既に置いてあったので、そこから拝借してる。
内容は大体こんな感じ 。

接続・終了

  • VPN接続
1
sudo service openvpn start
  • VPN切断
1
sudo service openvpn stop
  • VPN再接続
1
sudo service openvpn restart

ふつうに apt install openvpn すると常時つなぎっぱの設定になり、通常用途ではそれ以上は することないのでは。
テザリング時やサスペンドからの復帰時等、起動後にネットワーク環境が変わった時は再接続を行う。

ログ設定

ここまでで一応終わりだけど、ログを見やすくするには、以下のような設定をすると いいんじゃないだろうか。

まず、/etc/rsyslog.d/openvpn.confをこんな感じで書く。

続いて、/etc/logrotate.d/openvpnをこんな感じで。

rsyslogやlogrotateについては、詳細は割愛。

トゥートをCWに変える

その後構築したものがいくつかあり。
これらの作業ログも記事にしたいのだけど、なかなか時間がない。
今月ぐらいに上げられるといいなぁ。

今日のやつはそんなに大層なものではなく、小ネタです。
想定する読者さんは、SQLがちょっとだけわかってpsqlコマンドも扱える、 Mastodonのインスタンスを持っている管理者さん。

ネタバレを含んだ含んだトゥートをCWにする。

プリキュアのテーマインスタンス「キュアスタ!」に、いつも お世話になっている。
このようなテーマインスタンスでは、概ね「ネタバレを含むトゥートにはCWを」という 推奨がある。先日唐突に「一度送信したトゥートをCWに変えることも可能なはず」と 思い立って、軽く調べてみた。

この時点では純粋な技術的な好奇心であり、「あとからCW」の是非については一旦保留 する。これについては後ほど。

PostgreSQLに接続

手っ取り早く、 psql コマンドを叩いて試す。
FreeBSD環境でデフォルト設定でセットアップがされているなら、以下のコマンドで Mastodonのデータベースに接続できる。

1
sudo -u postgres psql mastodon

直近のトゥートを探す

CWにする対象のトゥートを特定する。
連合のトゥートを排除してローカルのトゥートのみ残し、せいぜい10件も取得すればよいのでは ないか。

1
2
3
4
5
6
7
8
9
10
11
SELECT
id, -- トゥートID
created_at, -- 投稿日
text, -- トゥート本文
spoiler_text, -- CWタイトル
sensitive -- 本文を隠すか?
FROM statuses
WHERE
local='t'
ORDER BY updated_at DESC -- 更新日降順
LIMIT 10 OFFSET 0; -- 先頭10件

目的のトゥートを見つけたら、トゥートのIDを控えておく。

トランザクションを利用しつつ更新

1年運用しているが、Mastodonのデータベースを直接更新するなんて、経験のないこと。
理由がなければやるべきじゃないし、いつでもロールバック出来る様な備えをするに越したことは ない。
もしステージング的な環境を持っているなら、そちらで試してほしい。

早速、トランザクションを開始。

1
BEGIN;

次に、実際の書き換えを行う。

1
2
3
4
5
6
UPDATE statuses SET
spoiler_text='ネタバレ注意なのです!ストーップなのです!',
sensitive='t', -- 「隠す」フラグを立てる
updated_at=now() -- 更新日付を現在時刻に
WHERE
id='00000'; -- 先程控えた、トゥートのID。絶対忘れちゃダメw

結果反映を確認

トランザクション中の更新である為、この時点ではMastodonの画面に反映しない。
画面上で確認できないので、更新の結果を確認するには、この場でSELECTする必要あり。(以下)

1
2
3
4
5
6
7
8
9
SELECT
id, -- トゥートID
created_at, -- 投稿日
text, -- トゥート本文
spoiler_text, -- CWタイトル
sensitive -- 本文を隠すか?
FROM statuses
ORDER BY updated_at DESC -- 更新日降順
LIMIT 100 OFFSET 0; -- 先頭100件

先ほどとほぼ同じだが、意図しない書き換えが行われていないか確認するために、以下の修正を行った。

  • WHERE句を削除。
  • 件数を100軒に増やす。

トランザクションの終了、又は破棄

意図通りの更新であれば、

1
COMMIT;

を実行すれば、この時点でMastodonの画面に反映。
「キャッシュのクリア」的な処理が必要かと思ったが、そうでもなかった。 おれが普段作っているものより素直な作りだなw。わかりやすくてよい。
反映を確認できた?

万一、期待した結果と異なっていたら、

1
ROLLBACK;

を実行。

「あとからCW」の是非

先ほど、「一旦保留」と言った件。

まず、技術的な観点から、やむを得ない場合のみにするべき。間違っても、これを前提にした 運用はやめたほうがいい。
DBの詳細な説明、どこかにあった?もしあるなら(どこかにあるのをおれが知らないだけかも)、 それを熟読精査した上で実行するのは、まずは技術的にはOK。

コミュニティとしてどうなのか?という問題も。
発言を容易に書き換えたり出来ると、そもそも会話が成り立たない。 出来ることならするべきではないし、仮に行うのでも、この点を念頭に置くべき。
CWは…、まぁ微妙か。会話が成り立たなくなる種類の修正ではないし。

ネタバレ禁止というのも、「推奨事項」程度のものと思っていて。
本人から「これCWにしたいんですけど〜」的な申し出があったら初めて動くぐらいで、 大抵は十分なのではないか。と、個人的には思う。

以上。