2024年5月1日から ipv4 アドレスが紐づいている lightsail instance が値上がりする [1]。 現在使用中の linux-based bundle (0.5 GM RAM, 20GB SSD plan) は 3.50 USD から 5.00 USD まで値上がりする。 この機に ipv6 instance に migration し、ipv4 からのアクセスは cloudfront 等でうまく proxy してやろうと思っていたが、 現状では cloudfront はオリジンと ipv4 で通信する必要があり、結局 ipv4 アドレスを買わないといけない [2]。 Cloudflare のサービスを使えばうまくいくようだが [3]、アカウントを持っていないし、無料プランを使いたくないが有料プランは役不足で高価なので AWS で完結させたい。 Cloudfront が ipv6 のみでオリジンと通信する機能は開発予定が (時期未定なものの) ある [2] ので、このときを待ってしばらくは ``tax" を支払うことにした。 きたる機能追加時の migration に備えて、現状わかっている手順を残す。

何をやっているのかはよくわかっていない。

General Procedure

  • インスタンスの Snapshot を作成
  • Snapshot から ipv6-only instance を作成
  • Route 53 で AAAA レコードを作成
  • nginx の ipv6 対応
  • SSL/TLS 証明書の更新
  • S3 の addressing style で ipv6 を許可
  • zotero 添付ファイル保管用 webdav サーバのための S3 bucket mountpoint の ipv6 対応
  • Cloudfront による ipv4 to ipv6 conversion proxy の設定 (未調査)

nginx の ipv6 対応

listen directive に ipv6 を受け付ける旨 [4] を記述する。

listen 443;
listen [::]:443;

SSL/TLS 証明書の更新

webroot でチャレンジするので、sites-enabled 内のスクリプトの、80 番ポートを受け付ける server ブロックにて https にリダイレクトする部分をコメントアウトする。 webroot をサーブする部分は include /etc/nginx/letsencrypt.conf;。 443 を受け付ける server ブロックをコメントアウト。ssl_certificate ディレクティブにてファイルが見つからなく起動時のコンフィグチェックでエラーが出るため。 lego run コマンドを適当なオプションとともに実行して証明書を発行する。

もっといいやり方があると思う。一番上の階層で /.well-known のアクセスをいいかんじにルーティングするとか。

S3 の addressing style で ipv6 を許可

以下を実行しておく。これをやらないと aws cli で S3 に接続すらできない [5]。

aws configure set default.s3.use_dualstack_endpoint true
aws configure set default.s3.addressing_style virtual

zotero 添付ファイル保管用 webdav サーバのための S3 bucket mountpoint の ipv6 対応

zotero は添付ファイルを WebDav サーバ経由で動機できる。 したがって、添付ファイルを WebDav サーバ経由で S3 に保存するために

zotero client --> nginx の WebDav 実装 --> goofys (S3 バケットをファイルシステムとして使うためのサービス) --> S3

という経路を取っていた。ここで、 goofys は ipv4 のみ対応であるから ipv6 (dualstack) 対応の別サービスを採用したい。

mountpoint-s3 を採用することを考える。 これは dualstack 対応だが、rename システムコールに対応していない。 一見今回の用途に rename は不要そうだが、nginx の webdav 実装は PUT を受け付けた際、 client body を一度一時ファイルとして (client_body_temp_file に) 保存してからリクエストがあったパスに rename する。 S3 マウントポイント内での rename を回避するために client_body_temp_file を別ファイルシステムに設定すれば良さそうだが、そうすると client_body_temp_file は無視され、もとのリクエストパスに連番をつけた場所を temp file として使用し、結局 S3 マウントポイント内で rename してしまう。 マニュアル [5] には

Starting from version 0.8.9, temporary files and the persistent store can be put on different file systems

とあるが、どうやってもうまくいかない。ログを見ても client_body_temp_file を設定したあとそれを無視したファイルを作っていて、どういう挙動なのかよくわからない。 バグの可能性を考え最新版を使おうと思ったが、zotero は PROPFIND を発行し、これは拡張モジュールでしかサポートされておらずソースからビルドが必要になるため面倒になってやめた。 しょうがないので、webdav リクエストを受け付けて S3 API を叩く webserver を自分で書く (TODO)。

https://gist.github.com/staaldraad/d835126cd46969330a8fdadba62b9b69 ←これを参考にする。

webdav 実装のもう一つの案として、サーバーはファイルシステムを触り、S3 とのやりとりは mountpoint-s3 にやらせるものもある。 メリットは実装が楽なところ。 もしこれをやりたくなったときのために、mountpoint-s3 のデーモンの作り方を残しておく (fuse は未対応)。

[Unit]
Description=Mountpoint for Amazon S3 mount
Wants=network.target
AssertPathIsDirectory=/mnt/zoteros3/zotero

[Service]
Type=forking
User=root
Group=root
ExecStart=/usr/bin/mount-s3 --dual-stack --allow-other --allow-delete --allow-overwrite --file-mode=0666 --dir-mode=0777 --uid=33 --gid=33 coppelab-zotero-storage /mnt/zoteros3/zotero
ExecStop=/usr/bin/fusermount -u /mnt/zoteros3/zotero

[Install]
WantedBy=remote-fs.target

おわりに

貧乏暇なし

References