先日から再び某ポークランチョンミートによる行為が確認されるようになってきたため、いい加減にnginxとプデチゲ(スパム対策フィルター)を導入して対策を行うことにしました。ちなみにcloudflaredを導入している自宅鯖でやっています。
ちなみに悩みながら書いていたので、最終的には採用していない部分を含みます。導入自体は最後のまとめまで飛ばしても導入できるはずです。
手順(試行錯誤の過程)
Docker版nginxをリバースプロキシの第一候補として検討したものの、Dockerだとネットワーク周りで色々と面倒そうなので、とりあえず今回はローカルにnginxを導入することにしました。どっちにしろプデチゲはDockerで導入することになりますが、Misskey自体はDockerで動かしているしまぁいいでしょう。
nginxのインストール
GPGキーを追加したりするいつものやつをします。公式のをコピペして実行するだけです。
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring # 既にあるなら不要
curl "https://nginx.org/keys/nginx_signing.key" | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg # 確認のコマンド
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
"http://nginx.org/packages/ubuntu" `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx
これでインストールできるはずです。
nginxの設定
vim /etc/nginx/conf.d/misskey.conf
どうやらnginxの設定ファイルは/etc/nginx/conf.d/
以下にあるらしいので、そこにmisskey.conf
という名前のファイルを新規作成します。ファイルの内容は以下の通り(このあと書き換えるのでまだ見るだけでOK)。
# For WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
server {
listen 80;
listen [::]:80;
server_name #あなたのドメイン;
# For SSL domain validation
root /var/www/html;
location /.well-known/acme-challenge/ { allow all; }
location /.well-known/pki-validation/ { allow all; }
location / { return 301 https://$server_name$request_uri; }
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name #あなたのドメイン;
ssl_session_timeout 1d;
ssl_session_cache shared:ssl_session_cache:10m;
ssl_session_tickets off;
# To use Let's Encrypt certificate
#ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
ssl_certificate #公開鍵のpublic.pemの保存先ディレクトリをここに書く
ssl_certificate_key #シークレットキーのprivkey.pemの保存先ディレクトリをここに書く
ssl_trusted_certificate #Origin CA証明書(origin_ca_ecc_root.pemとか)の保存先ディレクトリをここに書く
# To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
#ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# SSL protocol settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
# Change to your upload limit
client_max_body_size 4000m;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_redirect off;
# If it's behind another reverse proxy or CDN, remove the following.
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 https;
# For WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Cache settings
proxy_cache cache1;
proxy_cache_lock on;
proxy_cache_use_stale updating;
proxy_force_ranges on;
add_header X-Cache $upstream_cache_status;
}
}
今回はCloudflareのSSL証明書を使うので、dash.cloudflare.comの今回使うドメインからSSL/TLSからオリジンサーバーの項目を選び、証明書を発行しておきます(この時、RSAで作ったかECCで作ったか覚えておく)。privkeyに相当するものはこの作成時しか見られないので、忘れずに保存しておきましょう(まぁ使い始める前なら発行し直せばいいのですが…)。
そして、オリジン証明書の内容を上記ファイル(misskey.conf
)で設定したディレクトリのpublic.pem
に、プライベートキーをprivkey.pem
にコピペして保存します。
次に、[warn] "ssl_stapling" ignored, issuer certificate not found for certificate
という警告に対処します1。まず、ここにアクセスし、さっき作った証明書でRSAを使ったかECCを使ったかを思い出し、同じ方のリンクを右クリックでコピーします。コピーしたURLをターミナルに貼り付け、対象のマシンで
wget https://developers.cloudflare.com/ssl/static/origin_ca_ecc_root.pem
とすれば、現在のディレクトリに新たに.pem形式のファイルがダウンロードされます。これをmisskey.conf
でssl_trusted_certificate
として指定すればよいです。
ここまでできたら次に進みます。
sudo nginx -t # 設定の読み込み
sudo systemctl enable nginx # nginxの自動起動を設定
sudo systemctl restart nginx # nginxの再起動
いけるか…?
プデチゲ
Misskeyのdocker-compose.yml
(最近はcompose.yml
なんだっけ?)に、以下を追記します。なお、追記してからdocker-compose down
はできないので、コンテナを止めてからやりましょう。
budae:
image: perillamint/budae-jjigae:latest
restart: always
command:
- "/usr/bin/budae-jjigae"
- "--backend"
- "web:3000"
networks:
- external_network
- internal_network
environment:
- RUST_LOG=info
ports:
- '127.0.0.1:7000:3000'
depends_on:
- web
特に設定をしなければ、次に行うnginxの設定をしなくてもそのまま通信はできるはずです。
nginxのmisskey.conf
に以下を追記します。ただこれはカスタムしなきゃいけないらしい。どうすればいいんだろう…?
location /inbox {
try_files $uri @budae;
}
location ~ /users/(.*)/inbox {
try_files $uri @budae;
}
location @budae {
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 https;
proxy_set_header Proxy "";
proxy_pass_header Server;
# Avoid 504 HTTP Timeout Errors
proxy_connect_timeout 605;
proxy_send_timeout 605;
proxy_read_timeout 605;
send_timeout 605;
keepalive_timeout 605;
proxy_pass http://127.0.0.1:7000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
# For WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
server {
listen 80;
listen [::]:80;
server_name #あなたのドメイン;
# For SSL domain validation
root /var/www/html;
location /.well-known/acme-challenge/ { allow all; }
location /.well-known/pki-validation/ { allow all; }
location / { return 301 https://$server_name$request_uri; }
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name #あなたのドメイン;
ssl_session_timeout 1d;
ssl_session_cache shared:ssl_session_cache:10m;
ssl_session_tickets off;
# To use Let's Encrypt certificate
#ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
ssl_certificate #公開鍵のpublic.pemの保存先ディレクトリをここに書く
ssl_certificate_key #シークレットキーのprivkey.pemの保存先ディレクトリをここに書く
ssl_trusted_certificate #Origin CA証明書(origin_ca_ecc_root.pemとか)の保存先ディレクトリをここに書く
# To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
#ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# SSL protocol settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_stapling on;
ssl_stapling_verify on;
# Change to your upload limit
client_max_body_size 4000m;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_redirect off;
# If it's behind another reverse proxy or CDN, remove the following.
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 https;
# For WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Cache settings
proxy_cache cache1;
proxy_cache_lock on;
proxy_cache_use_stale updating;
proxy_force_ranges on;
add_header X-Cache $upstream_cache_status;
}
}
location /inbox {
try_files $uri @budae;
}
location ~ /users/(.*)/inbox {
try_files $uri @budae;
}
location @budae {
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 https;
proxy_set_header Proxy "";
proxy_pass_header Server;
# Avoid 504 HTTP Timeout Errors
proxy_connect_timeout 605;
proxy_send_timeout 605;
proxy_read_timeout 605;
send_timeout 605;
keepalive_timeout 605;
proxy_pass http://127.0.0.1:7000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
終わったら
sudo nginx -t
sudo systemctl restart nginx
を実行します。とりあえず、Misskeyにアクセスできないことは無かったけど、効いてもなさそうで…→これはCloudflare Zero TrustのPublic Hostnameがポート3000を指してて、nginxを通ってなかったからっぽい
ただ設定を変えると今度はMisskeyにエラーが起こる…
解決
cloudflaredについてふんわりとしか分かってなかったことに気づき、ネットワークの図を書いてみたら解決できました。
cloudflaredはホストコンピューターからCloudflare CDNまでをトンネリングする技術です。ということはつまり、ホストの中は全部HTTPでよくて、cloudflaredのPublic HostnameをHTTPSにすると暗号化されてエラーが出ることになります。
これまでは、cloudflaredの設定で、Public HostnameをHTTPSにしたりしていましたが、これは普通にHTTPで良い(でもHTTPSはじゃあなんであるんだろう?これは要調査)。
次にnginxですが、Misskey Hubで公開されているmisskey.conf
ファイルはcloudflaredを使わない想定で書かれていて、しかもNAT超えとかしなくても普通にインターネットに出られるレンタルサーバーとかそういう環境で使うもののようでした。ということは、SSL化の設定もおかしいことになります。cloudflaredを使えばホストまでは暗号化でき、ホスト内部は安全なはずだから、もうこの時点で暗号化については考えなくて良い(やらなくていい)。
これに従って、misskey.conf
を次のように書き換えました。要するに、ポート80でnginxがリッスンするようにし、SSL関係の設定は全てコメントアウトしました。いっそのこと削除してしまってもいいはずですが、一応残しておくことにしました。
# For WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
#server {
# listen 80;
# listen [::]:80;
# server_name #あなたのドメイン;
# For SSL domain validation
# root /var/www/html;
# location /.well-known/acme-challenge/ { allow all; }
# location /.well-known/pki-validation/ { allow all; }
# location / { return 301 https://$server_name$request_uri; }
#}
server {
# listen 443 ssl;
# listen [::]:443 ssl;
listen 80;
listen [::]:80;
http2 on;
server_name #あなたのドメイン
# ssl_session_timeout 1d;
# ssl_session_cache shared:ssl_session_cache:10m;
# ssl_session_tickets off;
# To use Let's Encrypt certificate
#ssl_certificate /etc/letsencrypt/live/example.tld/fullchain.pem;
#ssl_certificate_key /etc/letsencrypt/live/example.tld/privkey.pem;
#ssl_certificate #公開鍵のpublic.pemの保存先ディレクトリをここに書く
#ssl_certificate_key #シークレットキーのprivkey.pemの保存先ディレクトリをここに書く
#ssl_trusted_certificate #Origin CA証明書(origin_ca_ecc_root.pemとか)の保存先ディレクトリをここに書く
# To use Debian/Ubuntu's self-signed certificate (For testing or before issuing a certificate)
#ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
#ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
# SSL protocol settings
# ssl_protocols TLSv1.2 TLSv1.3;
# ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
# ssl_prefer_server_ciphers off;
# ssl_stapling on;
# ssl_stapling_verify on;
# Change to your upload limit
# client_max_body_size 4000m;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_redirect off;
# If it's behind another reverse proxy or CDN, remove the following.
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 https;
# For WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Cache settings
proxy_cache cache1;
proxy_cache_lock on;
proxy_cache_use_stale updating;
proxy_force_ranges on;
add_header X-Cache $upstream_cache_status;
}
}
location /inbox {
try_files $uri @budae;
}
location ~ /users/(.*)/inbox {
try_files $uri @budae;
}
location @budae {
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 https;
proxy_set_header Proxy "";
proxy_pass_header Server;
# Avoid 504 HTTP Timeout Errors
proxy_connect_timeout 605;
proxy_send_timeout 605;
proxy_read_timeout 605;
send_timeout 605;
keepalive_timeout 605;
proxy_pass http://127.0.0.1:7000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
次に、cloudflaredの設定をします。といっても、Public Hostnameのポート番号を、上記misskey.conf
に合致するように変更するだけでOKです。プロトコルはHTTPのままにします。
これで正常にプデチゲにinboxの通信が割り振られるようになり、ポークランチョンミートの投稿が弾かれるようになりました。プデチゲに感謝…
設定方法まとめ
1. サーバーにnginxをインストール
sudo apt install curl gnupg2 ca-certificates lsb-release ubuntu-keyring # 既にあるなら不要
curl "https://nginx.org/keys/nginx_signing.key" | gpg --dearmor \
| sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null
gpg --dry-run --quiet --no-keyring --import --import-options import-show /usr/share/keyrings/nginx-archive-keyring.gpg # 確認のコマンド
echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
"http://nginx.org/packages/ubuntu" `lsb_release -cs` nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list
sudo apt update
sudo apt install nginx
nginxの設定ファイルを作り(misskey.conf)、それにnginxの設定を追記
なお、レンタルサーバーなどで既にnginxを使用している場合は異なるので注意する。
# For WebSocket
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=cache1:16m max_size=1g inactive=720m use_temp_path=off;
server {
# listen 443 ssl;
# listen [::]:443 ssl;
listen 80;
listen [::]:80;
http2 on;
server_name #あなたのドメイン;
# Proxy to Node
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_redirect off;
# If it's behind another reverse proxy or CDN, remove the following.
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 https;
# For WebSocket
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
# Cache settings
proxy_cache cache1;
proxy_cache_lock on;
proxy_cache_use_stale updating;
proxy_force_ranges on;
add_header X-Cache $upstream_cache_status;
}
}
location /inbox {
try_files $uri @budae;
}
location ~ /users/(.*)/inbox {
try_files $uri @budae;
}
location @budae {
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 https;
proxy_set_header Proxy "";
proxy_pass_header Server;
# Avoid 504 HTTP Timeout Errors
proxy_connect_timeout 605;
proxy_send_timeout 605;
proxy_read_timeout 605;
send_timeout 605;
keepalive_timeout 605;
proxy_pass http://127.0.0.1:7000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
以下のコマンドを実行する。
sudo nginx -t # 設定の読み込み
sudo systemctl enable nginx # nginxの自動起動を設定
sudo systemctl restart nginx # nginxの再起動
docker-compose.ymlにbudae-jjigaeの項目を追記
適用したいMisskeyサーバーのdocker-compose.yml
があるディレクトリに移動し、Dockerコンテナをdocker-compose down
などで止めた後、docker-compose.yml
(今はcompose.yml
)を編集する。編集後のファイルは以下の通りです(version
とか色々古い書き方です)。
version: "3"
services:
web:
build: .
restart: always
links:
- db
- redis
# - es
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "3000:3000"
networks:
- internal_network
- external_network
volumes:
- ./files:/misskey/files
- ./.config:/misskey/.config:ro
redis:
restart: always
image: redis:7-alpine
networks:
- internal_network
volumes:
- ./redis:/data
healthcheck:
test: "redis-cli ping"
interval: 5s
retries: 20
db:
restart: always
image: postgres:15-alpine
shm_size: 1G
networks:
- internal_network
env_file:
- .config/docker.env
volumes:
- ./db:/var/lib/postgresql/data
healthcheck:
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
interval: 5s
retries: 20
budae:
image: perillamint/budae-jjigae:latest
restart: always
command:
- "/usr/bin/budae-jjigae"
- "--backend"
- "web:3000"
networks:
- external_network
- internal_network
environment:
- RUST_LOG=info
ports:
- '127.0.0.1:7000:3000'
depends_on:
- web
networks:
internal_network:
internal: true
external_network:
できたら止めていたサーバーを起動する。
docker-compose up -d
cloudflaredのPublic Hostnameを編集
cloudflaredの設定を開き、TunnelsのPublic Hostnameを編集する。具体的には、nginxが待ち受け(リッスン)しているポート番号にする。プロトコルはHTTPのまま。ポークランチョンミートが弾かれていればOK!
参考情報
- お一人様用Misskeyを立てて、お仕事備忘録を実現するマイクロブログSNSを作る – 3. nginxインストール編 │ きよさんが果てるまで。 https://kiyosan.life/2023/09/13/nginx-install/
- nginxによるWeb公開|Docker ComposeによるMisskeyサーバー構築 ~メールを送るまで~ https://zenn.dev/hal_shu_sato/books/misskey-docker-compose-mail/viewer/nginx
- Nginxの設定 | Misskey Hub https://misskey-hub.net/ja/docs/for-admin/install/resources/nginx/
- Origin CA certificates | Cloudflare SSL/TLS docs https://developers.cloudflare.com/ssl/origin-configuration/origin-ca/#cloudflare-origin-ca-root-certificate
- nginxでCloudflareのオリジン証明書のエラーが出るので対処する https://zenn.dev/waya0125/articles/d00a4fdc891aa1 ↩︎