- ① SSH、ユーザー追加
- ② IPv4/IPv6追加、netplan、ufw
- ③ Apache2
- ④ Let's Encrypt
- ⑤ PHP
- ⑥ MariaDB
- ⑦ WordPress
- ⑧ Dovecot、Postfix
- ⑨ Vsftpd
- ⑩ Python
- ⑪ llama.cpp、ChromaDB
- ⑫ Anaconda、Keras、TensorFlow
- ⑬ Node.js
- ⑭ MongoDB
- ⑮ Mosquitto
- ⑯ RabbitMQ
- ⑰ Supervisor
01旧サイト設定の棚卸し
5サイト分の設定を一括で書き直す前に、実際に使っているsasagawa.tokyoの設定ファイルを読み解いて、 今も必要なものと、そうでないものを仕分けた。
- mod_wsgiの実利用箇所:sasagawa.tokyo自体ではなく、iseeit.jpのMNISTデモ・word2vecツールが専用venv(
python-home=/home/login-user/env3.12)経由で使用。それぞれMosquitto・RabbitMQ経由でモデルへ接続する構成(この部分の詳細は⑮⑯で改めて記事化予定) - KeepAlive / KeepAliveTimeout:VirtualHost内に書かれていたが、この2つはApacheの仕様上
server configコンテキストのみ有効で、VirtualHost内に置いても構文エラーにはならないものの「同じIP:ポートの最初のVirtualHostの値が全体に適用される」という紛らわしい挙動になる。5サイト共存を機にapache2.conf側へ移設 - 死んでいたコメントアウト行:WebSocketプロキシが
ws://からwss://へ切り替わった際の旧設定の残骸。削除 - SSLProxy系の証明書検証無効化設定:127.0.0.1へのループバック接続専用なのでそのまま維持
02VirtualHostのIPバインド設計
②で確保できた追加IPv4は1個のみだったため、5サイトはこの1個をSNI(Server Name Indication)による名前ベース仮想ホストで共有する。 一方IPv6は17個使えるため、サイトごとに専用の1個を割り当てた。
| サイト | IPv6(下4桁) |
|---|---|
| iseeit.jp | ...xx1 |
| gwaw.jp | ...xx2 |
| appw.jp | ...xx3 |
| ibe.tokyo | ...xx4 |
| sasagawa.tokyo | ...xx5 |
443側のVirtualHostは共有IPv4とサイト専用IPv6の両方を明示バインドする。*:443のままでも動作はするが、
標準IPv4(メール・管理用)側にWebコンテンツが一切乗らない、という設計意図が設定上はっきり見える形にした。
80側は平文HTTPなのでSNIは関係なく、Hostヘッダーで振り分けられる。*:80のまま、
ServerName・DocumentRoot・ログパスだけをサイトごとに調整すればよい。
5サイト×2ポート(80/443)=10ファイルという構成自体は変更せず維持した。
.well-known/acme-challenge/用の設定を入れるかどうかは、Let's EncryptをHTTP-01(webroot)で取るかDNS-01にするかの判断待ち。この点は④で扱う。
03Apache2本体とモジュールのインストール
libapache2-mod-wsgi-py3を入れるとシステムのデフォルトPython(Ubuntu 26.04では3.14)にリンクされる。
一方、MNIST・word2vecはTensorFlowの都合上Python 3.12系のvenvで動かす必要があり、このままではバージョン不一致で動かない。
対応にはmod_wsgiを3.12venv内からpip installして個別にビルドする必要があるため、⑩Pythonの回でvenv構築と合わせて対応することにした。
045サイト分のVirtualHostを反映
棚卸しの内容を反映し、10ファイル(5サイト×80/443)を修正した。
05Apache(www-data)とPHP(login-user)の権限を分ける
ドキュメントルートは/home/login-user/www/...で所有者はlogin-user。旧サーバーではXML-RPC経由の画像アップロードがパーミッションで失敗し、
/etc/apache2/envvarsのAPACHE_RUN_USER/APACHE_RUN_GROUPをlogin-userに変更するなどして解決した記憶があったが、
これはApache全体(=5サイト共通のプロセス)がlogin-user権限で動くことを意味し、1サイトの脆弱性が他サイトへ波及する範囲を広げてしまう。
今回は役割を分けることにした。
| 役割 | 実行ユーザー | 権限 |
|---|---|---|
| Apache本体(静的配信・プロキシ) | www-data(デフォルトのまま) | 読み取りのみ |
| PHP(WordPress本体) | login-user(PHP-FPMのpool設定で指定、⑤で対応) | 書き込み可 |
envvarsは変更せずwww-dataのまま維持し、書き込み(アップロード含む)はPHP-FPM側のpool設定に任せる。
Apache自体はサイトの中身に対して書き込み権限を持たない。
ただし/home/login-userはデフォルトのパーミッションだと所有者以外アクセス不可のことが多く、www-dataがそもそも中に入れない可能性がある。
「その他」に開放するのではなく、www-dataをlogin-userグループに入れる形で対応した。
06ここまでの状態
- Apache2本体・標準モジュール(http2, proxy, proxy_wstunnel, rewrite, setenvif, ssl)導入済み。mod_wsgiは⑩へ先送り
- 5サイト×2ポート=10ファイルのVirtualHostを、共有IPv4+サイト別IPv6の明示バインドへ更新
- KeepAlive設定はapache2.confへ集約、死んだコメント行を削除、.htpasswdを移行
- Apache(www-data・読み取り専用)とPHP(login-user・書き込み可)の権限分離方針を決定