FreeBSDにP2P掲示板新月のsakuを導入して運用する

概要
======
筆者は、P2P型掲示板の一つ「新月 - P2P匿名掲示板」の公式ノード実装sakuをFreeBSD上で運用しています。
FreeBSDでのsaku導入・運用方法を備忘録として残します。
GNU/Linuxや他UNIX系OSなどでもある程度参考にできるかもしれません。

新月 - P2P匿名掲示板とは
======
https://shingetsu.info/index.ja

[2003年8月29日にfukutommy氏が発表](https://pc8.5ch.net/test/read.cgi/tech/999431595/572)した、オープンソースのP2P掲示板です。
新月プロトコルにしたがって互いに通信するノード群が新月ネットワークを構成しています。

https://shingetsu.info/protocol/protocol-0.7.d1.ja

ユーザはソフトウェアを実行してノードとして参加したり、公開ゲートウェイと呼ばれるノードを利用したりして投稿や閲覧ができます。

公式の公開ゲートウェイ

https://bbs.shingetsu.info/gateway.cgi

現在は[saku](https://github.com/shingetsu/saku)が公式の実装として開発されています。他にも[Gou](https://github.com/shingetsu-gou/shingetsu-gou)などいくつかの実装があります。

2023年8月で発表から20年が経ちますが、現在（2023年7月）もおよそ10～20個のノードが運用中です。

筆者の環境
======
さくらインターネットのさくらのVPS 1GBプランを使用しています。
OSはFreeBSD 13.2です。

VPSにFreeBSDインストール
======
さくらインターネットでは以前はコントロールパネルからカスタムOSインストールでFreeBSDをインストールできましたが、現在はISOイメージから起動が必要なようです。

https://vps.sakura.ad.jp/specification/

サーバのセキュリティ設定
======
saku導入前にセキュリティ設定をします。
やらなくても運用できますがセキュリティ上実施したほうがベターです。
- sudo権限付き管理者ユーザ作成（rootユーザはなんでもできてしまうため危険）
- sshのrootログイン無効化（外部の攻撃者が直接rootにログインするのを防ぐ）
- sshで公開鍵認証のみにする（パスワード認証よりもセキュア）
- OSパッケージアップグレード（脆弱性対策等のため。運用中は定期的に必要。アップグレード後はOS再起動することで各種サービス等も新しいバージョンとなる）
- etc.

パッケージ導入
======
Gitインストール（必要な場合）
------
```console
$ sudo pkg install git
```

Pythonインストール
------
デフォルトのPython 3.9（2023年7月9日現在）で問題ない場合は不要です。筆者はPython3.11を導入しています。
FreeBSDのパッケージは全般的にそうですがportsのほうがバージョンが新しいと思います。もしくはpython.orgからソースコードをダウンロードしてビルドでもよさそうです。
```console
$ sudo pkg install py311 # pkg
$ sudo portmaster lang/py311 # portmaster
```

pipインストール
------
```console
$ python3 -m ensurepip
```

saku導入
======

sakuダウンロード
------
sakuをダウンロードします。Gitでリポジトリをクローンする方法と、リリースされているファイルをダウンロードする方法があります。

### Gitリポジトリクローン

```console
$ git clone https://github.com/shingetsu/saku.git
```
最新コミットはリリース済みのバージョンより進んでいることがあるため、安定版で運用したい場合はバージョンのタグ付きコミットへ移動します。

```console
$ git checkout release-4.11.0
```

### 公式サイトよりダウンロード
以下ページから最新の安定版もしくは不安定版をダウンロードします。

https://shingetsu.info/saku/ 

ダウンロード後、適当なディレクトリに展開します。

sakuをインストールする場合
------
朔のインストールする場合の手順を参考にインストールできると思います。
筆者はインストールしていないため省略します。

https://shingetsu.info/saku/

sakuをインストールしない場合
------
### pipenv導入
v4.10.0以降のsakuは実行時にpipenvを使います。pipでインストールできます。
```console
$ pip install pipenv
```

w3mインストール
------
サーバにてsakuの画面へアクセスする際利用できるコマンドライン用Webブラウザです。
```console
$ sudo pkg install w3m
```

saku設定
======

saku.ini
------
sakuの基本の設定です。設定ファイルとして以下を読み込みます。下にいくほど設定が優先されます。
```text
file/saku.ini
/usr/local/etc/saku/saku.ini
/etc/saku/saku.ini
~/.saku/saku.ini
```

例
```ini
[Network]
port: 8000
dnsname: example.com

[Gateway]
visitor: .
admin: ^127
friend: ^127

[Application Thread]
save_record: 0
save_removed: 0
get_range: 32140800 
sync_range: 32140800
```

### 設定のパラメータ一覧（v4.11.0）
#### Networkセクション
|名前|デフォルト値|説明|
|:--|:--|:--|
|port|8000|listenするポート|
|dat_port|8001|2ch interfaceのlistenするポート|
|dnsname||/server.cgiへのdnsname以外のアクセスをブロックする。ドメイン名でのアクセスをOKにしてIPアドレスはNGにするイメージ。v4.11.0で追加|
|max_connection|20|最大コネクション数|

#### Pathセクション
|名前|デフォルト値|説明|
|:--|:--|:--|
|docroot|./www||
|log_dir|./log||
|run_dir|../run||
|file_dir|../file||
|cache_dir|../cache||
|template_dir|../template||
|spam_list|../file/spam.txt||
|initnode_list|../file/initnode.txt||
|node_allow|../file/node_allow.txt||
|node_deny|../file/node_deny.txt||
|apache_docroot|/var/local/www/shingetsu||
|archive_dir|/var/local/www/archive||

#### Gatewayセクション
/gateway.cgiに関する設定です。
|名前|デフォルト値|説明|
|:--|:--|:--|
|admin|^127|管理者用機能を使えるIPアドレス（正規表現可）|
|friend|^127|スレッド新規作成機能などを使えるIPアドレス（正規表現可）|
|visitor|.|画面を見られるIPアドレス（正規表現可）。「.」にすると誰でも閲覧可（＝公開ゲートウェイ）になる。|
|server_name||サーバ名とポート番号。例：example.com:8000|
|gateway_protocol|http|httpsかhttp|
|tag_size|20|タグの最大数|
|rss_range|259200|RSSの範囲。3\*24\*60\*60（秒）|
|top_recent_range|259200|トップページrecentnの表示範囲。3\*24\*60\*60（秒）|
|recent_range|recentページの表示範囲。2678400|31\*24\*60\*60（秒）|
|record_limit|2048|レコードのサイズ制限（kB）|
|proxy_destination|proxy_destination|プロキシサーバのサーバ名とポート。例：example.com:8000|
|archive_uri|https://archive.shingetsu.info/||
|enable2ch|False|2ch interface|
|root_index|gateway.cgi|rootのインデックス|

#### Application Threadセクション
|名前|デフォルト値|説明|
|:--|:--|:--|
|save_record|0|レコード保持期間（秒）。0は無制限|
|save_size|1|save_recordの期間経過後、最低限保持するレコードの個数|
|get_range|2678400|初回取得時の取得範囲。0は無制限。31\*24\*60\*60（秒）|
|sync_range|864000|定期取得時の取得範囲。0は無制限。10\*24\*60\*60（秒）|
|save_removed|4320000|50\*24\*60\*60（秒）|
|page_size|50|ページのレコード表示数|
|thumbnail_size|None|サムネイルを作る。PIL.Imageライブラリが必要。最大幅x最大高で指定。例：400x400|
|force_thumbnail|False||

spam.txt
------
スパムフィルタです。正規表現で記述できます。
1行目でファイルの文字コードを指定します。

例
```text
# -*- coding: utf-8 -*-
#
# Regexp list for spam posts.
# Copyright (c) 2006,2014 shinGETsu Project.
#
# Encoding must be UTF-8.
#
# Write one regexp per one line.
# The regexp is tested for a record line.
#
# Example:
#    <>body:This is SPAM
#    [Tt]his is (SPAM|Spam)
#    This.*Spam
#

<>mail:[^@]+@[^.]+\..+
<>body:[ -~]<>mail:[ -~]+<>name:[ -~]+$
```
https://github.com/shingetsu/docs/blob/master/spam-filters-elementary.md

initnode.txt
------
初期ノードです。

node_allow.txt
------


node_deny.txt
------
隣接ノードや探索ノードとして登録しないノードです。

version.txt
------
Gitで運用している場合、コミットのタイムスタンプをサーバの返すレスポンスのヘッダ情報に付与できます。
例：shinGETsu/0.7 (Saku/4.11.0; **git/20230612-0010**) Python/3.11.4

```console
$ make version
$ cat file/version.txt
20230612-0010
```

運用方法
======

saku起動(pipenv版)
------
```console
$ pipenv --python /usr/local/bin/python3.11 install
$ nohup pipenv --python /usr/local/bin/python3.11 run python3.11 ./saku.py --silent > /dev/null 2>&1 &
```

saku停止(pipenv版)
------
```console
$ p_id=$(ps | grep "./saku.py" | grep -v grep | awk '{print $1}')
$ kill $p_id
```

サーバのステータス
------
Statusページでノード情報を参照できます。
Known Nodesがページ閲覧時点の新月ネットワークノード数とおおよそ等しくなります。
```text
Linked Nodes 6
Known Nodes  10
BBSes        60
Articles     3966
Cache Size   6.4MB
Self node    node0.example.com:8000/server.cgi

Linked Nodes

  • node1.example.com:8000/server.cgi

Known Nodes

  • node1.example.com:8000/server.cgi
  • node2.example.com:8000/server.cgi
```

スレッド取得
------
管理者として自ノードに存在しないスレッドにアクセスするとネットワーク上から投稿を取得できます。
Recentページに他ノードで最近投稿があったスレッドがリストアップされています。

スレッド削除
------
削除したいスレッドにチェックを入れてDelete BBSをクリック

投稿削除
------
削除したい投稿にチェックを入れてDelete articleをクリック

sakuのバージョンアップ
------
設定ファイル等を編集していなければダウンロードして上書き更新で特に問題ないと思います。Gitでクローンしておくと`git pull`で最新版に更新できます。

依存パッケージのバージョンアップ
------
```console
$ pip list --outdated # pipの更新されていないモジュールを出す
$ pip install --upgrade <モジュール名> # アップグレード
$ pipenv update # sakuの依存パッケージをバージョンアップ
```

注意点
======
投稿の完全な削除は難しい
------
自ノードの投稿は削除可能で削除通知を他ノードに出すこともできますが、実際に消すかは各ノード管理者の判断になります。

著作権侵害コンテンツ等に注意
------
公開ゲートウェイの場合は通常のWebサイトと同様に外部から閲覧できる状態になります。著作権侵害している投稿などは削除したり、そもそも怪しそうなスレッドは取得しないようにしたりする対策が必要と思います。

その他
======
- FreeBSD jailでコンテナ化もしてみたいです。
- 疑問点や運用での困り事は[新月の開発](https://bbs.shingetsu.info/thread.cgi/%E6%96%B0%E6%9C%88%E3%81%AE%E9%96%8B%E7%99%BA)や[公開ゲートウェイ管理者会](https://bbs.shingetsu.info/thread.cgi/%E5%85%AC%E9%96%8B%E3%82%B2%E3%83%BC%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A4%E7%AE%A1%E7%90%86%E8%80%85%E4%BC%9A)などで質問すると解決するかもしれません。

参考
======
設定ガイド

https://shingetsu.info/saku/config

サンプル設定

https://github.com/shingetsu/saku/blob/master/doc/sample.ini

デフォルト設定

https://github.com/shingetsu/saku/blob/master/shingetsu/config.py