[{"data":1,"prerenderedAt":178},["ShallowReactive",2],{"tag-diary":3,"tag-diary-articles-1":13},{"contents":4,"totalCount":11,"offset":12,"limit":11},[5],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},"4oy2jc8mdg","2025-04-28T07:14:01.179Z","2025-12-03T16:08:24.495Z","diary","日記",1,0,{"contents":14,"totalCount":176,"offset":12,"limit":177},[15,37,59,69,83,100,110,125,134,143,155,165],{"id":16,"createdAt":17,"updatedAt":18,"publishedAt":19,"revisedAt":18,"title":20,"content":21,"tags":22,"is_no_index":36},"hp0fd0z-gnnt","2026-07-04T12:48:34.820Z","2026-07-04T13:57:28.343Z","2026-07-04T13:11:31.078Z","塩漬けのMisskey v12を最新版にアップグレードする","\u003Ch1 style=\"text-align: start\" id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp style=\"text-align: start\">どうも、わたしです。\u003C/p>\u003Cp style=\"text-align: start\">先日、お友達の運営する2つのMisskeyインスタンスを、v12.119.1ベースのフォークから最新の2026.6.0ベースの\u003Ca href=\"https://github.com/lqvp/misskey-tempura\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">別フォーク(tempura)\u003C/a>へ移行しました。およそ3年半の塩漬けインスタンスです。\u003Cbr>バックアップはありませんでしたし、FWもなく、inbound全解放の状態でした。よく今まで無事だったなと。\u003C/p>\u003Cp style=\"text-align: start\">旧サーバはConoHa VPS上のUbuntu 22.04にMisskey install shell scriptで構築された環境でした。これをKAGOYA VPSのUbuntu 26.04へDocker構成で丸ごと引っ越します。DBはPGroonga入りのPostgreSQL18にし、\u003Ccode>files/\u003C/code>配下にあったメディア類はR2へ、デプロイはcompose-cdでGitOps化するところまでやりました。当エントリはその備忘録です。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h8aea7b1b68\">移行前と移行後\u003C/h1>\u003Ctable>\u003Ctbody>\u003Ctr>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>\u003C/p>\u003C/th>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>旧\u003C/p>\u003C/th>\u003Cth colspan=\"1\" rowspan=\"1\">\u003Cp>新\u003C/p>\u003C/th>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>サーバ\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>ConoHa VPS(Ubuntu 22.04)\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>KAGOYA VPS(Ubuntu 26.04LTS)\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>Misskey\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>v12.119.1フォーク(systemd)\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>tempura 2.0.9(Docker)\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>DB\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>PostgreSQL15\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>PostgreSQL18.4+PGroonga\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>全文検索\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>無し\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>PGroonga\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>メディア\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>ローカル\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>Cloudflare R2\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>リバースプロキシ\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>nginx+certbot\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>Caddy+Cloudflare Origin証明書\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>バックアップ\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>無し\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>R2へ1日2回\u003C/p>\u003C/td>\u003C/tr>\u003Ctr>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>デプロイ\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>\u003C/p>\u003C/td>\u003Ctd colspan=\"1\" rowspan=\"1\">\u003Cp>compose-cd\u003C/p>\u003C/td>\u003C/tr>\u003C/tbody>\u003C/table>\u003Cp style=\"text-align: start\">compose一式は、以前\u003Ca href=\"https://misskey.blue/\" target=\"_blank\" rel=\"noopener noreferrer\">misskey.blue\u003C/a>用に組んだ\u003Ca href=\"https://github.com/chan-mai/misskey.blue-docker-provision\" target=\"_blank\" rel=\"noopener noreferrer\">provisionレポジトリ\u003C/a>を下敷きにしています。 概ね中身は\u003Ca href=\"https://mq1.dev/entry/krpvl5itbr9h\" target=\"_blank\" rel=\"noopener noreferrer\">以前書いた構築記事\u003C/a>のものです。\u003Cbr>成果物は\u003Ca href=\"https://github.com/miel-misskey/rochka.club-docker-provision\" target=\"_blank\" rel=\"noopener noreferrer\">ここ\u003C/a>に置いてあります。\u003C/p>\u003Cp style=\"text-align: start\">\u003Ca href=\"https://github.com/miel-misskey/rochka.club-docker-provision\" target=\"_blank\" rel=\"noopener noreferrer\">\u003Cu>https://github.com/miel-misskey/rochka.club-docker-provision\u003C/u>\u003C/a>\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"hd196191eab\">アップグレードの方針\u003C/h1>\u003Cp style=\"text-align: start\">フォークのまま多段アップグレードはしません。というより、できませんでした。\u003C/p>\u003Cp style=\"text-align: start\">旧サーバが使っていたv12.119.1ベースのフォークは元レポジトリ自体がすでに消滅していて、差分をたどって移行パスを検証するという選択肢がなかったためです。なのでDBをバニラ相当とみなし、上流の通常アップグレード手順にそのまま追従させて最新版まで上げてから、最後にtempuraフォーク差分を適用することにしました。\u003C/p>\u003Cp style=\"text-align: start\">手順としては、旧サーバで\u003Ccode>pg_dump\u003C/code>したものを新サーバのpostgres:15コンテナへ\u003Ccode>pg_restore\u003C/code>し、あとはappイメージのtagを差し替えて起動、マイグレーションの完走を見届けてまた次のtagへ。\u003C/p>\u003Cp style=\"text-align: start\">ここで\u003Ccode>docker compose exec -T\u003C/code>がstdinを消費することにハマりました。スクリプトを流し込む段階で、execが残りのスクリプトをstdinとして食ってしまい、以降のコマンドが実行されなかったためです。restoreやインデックス作成がエラーを出さずに飛ぶので気づきにくいですが、SQLは\u003Ccode>&lt; file\u003C/code>、参照系は\u003Ccode>&lt;/dev/null\u003C/code>で明示的にリダイレクトするといいでしょう。\u003C/p>\u003Cp style=\"text-align: start\">今回は、12.119.1 → 13.14.2 → 2023.12.2 → 2024.10.0 → 2025.1.0 → 2026.6.0 → tempura 2.0.9の順でアップグレードしました。最大の難所はv12→v13で、かなり大規模な差分が入っています。マイグレーション数でいうと350本前後、tempura独自の57本を足して最終的に400本ちょっとでした。 \u003C/p>\u003Cp style=\"text-align: start\">v12からの移行で苦しんだことも記憶に新しいですが、もう3年前なんですね、あれ。\u003C/p>\u003Cp style=\"text-align: start\">移行に際して、\u003Ccode>default.yml\u003C/code>の項目も幾分か変わっているのですが、id方式(aid)だけは全世代を通して変えないことが必要です。これはデータの整合性を担保するために必須です。\u003C/p>\u003Cp style=\"text-align: start\">また、PG15からPG18への移行はメジャーバージョン跨ぎなのでデータディレクトリの流用はできず、ここもdump/restoreで行いました。PGDATAが\u003Ccode>/var/lib/postgresql/18/docker\u003C/code>にあるので、親ディレクトリごとマウントすれば永続化できます。今回は合わせてPGroongaの導入も行っているので、\u003Ccode>CREATE EXTENSION pgroonga\u003C/code>して\u003Ccode>note.text\u003C/code>にインデックスを張り、\u003Ccode>fulltextSearch: sqlPgroonga\u003C/code>を有効にしました。v12には無かった全文検索が使えるようになりました。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h19474baa06\">メディア移行とMIME\u003C/h1>\u003Cp style=\"text-align: start\">\u003Ccode>drive_file\u003C/code>は53,534行ありましたが、ローカルに実体を持つのは4,007件だけで、残り49,527件はリモートのリンク参照でした。ファイルそのものは9,564個(原本4,007+サムネイル3,898+webpublic1,659)で計8.8GiBほどありました。これらをまとめて旧サーバからrcloneでR2へ直接上げました。\u003C/p>\u003Cp style=\"text-align: start\">DB側の既存メディアのURL書き換えは、\u003C/p>\u003Cpre>\u003Ccode class=\"language-sql\">UPDATE drive_file SET url = replace(url, &apos;https://&lt;domain&gt;/files/&apos;, &apos;https://media.&lt;domain&gt;/local/&apos;) WHERE ...;\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">で行い、空のフィールドは空のまま残るので404は出ません。非空URLの合計(4,007+3,898+1,659=9,564)が物理ファイル数とぴったり一致したことを確認しました。\u003C/p>\u003Cp style=\"text-align: start\">また、リモートには\u003Ccode>files/\u003C/code>配下のファイルを参照するデータが残っていることを考慮し、アプリケーションの前段に置いているCaddyでリダイレクトする経路をあわせて用意しています。\u003C/p>\u003Cpre>\u003Ccode>example.com {\n\ttls /etc/ssl/certs/certificate.pem /etc/ssl/private/key.pem\n\tencode gzip\n\theader /assets Cache-Control &quot;public, max-age=31536000, immutable&quot;\n\tfile_server\n\n\tlog {\n\t\toutput file /var/log/caddy/access.log {\n\t\t\troll_size 500mb\n\t\t\troll_keep 10\n\t\t}\n\t\tformat json {\n\t\t\ttime_format iso8601\n\t\t}\n\t}\n\n\t# 旧メディアURLをR2へ\n\t@legacyfiles path_regexp legacyfiles ^/files/(.*)$\n\tredir @legacyfiles https://media.example.com/local/{re.legacyfiles.1} permanent\n\n\treverse_proxy app:3000 {\n\t\theader_up X-Real-IP {header.CF-Connecting-IP}\n\t\theader_up X-Forwarded-For {header.CF-Connecting-IP}\n\t\theader_up X-Forwarded-Proto {scheme}\n\t\theader_up X-Forwarded-Host {host}\n\n\t\thealth_uri /\n\t\thealth_interval 10s\n\t\thealth_timeout 2s\n\t\thealth_status 200\n\t}\n\n\thandle_errors {\n\t\t# appコンテナ停止時などのバックエンドエラー\n\t\t@backend_down `{err.status_code} in [500, 501, 502, 503, 504, 522]`\n\t\thandle @backend_down {\n\t\t\t# /api系は外形監視のためメンテナンスを返さず本来のエラー(5xx)を通す\n\t\t\t@api path /api/*\n\t\t\thandle @api {\n\t\t\t\trespond {err.status_code}\n\t\t\t}\n\t\t\t# それ以外はメンテナンスページを200で返す\n\t\t\thandle {\n\t\t\t\treverse_proxy maintenance:80 {\n\t\t\t\t\thandle_response {\n\t\t\t\t\t\tcopy_response_headers\n\t\t\t\t\t\tcopy_response 200\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">R2への転送で一つ問題があり、Misskeyのローカルファイルはファイル名に拡張子がなく(accessKeyがそのままファイル名)、rcloneは拡張子からしかMIMEを判定しないため、全部\u003Ccode>application/octet-stream\u003C/code>でアップロードされていました。画像はブラウザのスニッフィングで表示されてしまうため気づきにくいのですが、動画がインライン再生できない等の問題が発生します。 修正として、S3のCopyObject(metadata REPLACE)で、Content-Typeだけ貼り替えました。\u003Ccode>file --mime-type\u003C/code>の実判定値を9,564件流し込んで完了しました。ちなみに、並列に\u003Ccode>aws-cli\u003C/code>を立ち上げるやり方はメモリ2GiBの子には荷が重すぎたようでOOMしてしまいました。boto3+スレッドプールの単一プロセスでやるのが速くて安全そうです。\u003C/p>\u003Cp style=\"text-align: start\">余談ですが、アップロード中に止めようとして打った\u003Ccode>pkill -f &quot;rclone copy&quot;\u003C/code>は、自分がsshで送ったコマンド文字列そのものにもマッチするようでセッションごと死んでしまい、exit 255が返ってきて数秒固まりました。\u003Ccode>pkill -x rclone\u003C/code>を使いましょう。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"hc07c39fafc\">全員のアイコンがidenticonになる\u003C/h1>\u003Cp style=\"text-align: start\">v12からv13へのアップグレードで、既存ユーザの\u003Ccode>avatarUrl\u003C/code>/\u003Ccode>bannerUrl\u003C/code>がnullになりました。Misskeyの挙動として、identiconにフォールバックされるので、移行直後は全ユーザーのアイコンがidenticon表示になってしまいました。失敗したのかとちょっと焦りましたね。\u003C/p>\u003Cp style=\"text-align: start\">解決策として、\u003Ccode>drive_file\u003C/code>自体は無事(なはず)なので、そこから再構築しました。\u003C/p>\u003Cpre>\u003Ccode class=\"language-sql\">UPDATE &quot;user&quot; SET &quot;avatarUrl&quot; = COALESCE(NULLIF(f.&quot;webpublicUrl&quot;, &apos;&apos;), f.&quot;url&quot;) FROM drive_file f WHERE ...;\u003C/code>\u003C/pre>\u003Cp style=\"text-align: start\">これで9,507人のアバターと7,238件のバナーが正常に表示されます。\u003Cbr>注意点として、ユーザ情報はin-memoryでキャッシュされているので、DBを直しただけでは反映されませんので、Misskeyのアプリケーション本体を再起動するところまでやりましょう。\u003C/p>\u003Cp style=\"text-align: start\">ちなみに、絵文字も似たような問題を踏んでいて、\u003Ccode>emoji.publicUrl\u003C/code>が旧URLのまま残り、ローカルの絵文字だけダミー画像にフォールバックしていました。URLを\u003Ccode>drive_file\u003C/code>と同じ直R2形式に置換し、Redisの\u003Ccode>&lt;domain&gt;:singlecache:localEmojis\u003C/code>を消して再起動することで事なきを得ました。 ここで安直に\u003Ccode>FLUSHALL\u003C/code>してしまうとジョブキューごと消えてしまうのでやってはいけません。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h61e6f6ae5a\">管理者がいない\u003C/h1>\u003Cp style=\"text-align: start\">今回利用しているフォークのtempuraでは、管理者/モデレータの判定を\u003Ccode>permissionGroup\u003C/code>という独自カラム(Admin/MainModerator/Normal/Community)で行っており、バニラにある\u003Ccode>isAdministrator\u003C/code>のbool値を見ていません。管理者ロールをDBで作って割り当てても、\u003Ccode>permissionGroup=&apos;Admin&apos;\u003C/code>でなければ権限は付かないことになります。\u003C/p>\u003Cp style=\"text-align: start\">さらに、v12からの移行では\u003Ccode>user.isAdmin\u003C/code>がロールに変換されません。よって、移行後のインスタンスには管理者が存在しないインスタンスが完成してしまいます。\u003C/p>\u003Cp style=\"text-align: start\">対応として、DBで管理者ロールを手組みしました。IDはaid形式(タイムスタンプのbase36を8桁+ランダム2桁)を自前で用意し、\u003Ccode>role_assignment\u003C/code>で割り当てて、ロールキャッシュ解消のためapp再起動。これで事なきを得ました。\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"hcb82afc914\">横展開\u003C/h1>\u003Cp style=\"text-align: start\">同じ手順で2台目も移行しました。1台目のレポジトリをコピーしてfindとsedでドメインとレポジトリ名を置換し、\u003Ccode>compose.yaml\u003C/code>を初期状態(postgres:15+バニラ)に戻してから、同じ手順をもう一度たどるだけで、データ規模が小さかったこともあり、あっさりと終わりました。\u003C/p>\u003Cp style=\"text-align: start\">\u003Ca href=\"https://misskey.blue/notes/01KWHYKPNCBKFFHH66VA7D1Z8T\">https://misskey.blue/notes/01KWHYKPNCBKFFHH66VA7D1Z8T\u003C/a>\u003C/p>\u003Ch1 style=\"text-align: start\" id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp style=\"text-align: start\">移行結果を確認しておきます。1台目でいうとnotes 189,545、users 9,841、drive_file 53,534。移行の前後で1件も欠けていません(usersだけ+1ですが、これはインスタンスactorが追加されたぶんなので正常です)。\u003Cbr>3年半塩漬けだったデータを、そのまま現行環境へ載せ替えられました。\u003C/p>\u003Cp style=\"text-align: start\">同じようなことを試みる誰かの参考になれば幸いです。\u003C/p>\u003Cp style=\"text-align: start\">それでは。\u003C/p>",[23,29,35],{"id":24,"createdAt":25,"updatedAt":26,"publishedAt":25,"revisedAt":26,"slug":27,"name":28},"vmhb23sq4","2025-07-29T12:56:07.884Z","2025-12-03T16:06:19.140Z","misskey","Misskey",{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},"qfey3yw0z1","2025-04-29T08:44:41.687Z","2025-12-03T16:07:14.622Z","technology","テクノロジー",{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},false,{"id":38,"createdAt":39,"updatedAt":40,"publishedAt":41,"revisedAt":40,"title":42,"content":43,"tags":44,"is_no_index":36},"oy69jxht12","2026-06-19T18:38:58.987Z","2026-06-26T14:48:16.179Z","2026-06-19T18:48:10.255Z","Hide My Emailのドメインが変わるので、また悩んでいる","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>以前、\u003Ca href=\"https://mq1.dev/entry/svgkndwg3ng9\">独自ドメインでのメールアドレス運用をやめ、Hide My Emailに移行した話\u003C/a>という記事を書きました。「自前運用もSESも全部やめて全てをHide My Emailに寄せたよ〜」という話です。\u003C/p>\u003Cp>で、そのHide My Emailなんですが、先日、生成されるアドレスのドメインが\u003Ccode>@icloud.com\u003C/code>から\u003Ccode>@private.icloud.com\u003C/code>に変わると発表されました。すでに発行済みのアドレスは引き続き転送されるらしいので、過去の登録が消えてしまうわけではないのですが、これから作るぶんが別ドメインになる時点で、わたしにとっての価値の大半は消し飛びます。\u003C/p>\u003Cp>\u003Ca href=\"https://developer.apple.com/news/?id=sus6t6ab&amp;7194ef805fa2d04b0f7e8c9521f97343\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https://developer.apple.com/news/?id=sus6t6ab&amp;7194ef805fa2d04b0f7e8c9521f97343\u003C/a>\u003C/p>\u003Cp>さて、困りました。\u003C/p>\u003Ch1 id=\"ha05bbba395\">なにが困るのか\u003C/h1>\u003Cp>わたしがHide My Emailを愛用していた理由は、大きく二つあります。\u003C/p>\u003Cp>プライマリのアドレスと紐付けずにサービスごとに使い分けられること、そして\u003Ccode>icloud.com\u003C/code>のドメインパワーに肖れることです。\u003C/p>\u003Cp>特に後者が大きくて。\u003Cbr>そもそもHide My Emailを嬉しく思っていたのは、生成されるアドレスが普通のiCloudユーザと見分けがつかなかったからでした。受け手からすればただのiCloudユーザーにしか見えないので、後述する特定の大手ドメインしか受け付けないみたいな邪悪な実装も平然と通過できていました。それが\u003Ccode>@private.icloud.com\u003C/code>になると、受け手がHide My Emailを判別できるようになってしまいます。\u003C/p>\u003Cp>要するに、機能が成立していた前提をApple自身が手放しにきているわけです。プライバシ機能を名乗っておいてこれは、なかなかのものだなと思います。\u003C/p>\u003Cp>で、世の中には、GmailとiCloud(国内だとヘンテコ仕様なキャリアメールなんかも)以外のドメインを弾くようになっているサービスがそこそこあります。\u003Cs>Pi○tLinkなんかがそうですね。\u003C/s>こういう邪悪な実装のところでは、\u003Ccode>icloud.com\u003C/code>が使えること自体が最大にして唯一の利点でした。正直、わたしはこの一点のためだけにiCloud+へ課金していたと言っても過言ではありません。\u003C/p>\u003Cp>プライバシがどうとかいう高尚な理由ではなく、純粋に弾かれないための月額だったので、ここがなくなってしまうのはとても苦しい。\u003C/p>\u003Ch1 id=\"hf58740672c\">そもそも独自ドメインのメールって旨味あるの\u003C/h1>\u003Cp>「じゃあ独自ドメインに戻せば」という話になりそうですが、わたしはこのご時世に個人で独自ドメインのメールを持つ旨味、あんまりないと思っています。理由は二つ。\u003C/p>\u003Cp>一つは、メールサーバを自前で持つハードルが高いこと。\u003Cbr>ここで言うハードルは、構築の手間のことではありません。安定して長期運用できること、そしてレピュテーションを健全に保ち続けられること。実際のところ、メールサーバを立てるだけなら誰でもできるのですが、問題はそこから先で、送信ドメイン認証を整えて、IPを腐らせないように気を遣って、ある日突然どこかにブロックされても対処し続ける維持のほうが本体なんですよね。一度評判を落とすと戻すのも大変だし、これを個人で延々とやる価値があるかというと、正直微妙です。\u003C/p>\u003Cp>そもそもASN単位でブロックリスト入りすることも往々にしてあるので、根本的解決を図るにはASNを取得しIP割当を受けるしかない気がします。あまりにも不毛です。\u003C/p>\u003Cp>もう一つは、結局外部のプロバイダに乗せるなら独自ドメインの旨味は薄いこと。\u003Cbr>SESなりWorkspaceなりに任せるなら、配送やレピュテーションの面倒は向こうが見てくれる代わりに、自分が握ってるのはドメイン名といざとなれば乗り換えられる安心感くらいになります。それはそれで価値がないこともないのですが、Hide My Emailの大手のドメインに乗れることとはそもそも別の話です。\u003C/p>\u003Cp>もちろん利点もあって、スパムが来たときにどのサービスがお漏らしたか分かるとか、普段使いのアドレスを隠せるとか、管理が幾分か楽になるとか。でも正直、どれも過去のHide My Emailを超えることはないように思います。\u003C/p>\u003Ch1 id=\"hba13ad79dc\">Gmailのサブアドレスも微妙\u003C/h1>\u003Cp>Gmailのエイリアス(※1)を使う手もあります。\u003C/p>\u003Cp>ただこれ、同一人物への到達性を保証しなくていいスパムであれば、local partのuser部だけ抽出して(厳密ではないにせよ)送れてしまうんですよね。\u003Cs>少なくとも私ならそういう実装をしますし、多くの人がそう考えると思います。\u003C/s>Separator character sequence以降を捨てれば届いてしまうので、使い捨てアドレスとしては心許ない。かなり微妙。\u003C/p>\u003Ch1 id=\"h287541f080\">で、結局どうするか決まってない\u003C/h1>\u003Cp>整理すると、わたしが欲しいのは三つです。プライマリのアドレスを隠せること、サービスごとに分けられること、そして邪悪な実装を通れること。最初の二つは代替がいくらでもあるのですが、問題は三つめで、これを満たせる選択肢が驚くほど見つかりません。\u003C/p>\u003Cp>一応、候補は一通り眺めてみました。\u003C/p>\u003Cp>\u003Ca href=\"https://addy.io/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">addy.io\u003C/a>や\u003Ca href=\"https://simplelogin.io/ja/\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">SimpleLogin\u003C/a>のようなエイリアスサービスは、マスキングも使い分けも完璧。しかし、相手に渡すアドレスは結局そのサービス自身のドメインになるので、\u003Ccode>@addy.io\u003C/code>とか\u003Ccode>@simplelogin.io\u003C/code>をGmail/iCloud/ヘンテコキャリアメールしか通さない許可リストが受け入れてくれるわけがありません。ついでにSimpleLoginはProton傘下で、わたしはProtonが好きではないので却下。\u003C/p>\u003Cp>独自ドメインを自前運用したりWorkspaceに載せたりする手も、同じ壁に当たります。受け手が見てるのはドメイン名の文字列であって、誰がホストしてるかではないため、どれだけ真っ当に運用されてようと、\u003Ccode>icloud.com\u003C/code>でも\u003Ccode>gmail.com\u003C/code>でもない以上、リテラル照合の前では無力です。Googleのインフラに乗せようが、自分のドメインである事実は変わらないので。\u003C/p>\u003Cp>iCloudの素のエイリアス(Hide My Emailではなく、\u003Ccode>@icloud.com\u003C/code>を最大3つ作れるやつ)は、ドメインが本物の\u003Ccode>icloud.com\u003C/code>のままなので許可リストは通ります。これはうれしい。しかし、3つしか作れないうえ、3つ埋まった状態で1つ消すと次を作るまで7日待たされるようで、使い捨てとして回すには微妙です。\u003C/p>\u003Cp>規約上どうかは知りませんが、転送専用のGmailアカウントを量産する手も思いつきました。\u003Cs>(思いついただけでやってないので叩かないでください)\u003C/s>これなら渡すのは正真正銘の\u003Ccode>@gmail.com\u003C/code>で許可リストも確実に通るし、数も稼げそうです。しかし、アカウントごとに電話番号認証だの複数アカウントの取り回しだのが付いてくる上、Googleの機嫌次第でまとめて凍結される可能性も拭えず、得られる体験のわりに管理コストとリスクが釣り合っていません。無念。\u003C/p>\u003Cp>という具合に、どれを取っても過去のHide My Emailには届かないんです。結局わたしが失おうとしてるのは、「大手のドメインに、ほぼ無限に、片手間で乗れる」という、よく考えるとかなり贅沢な状態だったんだなと。\u003Cbr>しかもApple側が仕様としてやめると言ってる以上、こっちの工夫でどうこうできる話でもなく。すごく普通に困ってます。\u003C/p>\u003Cp>そもそもみなさん、メールアドレスの運用ってどうしてるんでしょう？\u003Cbr>いい感じの方法があったら本当に教えてほしいです。\u003C/p>\u003Cp>\u003C/p>\u003Cp>\u003C/p>\u003Chr>\u003Cp>※1 RFC 5233のsubaddressingは、Separator character sequence + Detailであって、これがエイリアスでないことは理解しています。が、(腹立たしいことに)慣習上そう呼ばれることが多い(らしい)のでここでもそう呼んでます。\u003C/p>\u003Cp>蛇足ですが、&quot;Separator character sequence&quot;という言い方をすると、何らかの形で明確に分離された構造になっているように聞こえますが、実際にRFCが言ってるのは「UserにDetailを加えたアドレスをUserにルーティングできる」くらいのことでしかなくて、RFC 5321/5322が「local partの解釈は受け手のソフトウェア次第」ってスタンスなのに対して、RFC 5233はlocal partの形式の例として「local part=userってわけじゃなくてぇ」みたいな話をしてるに過ぎません。広げてるように見えて制限してる規格かと思いきや、その実なにも制限してない用語と用例が出されてるだけのものなので誤解しないようにしてくださいね。\u003C/p>\u003Cp>そもそもエイリアスは原初から全く別の機能の名称として存在してるので、この呼び方にはずっと不満があります。\u003C/p>",[45,46,52,58],{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},{"id":47,"createdAt":48,"updatedAt":49,"publishedAt":48,"revisedAt":49,"slug":50,"name":51},"fwj_nwhj1-s","2025-04-30T04:55:28.953Z","2025-12-03T16:07:03.591Z","server","サーバー",{"id":53,"createdAt":54,"updatedAt":55,"publishedAt":54,"revisedAt":55,"slug":56,"name":57},"wia4slp55q","2025-04-28T07:14:14.541Z","2025-12-03T16:08:13.798Z","thoughts","独り言",{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":60,"createdAt":61,"updatedAt":62,"publishedAt":63,"revisedAt":62,"title":64,"content":65,"tags":66,"is_no_index":36},"l_gwwt21az06","2026-04-18T08:31:28.769Z","2026-04-18T18:16:15.075Z","2026-04-18T08:36:42.914Z","20歳になりました","\u003Cp>どうも、わたしです。\u003C/p>\u003Cp style=\"text-align: start\">早いもので、とうとう先日20歳になってしまいました。世間一般で言えば立派な大人の仲間入りということになるのでしょうが、自認はまだまだ5歳児です。時間の流れだけは残酷なほど速く過ぎ去っていくので、ただただ戸惑うばかりです。\u003C/p>\u003Cp style=\"text-align: start\">思い返せば高校時代、卒業した後の自分の姿なんて、微塵も想像していませんでした。当時の私にとって、あの閉鎖的で代わり映えのしない日々の生活が世界の全てでした。その先の未来なんてものは想像すらできず、ぱっと死んでしまうような、そんな刹那的な感覚すら抱いていたのかもしれません。\u003C/p>\u003Cp style=\"text-align: start\">しかし現実は無慈悲に続くもので、時を経て、高校を卒業してからあっという間に2年の月日が経過してしまいました。\u003C/p>\u003Cp style=\"text-align: start\">相変わらず1人怠惰な日々を送っています。20歳になったからといって、急に視界が開けたり、精神的に成熟したり、劇的に何かが変わるわけでもありません。明日からもきっと似たり寄ったりの、良くも悪くもつまんない日々を淡々と消化していくんだと思います。\u003C/p>\u003Cp style=\"text-align: start\">数年前の民法改正によって、成人年齢自体は18歳に引き下げられました。しかし、お酒やタバコ、各種賭博等の規制は依然として20歳がボーダーとして残されています。\u003C/p>\u003Cp style=\"text-align: start\">この年齢制限がようやく解除されたことで、社会的には、真の意味で大人(笑)になれたのかもしれません。とはいえ、中身の精神性は先述した通り未熟なままなので、あまり大きい声では言えないのですが。\u003C/p>\u003Cp style=\"text-align: start\">ただ年齢が一つ増えただけで、許可される行為の幅が広がるというのは、なんだか不思議なシステムだと改めて感じます。\u003C/p>\u003Cp style=\"text-align: start\">それはそれとして。せっかくなので初めての飲酒というやつを経験してみました。\u003C/p>\u003Cp style=\"text-align: start\">選んだのはほろよいの桃っぽい甘いやつ。\u003C/p>\u003Cp style=\"text-align: start\">「初飲酒とはいえ、アルコール3%だしいけるっしょ」と、完全に高を括っていたのですが、結果は無惨な敗北でした。\u003C/p>\u003Cp style=\"text-align: start\">全然顔が赤くなってしまい、東アジア人を感じました。アセトアルデヒドを全く分解できていなさそうな、どうしようもない間抜け顔です。\u003C/p>\u003Cp style=\"text-align: start\">自分の家系はそれなりにアルコールに強い方だと思い込んでいたので、この圧倒的な弱さにはちょっとびっくりしました。\u003C/p>\u003Cp style=\"text-align: start\">そういえば幼少期、両親が離婚する以前は「お前は近所の海で拾ってきたんだ（意訳）」的なことをよく言われていた記憶があります。アルコール適性の無さを鑑みるに、本当に近所の海から拾われてきた捨て子だったのかもしれません笑\u003C/p>\u003Cp style=\"text-align: start\">これは冗談です。あしからず。\u003C/p>\u003Cp style=\"text-align: start\">とまあ、そんなどうしようもない20歳の幕開けを迎えたわけですが、私の日常自体はこれまでと何一つ変わっていません。\u003C/p>\u003Cp style=\"text-align: start\">そういえば、すっかり書き忘れていましたが、またMisskeyインスタンスを建てました。\u003C/p>\u003Cp style=\"text-align: start\">\u003Ca href=\"https://misskey.blue/\">https://misskey.blue/\u003C/a>\u003C/p>\u003Cp style=\"text-align: start\">過去に文句を散々書き連ねておきながら、本当に性懲りもない人間だなと自分でも呆れています。喉元過ぎれば熱さを忘れるとはよく言ったもので、ふと手持ち無沙汰になると、あの空気が恋しくなってしまうようです。\u003C/p>\u003Cp style=\"text-align: start\">今回はVultrを借りて、2 vCPUs / 4GiB のインスタンス上にDockerで構築しています。ただ、分かってはいたことですが、Misskeyを動かすにはこのスペックだとリソース的にかなりカツカツで厳しいのが現状です。要求されるリソースがそれなりに重いため、常にswapと睨めっこしながらの綱渡り状態を強いられています。\u003C/p>\u003Cp style=\"text-align: start\">快適さを求めるのであればさっさとスケールすべきなのですが、一つ上のプランに引き上げるとなると、支払い額ほぼ2倍に跳ね上がるようで、十数人程度しかいないインスタンスにその出費を受け入れるかと言われると、どうしても「うーん…」と躊躇してしまうのが正直なところです。\u003C/p>\u003Cp style=\"text-align: start\">現状は、仲のいい子を数人呼んでひっそりと運用しているだけです。ただ、やはり少人数だとどうしてもLTLの動きが鈍く、わちゃわちゃとした楽しさに欠けるというか、純粋にTLが寂しいんですよね。\u003C/p>\u003Cp style=\"text-align: start\">もっと人を呼んでLTLを賑やかにしたいという思いは山々ですが、公開鯖にしてしまうと、かつてと同じ轍をまた踏む未来が容易に想像できてしまいます。\u003C/p>\u003Cp style=\"text-align: start\">人、ほしい。\u003C/p>\u003Cp style=\"text-align: start\">それでは\u003C/p>",[67,68],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":53,"createdAt":54,"updatedAt":55,"publishedAt":54,"revisedAt":55,"slug":56,"name":57},{"id":70,"createdAt":71,"updatedAt":72,"publishedAt":72,"revisedAt":72,"title":73,"content":74,"tags":75,"is_no_index":36},"5nf10o2ud0j","2026-04-02T14:00:30.562Z","2026-04-02T14:01:54.127Z","ねこちゃんをお迎えしました2","\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>以前から検討していたのですが、新しく2匹目のねこをお迎えすることにしました。\u003Cbr>今回お迎えしたのは、ノルウェージャンフォレストキャットの女の子(7ヶ月齢)です。名前は「ラテ」にしました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/3204c913ca2a4c6b81fcf3660d7af26b/beauty_1774772499640.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>一般的にはもっと幼い時期にお迎えするケースが多いかと思いますが、あえてこの月齢の子を選びました。\u003C/p>\u003Cp>7ヶ月ともなると、性格もかなり安定していますし、体調面での不安も少ないです。ノルウェージャンらしい立派な飾り毛や毛吹きも既に出始めており、成猫になった時の完成形がイメージしやすかったのも決め手の一つでした。\u003C/p>\u003Cp>先住猫のモカちゃんは、お迎え当日に添い寝をしてくれるほどの驚異的な適応能力を持っていました。対して今回のラテちゃんは、初日こそ少し慎重でしたが、数時間もすれば部屋の探索を始めるなど、なかなかの図太さを見せてくれています。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/bb54aa22e13446e79786cc85f973296d/beauty_1774942744631.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>先住猫のモカちゃんは、ご縁があって譲っていただいた子だったので、実質的な生体価格というものは発生していませんでした。\u003Cbr>しかし、今回は順当な？ルートでお迎えしたため、総額で25万円近くかかりました。\u003C/p>\u003Cp>猫を購入する経験がなかった身からすると、この金額には正直かなりの衝撃を受けています。支払う瞬間に一瞬手が止まるくらいの重みはありましたが、まあ、お迎えしてしまったものは仕方がありません。\u003Cbr>これからこの2匹が仲良く並んで寝てくれる日を目標に、しっかり面倒を見ていこうと思います。\u003C/p>\u003Cfigure style=\"text-align: left;\">\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/106405f266634defae61fc31b18da359/beauty_1774881852261.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/a5212af8ab2548c6b4fd0abe6d7476d0/beauty_1774869951812.jpeg\" alt=\"\" width=\"3840\" height=\"2160\">\u003C/figure>",[76,77],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":78,"createdAt":79,"updatedAt":80,"publishedAt":79,"revisedAt":80,"slug":81,"name":82},"zvbbh2k4o","2025-07-09T17:50:30.110Z","2025-12-03T16:06:32.163Z","cat-life","ネコのいる暮らし",{"id":84,"createdAt":85,"updatedAt":86,"publishedAt":86,"revisedAt":86,"title":87,"content":88,"tags":89,"is_no_index":36},"881vyfdq_5","2026-01-12T19:08:19.276Z","2026-01-12T19:14:08.297Z","さようならVercel, こんにちはGCP","\u003Cp>こんばんは。あるいはこんにちは。\u003C/p>\u003Cp>実はお気づきの方もいらっしゃるかもしれませんが、このサイト、数ヶ月前にインフラのお引越しをしています。暫くお世話になっていたVercel基盤を離れ、現在はGCPの上で稼働しています。移行作業からしばらく経ち、運用も安定していて特に問題なさそうなので、ここらで重い腰を上げて移行の経緯でも書き残しておこうかなと思います。\u003C/p>\u003Cp>今回、以降に踏み切った理由はいろいろとあるのですが、きっかけとして大きかったのは、単純にVercelの無料枠を使い果たしてしまったことです。個人の趣味サイトとはいえ、トラヒックが増えればリソースも食いますし、記事数が増えれば(移行当時は部分的にSSG構成だったので)ビルド時間も伸びます。もちろん、お金で殴ってプランを上げてしまえばそのまま使い続けることは造作もないことなのですが、そこでふと損得勘定が働いてしまいました。毎月10USDを固定で払うくらいなら、必要な分だけ課金されるCloud Runで動かした方が、結果的にはお財布に優しいしお得なんですよね。\u003C/p>\u003Cp>そして2つ目。実はこっちの方が心情的な割合としてはかなり大きいのですが、VercelのCEOであるGuillermo Rauch氏の倫理観に対して、どうしても拭えない不信感を抱いてしまったという点です。ご存じの方も多いかと思いますが、彼がイスラエルのネタニヤフ首相と会談し、ML技術について議論を交わし、その後に満面の笑みで撮影したセルフィーをTwitterに投稿したあの一件です。\u003C/p>\u003Cp>相手は国際刑事裁判所から指名手配を受け、ガザでのジェノサイド容疑もかけられている人物です。政治的なスタンスは人それぞれあるにせよ、公人として、tech企業のトップとして、そのセルフィーを世界に発信することの意味をどう捉えているのか。本当にこの人の倫理観はどうなっているんだろうと、背筋が寒くなるような思いでした。\u003C/p>\u003Cp>「たかが個人の趣味サイトなんだから、プラットフォームのCEOの思想なんて関係ないじゃん」と言われればそれまでですし、別にわたしのサイトは法人の看板を背負っているわけでも、社会的な信用を切り売りしている商売でもありません。実害は全然ないんです。でも、それはそれとして、一度すこしでも嫌悪感を感じてしまうと、それ以外の部分まで全部が色褪せて見えてしまうのものです。所謂、坊主憎けりゃ袈裟まで憎いというやつです。\u003C/p>\u003Cp>そうなると不思議なもので、元々は妥協していた小さな不満が、急に許せなくなってきます。例えば、NuxtImgを使った画像最適化の取り回しについて、Vercelプロバイダを利用するときだけ妙に設定が面倒だったり、挙動に癖があったりして、結局対応するのが億劫でipxを利用して回避していた事なんかが思い出されます。\u003C/p>\u003Cp>あとはあれですね、令和の現代においても未だにIPv6をネイティブでサポートしていない点とか。先進的なフロントエンド体験を謳っているプラットフォームなのに、足回りのネットワークに関しては意外と適当なんだなと、以前から感じていた違和感が嫌悪感に変わりました。そういう小さな「うーん」という澱みのようなものが積み重なって、最終的に「もう全部嫌だ、引っ越そう」という決断に至ったわけです。\u003C/p>\u003Cp>移行先にGCPを選んだ理由は至ってシンプルで、安くて使いやすくて、なんとなくいい感じだからです。ありがたいことに無料枠もそれなりに充実していますし、貧乏開発者には優しい環境が整っています。\u003C/p>\u003Cp>ちなみに、このサイトを作り始めたちょうど1年くらい前は、Cloudflare Workersを利用していました。なので今回もWorkersに出戻りすることを真っ先に検討したのですが、いざ検証してみると壁にぶつかりました。現在の構成がNode.js依存の実装を含むライブラリとズブズブの関係になってしまっており、Workersのランタイム環境では動かすのが厳しかったのです。加えて、仮にPaidプランにしたとしても、ランタイムサイズの制限を大幅に超過してしまうことは明白でした。\u003C/p>\u003Cp>あれこれ悩んだ結果、CockroachDBがちょうどGCP上にあったこともあり、それならアプリケーションも同じGCPに置いてしまった方が合理的だという結論に達しました。結果的に、GCPへの集約は正解だったと思います。\u003C/p>\u003Cp>インフラの構築に関しては、例によって私はGUIの管理画面をポチポチして手動で設定するのが大嫌いなので、今回も全てTerraformを使ってIaC化しています。人の温もりを感じるインフラなんて、いつ壊れるかわからない時限爆弾みたいなものですからね。\u003C/p>\u003Cp>あ、そうそう、ついでにGoogle Fontsもやめました。Lighthouseのパフォーマンススコアの足を引っ張っていて邪魔だったので思い切って削除したのですが、代わりのシステムフォントはどうにも気持ち悪くて、納得できませんでした。結局、Adobe Fontsを導入してFutura-PTを利用することにしました。そのせいで削除前よりもLighthouseのスコアは低下してしまったのですが、見た目が圧倒的にかわいくなったのでよしとしています。\u003C/p>\u003Cp>最適化については、またいつか気が向いた時にでも頑張ろうと思います。\u003C/p>\u003Cp>それでは。\u003C/p>",[90,91,92,98,99],{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},{"id":47,"createdAt":48,"updatedAt":49,"publishedAt":48,"revisedAt":49,"slug":50,"name":51},{"id":93,"createdAt":94,"updatedAt":95,"publishedAt":94,"revisedAt":95,"slug":96,"name":97},"8q8qyy8sz3","2025-04-29T08:44:23.406Z","2025-12-03T16:07:24.495Z","programming","プログラミング",{"id":53,"createdAt":54,"updatedAt":55,"publishedAt":54,"revisedAt":55,"slug":56,"name":57},{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":101,"createdAt":102,"updatedAt":103,"publishedAt":104,"revisedAt":103,"title":105,"content":106,"tags":107,"is_no_index":36},"f6z480u0b","2025-12-14T15:50:26.180Z","2025-12-16T10:08:14.969Z","2025-12-16T10:05:42.467Z","THE SANZAI 2025","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>2025年も残すところ僅かとなりました。皆様いかがお過ごしでしょうか。\u003Cbr>年末ということで、みんなやってる散財報告を行いたいと思います。\u003C/p>\u003Cp>恐る恐るAmazonの注文履歴やクレジットカードの明細を見返してみたのですが、スクロールする指が震えるほどの件数でした。高校を卒業してから、今までの反動なのか怒濤の散財を繰り返していたので、「そらそうでしょうね」という感じ。というか、現時点ですでに口座残高はカツカツです。\u003Cbr>ここでは、特にインパクトの大きかった大きめの散財を抜粋して記録しておきます。\u003C/p>\u003Ch1 id=\"h0b2bb79295\">振り返り\u003C/h1>\u003Ch2 id=\"h2c5a7364b2\">自作PC\u003C/h2>\u003Cp>2025年最初の大きな散財はPCでした。感覚的には去年組んだ気でいたのですが、履歴を見ると今年の話だったようで時の流れの早さに驚愕しています。\u003C/p>\u003Cp>元々DeskMeetを使っていたのですが、若干のスペック不足を感じ始めたため、思い切って組み直しました。DeskMeetは小さい筐体に色々詰め込むことができて好みだったのですが、やはり拡張性に難があり今回のPCでは見送る事に。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/3548cc50469747fa9c123228295a6ddc/beauty_1744095297549.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/e5d6573665b74e16a5c0bfed3a9acebf/beauty_1744112518298.jpeg\" alt=\"\" width=\"522\" height=\"928\">\u003C/figure>\u003Cp>Ryzen5 8600G /  RTX 5070 / 64GiBの構成で、現行のミドルクラスとしては申し分ない…と言いたいところですが、既にRAM不足を感じており、近いうちに増設が必要そうです。\u003C/p>\u003Cp>一点、誤算だったのがマザーボードのオンボードNICです。有線接続時のレイテンシが異常なほど高い値を示し、使い物にならないというトラブルに見舞われました。その後、別途NICを買い足して事なきを得たのですが、その購入履歴は見つけられませんでした。(多分実店舗で買ったのかな？)\u003C/p>\u003Cp>総額 272,441円(+NIC代)\u003C/p>\u003Ch2 id=\"h655a931e31\">UniFi Dream Machine Pro\u003C/h2>\u003Cp>自宅のメインルータとして長らくNECのIX3110を運用してきましたが、諸々の理由でリプレイスを敢行。\u003Cbr>同ベンダのIX-R2530やYAMAHA RTX3510といったルータも検討しましたが、最終的には安さと「UniFiを触ってみたい」という好奇心が勝ち、UDM Proを導入しました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/7e61d17cb9a34cbd94565fea1e3b6236/beauty_1746763922238.jpeg\" alt=\"\" width=\"3840\" height=\"2160\">\u003C/figure>\u003Cp>これまで使っていた中華製NVRもこれ一台に統合できたので、少しスッキリしました。\u003C/p>\u003Cp>総額 71,800円\u003C/p>\u003Ch2 id=\"h9beca2c1cc\">乾燥機\u003C/h2>\u003Cp>毎回洗濯物を干すのが億劫で仕方がなかったので衝動買い。\u003Cbr>意識高い系みたいなことを言いますが、QOLの向上幅で言えば、今年一番かもしれません。もっと早く買えばよかった。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/dd5bdc701fd54bca95d4e3cf3d30576d/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202025-12-15%201.04.31.png\" alt=\"\" width=\"948\" height=\"202\">\u003C/figure>\u003Cp>総額 75,222円\u003C/p>\u003Ch2 id=\"h88601d35eb\">iRobot Roomba Combo Essential 2\u003C/h2>\u003Cp>地元の某ジャ○ネットたかたのセールで安くなっていたので追加購入。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/60bbee8d7b744dd29adecc41ff2aab97/beauty_1746576506150.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>既にRoomba i7+を持っているので、どうしても比較の目が厳しくなってしまうのですが、正直これは微妙でした。\u003Cbr>全体的な評価として、i7+に遠く及びません。水拭きができる点に若干の優位性はありますが、どうせ買うなら上位モデル一択だなと痛感しました。\u003C/p>\u003Cp>総額 41,730円\u003C/p>\u003Ch2 id=\"hf536e6622d\">Apple Watch Series 10\u003C/h2>\u003Cp>以前から欲しいと思いつつスルーしていましたが、深夜テンションに押されて購入。後悔はしていません。\u003Cbr>GPS+Cellularモデルと迷いましたが、重度のインターネット依存症なので、スマホを置いて外出することはまずあり得ないため、GPSモデルで妥協しました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/830cf17aef224333a0f99e461a372052/image.png\" alt=\"\" width=\"1002\" height=\"315\">\u003C/figure>\u003Cp>他Apple製品のロック解除を連携できたり、決済できたりと地味に便利です。\u003C/p>\u003Cp>総額 59,800円\u003C/p>\u003Ch2 id=\"h6d0a4f92a1\">自動車学校\u003C/h2>\u003Cp>都会に住んでいれば車なんて不要なのかもしれませんが、生憎と田舎住みなので渋々取得。\u003Cbr>高校時代の友人からの紹介で多少の割引はあったものの、基本料金で約32万円。私の運転センスが壊滅的だったようで、補習による追加課金が数万円発生しました…。苦しい。\u003C/p>\u003Cp>正直、車自体にはそこまで興味がないのですが、年々バスも電車も本数が減っていて、まともに生活ができなくなりそうです。都会住みが本当に心底羨ましい。\u003C/p>\u003Ch2 id=\"hc79df5a48b\">椅子・オーディオ系\u003C/h2>\u003Cp>使っていた座椅子が壊れたので、Amazonの検索上位に出てきたものを思考停止で購入。\u003Cbr>その際、以前から気になっていた AG03mk2とAT2020が安くなっていたので、勢いでカートに突っ込んでしまいました。\u003C/p>\u003Cp>典型的なあわせ買い散財です。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/c6d6fc2cd2284761b69923c907c148a3/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202025-12-15%200.39.16.png.png\" alt=\"\" width=\"951\" height=\"691\">\u003C/figure>\u003Cp>総額 92,880円\u003C/p>\u003Ch2 id=\"hec04ad5490\">Petsnowy 自動トイレ / 自動給餌器 / 給水器\u003C/h2>\u003Cp>ちょうどこの頃に、猫のモカちゃんをお迎えしました。\u003Cbr>毎日トイレ掃除するのも億劫ですし、どうせなら快適な環境をつくってあげようと、一式購入しました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/2d9d628cfb414cc2879465a7ed139105/beauty_1754384048831.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/1998dc79aad846f28666536402b28790/beauty_1755271420215.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>ハードウェアの作りは非常に良く、トイレ掃除の手間から解放されたのは革命的です。ただ、スマホアプリ側のUI/UXや挙動がイマイチなのが玉に瑕。モノが良いだけにおしい。\u003C/p>\u003Cp>総額 76,030円\u003C/p>\u003Ch2 id=\"h36d58ae87a\">Macbook Pro M4 Max\u003C/h2>\u003Cp>Windows環境での開発に対するストレスが限界突破し、衝動買いしました。Linux環境への完全移行も検討しましたが、AdobeCCスイートが使えない点がどうしてもネックとなり、macOSへ回帰することに。\u003C/p>\u003Cp>学割が使えたので、ストレージ以外をすべて最大構成にカスタマイズしています。5年は使い倒すつもりです。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/1256a1502de441d09ef9e0b501c5b542/beauty_1755753949610.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/bacd55c11372487393e5f6a7f128af44/image.png\" alt=\"\" width=\"647\" height=\"490\">\u003C/figure>\u003Cp>賛否両論あったNano-textureディスプレイですが、個人的には大正解でした。映り込みが激減し、長時間触っていても目が疲れにくいです。\u003Cbr>ちょっとした軽自動車が買えるくらいの金額で若干の苦しさはありますが、後悔はありません。使い倒します。\u003C/p>\u003Cp>総額 799,900円\u003C/p>\u003Ch2 id=\"h75fbb98cf0\">PETIT ドライヤーハウス\u003C/h2>\u003Cp>うちの子はスコ長毛種のため毎月のシャンプーが欠かせないのですが、ハンドドライヤーの音と風をあまりに嫌がる姿が不憫で購入を決意。箱に入ってもらうだけで乾かせるので、猫・人間双方のストレスが激減しました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/9ba85afa945a4744af9a81ddecdf06fb/beauty_1762068680230.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/828a98ce67c74ff886d7c2d4b53e6c89/beauty_1762157641125.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>若干翻訳が微妙なところもあるものの、製品自体のクオリティも高く、ソフトもかなりよく作り込まれている印象です。\u003Cbr>給餌器/給水器を買い足す際はPetKitのものに統一しようかなと考えています。\u003C/p>\u003Cp>総額 55,930円\u003C/p>\u003Ch2 id=\"h59d2ba6203\">モニタ\u003C/h2>\u003Cp>かれこれ7年近く愛用していたBenQの液晶がついに映らなくなってしまいました。\u003C/p>\u003Cp>症状的に電源回路の故障っぽいので修理もできそうでしたが、ベゼルの太さを邪魔に感じていたこともあり、これを機にリプレイスを決意。ついでに枚数も増やしました。\u003Cbr>とはいえ、金欠なので安くてそれなりに使えるモデルを購入。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/9c082d1fa338435ca81c881ece2eabc7/image.png\" alt=\"\" width=\"662\" height=\"230\">\u003C/figure>\u003Cp>色味に関しては調整しても若干の違和感が残りますが、コーディングや通常のブラウジング用途であれば許容範囲内です。可もなく不可もなくって感じで、値段相応なんでしょうね。\u003C/p>\u003Cp>総額 42,492円\u003C/p>\u003Ch2 id=\"h517ebf34ca\">iVANKY FusionDock Max 1\u003C/h2>\u003Cp>M4 Max MacBook Proの導入に伴い、デスクの配線を一本化するために導入しました。\u003Cbr>私の環境では4枚の外部モニタを制御する必要があるのですが、DisplayLinkやDaisy chain接続はHDCPの問題や安定性の観点から避けたかったため、実質的に選択肢はこれ一択でした。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/e162019878f14d9cb593973e8a753b46/beauty_1761461912103.jpeg\" alt=\"\" width=\"1500\" height=\"843\">\u003C/figure>\u003Cp>M4 Maxを積んでいるので、巷でよく言われるような外部出力制限についてそこまでシビア気にする必要はないのですが、他に良さげなものがありません。\u003Cbr>稀に前面のPDポート使用中にUSB 3.0接続が不安定になる挙動が見られますが、それ以外は安定しています。ケーブル1本で完結する便利代としては妥当でしょうか。\u003C/p>\u003Cp>総額 59,999円\u003C/p>\u003Ch2 id=\"h1df2cc6df6\">脱衣所・ユニットバス\u003C/h2>\u003Cp>これがおそらく今年の支出で一番大きいです。貯金残高にトドメを刺されました。\u003C/p>\u003Cp>我が家の浴室は昔ながらのタイル張りだったのですが、脱衣所の柱がシロアリに侵食されていることが発覚。駆除が必須となり、「どうせ壁を壊すなら、寒くてボロいお風呂もリフォームしよう」という流れになりました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/a38cf300eb7e4341ab31e1618aa4ee3b/combined_output.jpg\" alt=\"\" width=\"8640\" height=\"3840\">\u003C/figure>\u003Cp>なんと言うことでしょう。元々は換気扇すらなく、壁に穴が開いているだけだった浴室が、綺麗なユニットバスに生まれ変わりました。浴室乾燥機付きです。\u003Cbr>お金の力って怖いですね。\u003C/p>\u003Cp>シロアリ駆除に約28万円、リフォームに約260.5万円。 半額は同居の母が負担してくれましたが、中学時代からコツコツ貯めていた有価証券という有価証券が大方吹き飛びました。\u003Cbr>財布の中が真冬です。誰かお布施してくれないかな。\u003C/p>\u003Ch2 id=\"h602635c732\">Meta Quest 3s 128GBモデル\u003C/h2>\u003Cp>去年の12月頃にVRChatを始め、一緒にやってくれていた子が飽きたりなんだりでしばらくログインしていなかったのですが、ふと欲求が再燃。\u003Cbr>ちょうどブラックフライデーセール中だったこともあり、Quest 3S をお迎えしました。うれしい。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/dc04d39a5f914669ad38ef15365bc4d9/beauty_1764383679952.jpeg\" alt=\"\" width=\"3840\" height=\"2160\">\u003C/figure>\u003Cp>総額 39,112円\u003C/p>\u003Ch2 id=\"h4207c0a576\">Lofree Flow Lite 84\u003C/h2>\u003Cp style=\"text-align: start\">これまで使っていた赤軸中華キーボードのキースイッチにチャタリングが発生したため買い替え。\u003Cbr>以前、Flowを勧められていたのですが、レビューを見た感じ、長時間タイピングするような用途であればFlow Liteの方よさげなのではと考えました。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/211ae01ba99d4523918e7712d79c777d/beauty_1765802315490.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp style=\"text-align: start\">通常版のような金属筐体ではないので高級感は劣りますが、使い勝手はいい感じ。\u003Cbr>地味に刺さったのがキーキャップの印字。私は普段Mac、ゲーム時はWindowsとOSを行き来するため、純正キーキャップにMac/Win両方の印字があるのは地味ながら非常にありがたい仕様です。\u003C/p>\u003Cp style=\"text-align: start\">総額 17,600円\u003C/p>\u003Ch1 id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp>ここまで今年買ったものを書き連ねてきましたが、合計金額を計算するのはやめておきます。現実を見るべきではありません。そう、これは浪費ではなく投資なのです(自己暗示)\u003C/p>\u003Cp>2026年はもう少しお財布に優しい生活を送りたいところですが、すでに物欲が…。\u003Cbr>どなたか、可哀想な大学生にお布施をしてくれる石油王がいらっしゃいましたら、ぜひご連絡をお待ちしております。\u003C/p>\u003Cp>それでは。\u003C/p>",[108,109],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":53,"createdAt":54,"updatedAt":55,"publishedAt":54,"revisedAt":55,"slug":56,"name":57},{"id":111,"createdAt":112,"updatedAt":113,"publishedAt":114,"revisedAt":113,"title":115,"content":116,"tags":117,"is_no_index":36},"552stg8oj_0","2025-12-09T19:45:02.079Z","2025-12-10T10:40:55.112Z","2025-12-10T10:37:15.742Z","ようやくQuest 3sを買ったにょ","\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>ついに買ってしまいました。\u003Cbr>赤字垂れ流しハードウェアの代表格、Meta Quest 3s。買おう買おうと思ってから実際に決済ボタンを押すまでが長かったのですが、Amazonのブラックフライデーセールとかいう甘い誘惑に乗せられ、40,700円でお迎えすることになりました。\u003C/p>\u003Cp>昨年の今頃にVRChatに手を出してから、半年ほど放置していた期間があるものの、界隈の人たちと比較するとVR環境を手に入れるのが遅い方だったかもしれません。\u003C/p>\u003Cp>注文してから2日？くらい、ようやく手元に届いた3s。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/dc04d39a5f914669ad38ef15365bc4d9/beauty_1764383679952.jpeg\" alt=\"\" width=\"3840\" height=\"2160\">\u003C/figure>\u003Cp>デザインは近未来感があってめっちゃおしゃれ、好きです。\u003C/p>\u003Cp>と言っていたのも束の間、セットアップの段階で早くも洗礼を浴びました。スマホにMeta Horizonなるアプリを入れさせられた挙句、Meta Accountでのログインを強要される始末。手元にいい感じのアカウントを持ち合わせておらず、勢いでリア垢インスタでサインインしてしまったのですが、これ本当に大丈夫なんですかね。\u003Cbr>なんでもかんでも紐付けさせようとするのは最早Metaのお家芸ですが、個人的にはビックテックのこういう仕草はあまり好きではありません。\u003C/p>\u003Cp>ちなみに、購入前に懸念していたフレネルレンズについてですが、明暗がくっきり出る映像ではもやっとした感じが若干残ります。解像度についても、数年前にMeta Quest 3をお借りした時の記憶と比較すると、パンケーキレンズではないことによる若干の解像感低下は否めません。ですが、そもそもの価格帯がかなり違うのでかなり頑張っている印象です。入門機種としてはかなり良く出来ているとは思います。不満があるとすれば、3.5mmのミニプラグ出力が削られていることくらいでしょうか。\u003C/p>\u003Cp>HMDを購入する以前から、フレンドたちから「Virtual Desktopは事実上の人権だから買っておくべだ(意訳)」と散々言われていました。調べてみたところ、接続は無線のみとのこと。\u003C/p>\u003Cp>ここでおうちの無線環境が問題になります。私の自宅では、APに\u003Ca href=\"https://documentation.meraki.com/Go/Product_Information/Meraki_Go_Datasheets/Meraki_Go_Indoor_WiFi_Access_Point_-_GR10_Datasheet\" target=\"_blank\" rel=\"noopener noreferrer\">Meraki Goの古い子(GR-10)\u003C/a>を未だに使っています。当然ながらIEEE 802.11beはおろか、IEEE 802.11axにも対応していません。Virtual Desktopは無線接続が命だ〜みたいな言説を至る所で聞きかじっていたので、正直今の環境では厳しいだろうと踏んでいました。\u003Cbr>見てくれがスマートではないものの、最悪どちゃくそ長いケーブルを買ってきてリバーステザリングでもすればいいかと考えていたほどです。(中身Androidですからね。未検証ですがおそらく\u003Ccode>adb ppp\u003C/code>が使える？はず)\u003C/p>\u003Cp>しかしながら、実際に試してみると、良い意味で拍子抜けしました。ほぼ標準設定のまま(Preferred CodecのみH.265に変更)で、何の問題もなくプレイできてしまったのです。レイテンシが21ms程度ありますが、正直違和感はありません。\u003Cbr>Wi-Fi環境がしんどいと嘆いている方々は、HGWをそのままAPとしても使っていたりするんでしょうか。そもそもあれをAPとして使うのは微妙だと思いますが、真相は謎です。\u003C/p>\u003Cp>そして本題のVRChat。これをやるために買ったわけです。\u003Cbr>今までデスクトップでプレイしていたので驚いたのですが、VR環境だと描画負荷が段違いなんですね。フレンドに誘われて初めてパブリックのFUJIYAMAに行ってきたのですが、制限を緩めにしていたせいか、重すぎて落ちました。どうやらRTX 5070には荷が重かったようです。(VRAM少ないですしね〜)\u003C/p>\u003Cp>あと、はじめて重いワールドに入って気づいたのですが、VRChat側が利用できる帯域を絞っておかないと、Virtual Desktopの転送が異様に重くなります。少ない帯域を取り合っているので仕方ないんでしょうけど。\u003Cbr>最近いい感じにおうちの10GbE環境が整ってきているので、そのうちPC用にNICを買い足して足回りを強化しようと画策しています。\u003C/p>\u003Cp>それにしても、VRChatは楽しいですね。やってることはDiscordでだべってるのと何ら変わらないんですけど、視覚的に色々なインタラクティブな動作ができるだけで、こうも飽きないものなんですね。\u003C/p>\u003Cp>最後に、せっかくHMDを被って電脳世界にダイブしたわけですから、その証拠写真を何枚か貼ってお茶を濁そうと思います。端から見れば、ゴーグルを付けて部屋で一人ニヤニヤしている不審者ですが、本人は至って真面目に楽しんでいますのでご放念ください。\u003C/p>\u003Cp>\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/4a5d391e5c3745428a7821336c8ca2cc/VRChat_2025-12-02_22-48-11.698_2560x1440.png\" alt=\"\" width=\"2560\" height=\"1440\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/c62c62791f6e4107a1de8efec11463d5/VRChat_2025-12-09_18-18-53.129_2560x1440.png\" alt=\"\" width=\"2560\" height=\"1440\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/9d0af32566de4318954616db05e7915f/VRChat_2025-12-09_18-57-17.890_2560x1440.png\" alt=\"\" width=\"2560\" height=\"1440\">\u003C/figure>\u003Cp>あ、そうそう。折角VRデビューを果たしたわけですし、一緒に遊んでくれるフレンドの方を募集しています。これまではデスクトップでひっそりとしていましたが、VRになったのを機に、もう少し人と関わっていきたいな、なんて柄にもないことを思っています。\u003Cbr>ｷﾓ=ｦﾀｸなので早口でにﾆﾁｬﾆﾁｬしていることもあれば、ただ綺麗なワールドを巡ってぼーっとするのも好きです。まだ全然慣れていない初心者ですが、もしよければ仲良くしてやってください。画面の向こうで小躍りして喜びます。\u003C/p>\u003Cp>では。\u003C/p>",[118,119],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":120,"createdAt":121,"updatedAt":122,"publishedAt":121,"revisedAt":122,"slug":123,"name":124},"riqchoqn8lw","2025-11-06T18:20:17.154Z","2025-12-03T16:06:09.687Z","games","ゲーム",{"id":126,"createdAt":127,"updatedAt":128,"publishedAt":128,"revisedAt":128,"title":129,"content":130,"tags":131,"is_no_index":36},"cpum19l7-34","2025-12-06T21:47:12.281Z","2025-12-07T12:57:39.377Z","いい人になりたかった","\u003Cp>幼い頃から、私はよく優しい子だと言われて育ちました。\u003C/p>\u003Cp>今思うと、それは私に際立った才能や愛嬌といった、取り柄が圧倒的に無かったからに過ぎないように思えます。他に褒めるべき点が見当たらない子供を、なんとか他の子供たちと対等な土俵に立たせるために、大人たちが苦し紛れに捻り出した建前としての道具。それが優しさという言葉に内包されていたように思います。\u003C/p>\u003Cp>実際のところ、私は到底優しいと呼ばれるに相応しい人間性を持ち合わせていませんでした。私が振る舞っていたのは、他者を思いやる心などではなく、単に自分の意見を持たず、波風を立てることを恐れ、曖昧に笑ってやり過ごす主体性のなさでした。自己を主張するだけの芯や度胸といったものが欠落していただけなのです。\u003C/p>\u003Cp>自分が空洞であることを、紛い物の優しさというラベルで必死に隠蔽していました。そして残酷なことに、その本質は今も、何ひとつ変わっていません。\u003C/p>\u003Cp>私にとっていい人であることは、道徳的な目標ではなく、切実な生存戦略でした。\u003C/p>\u003Cp>私のような人間にとって、期待で勝手に型へ流し込まれることは、最も楽で、最も安全な生き方です。拒絶されず、攻撃されず、居場所を確保するための擬態。\u003C/p>\u003Cp>誰かの意見に頷き、摩擦を避け、無害な存在として振る舞う。そうしていれば、世界は私を傷つけない。そう信じていました。\u003C/p>\u003Cp>しかし、技術や知識を得て、世界を見る解像度が上がるにつれ、この生存戦略は音を立てて崩れ去りました。\u003C/p>\u003Cp>エンジニアリングの世界に足を踏み入れ、論理や整合性を欲するようになると、かつては見過ごせていた他人の粗が、許容しがたい異様なモノとして目に映るようになってしまいました。\u003C/p>\u003Cp>手のひらに世界中の知財へアクセスできるデバイスを持っていながらも、検索すら惜しみ、「誰か教えて🥺」と幼児のように口を開けて待つ人々。\u003C/p>\u003Cp>救われるべき弱者という自己憐憫が、奉仕されるべき特権階級という傲慢さへと腐敗していく過程。\u003C/p>\u003Cp>その無垢な怠惰さや、被害者という立場を利用した加害性が、私には耐え難い悪臭のように感じられるのです。\u003C/p>\u003Cp>善人の皮を被ったままでは、それらを指摘できません。しかし、飲み込もうとすると、今度は自分が壊れてしまいそうになる。言いたいことを飲み込み、表面だけ取り繕うコストが、得られる平穏のメリットを上回ってしまったのです。だってインターネットでくらい自由に好き放題言いたいじゃないですか。\u003C/p>\u003Cp>私は長い間、自分の攻撃性を正しさへの執着だと言い訳してきました。\u003C/p>\u003Cp>「間違っているから指摘するのだ」「知的生命体としての誠実さだ」と。\u003C/p>\u003Cp>本当はどこかで気づいていたのかもしれません。ある時ふと、その欺瞞に気づいてしまいました。\u003C/p>\u003Cp>私が重ねていたのは、建設的な批判などではなく、対象の動機を疑い、安全圏から石を投げて嘲笑することで優越感に浸る、ただの卑小な冷笑でしかなかったのです。欺瞞を直視せざるを得ない瞬間が訪れてしまいました。\u003C/p>\u003Cp>そこにこうすれば良くなるといった代替案はあったでしょうか。相手の動機を尊重する姿勢はあったでしょうか。\u003C/p>\u003Cp>勿論そんなものは微塵もありません。私がしていたのは、相手が必死になっている姿を嘲笑うことで、「自分はそっち側の人間ではない」と確認するための、卑小なマウンティングでした。\u003C/p>\u003Cp>私は正しいことをしたかったのではなく、安価でコンスタントに消費できる知的快楽を貪りたかっただけなのかもしれません。\u003C/p>\u003Cp>何も作らず、何も提案せず、リスクも取らず、ただ「レベルが低い」｢お前はだめだ｣と吐き捨てるだけで得られる、安っぽくて強烈な全能感に依存していた節は否めません。\u003C/p>\u003Cp>そうでもしないと、空っぽな自分が保てなかった。他人を見下すことでしか、自分の立ち位置を確認できない。その事実に気づいてしまった時の情けなさと、底知れない不安は、言葉にできません。\u003C/p>\u003Cp>自分が正当性のある批判をしていたのではなく、ただの冷笑をしていたことを自覚してしまった今、私はどうすればいいのでしょうか。「これからは心を入れ替えて、建設的な批判だけをします」とか宣言できれば、いいんですけどね。現実はそう簡単にはいきません。\u003C/p>\u003Cp>おそらく私はこれからも変わらず、画面の向こうの誰かを冷笑し続けるのでしょう。実際、彼ら彼女らを見れば不快になり、それを言語化して断罪せずにはいられない気がします。\u003C/p>\u003Cp>｢いい人になりたかった｣\u003C/p>\u003Cp>それは偽らざる本音です。けれど、それ以上に私は、自分の浅はかな賢さを証明したいし、愚かなものを愚かだと断じて安心したい。その醜い欲望を、どうしても手放すことができないみたいです。\u003C/p>\u003Cp>きっと明日も私は、何かを批判したつもりになって冷笑し、誰かを見下して一瞬の快楽を得て、その後に訪れる虚無感と自己嫌悪に震えながら生きていくのだと思います。\u003C/p>\u003Cp>やめようと思ってやめられるなら、とっくの昔にやめていますから。\u003C/p>",[132,133],{"id":53,"createdAt":54,"updatedAt":55,"publishedAt":54,"revisedAt":55,"slug":56,"name":57},{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":135,"createdAt":136,"updatedAt":137,"publishedAt":137,"revisedAt":137,"title":138,"content":139,"tags":140,"is_no_index":36},"37dki_cat","2025-12-03T11:14:35.085Z","2025-12-03T11:26:21.983Z","猫ちゃんが一歳になりました！！","\u003Cp>数ヶ月前にお迎えした猫のモカちゃんが1歳になりました\u003Cbr>とてもめでたい🎉\u003C/p>\u003Cp>お迎え当初と比較すると、サイズも体重もしっかり大きくなってはいるものの、現在は3.5kg前後を推移しており、平均的な体重を若干下回っています。\u003Cbr>元々食が細い子ということもあって、なかなか太ってくれないんですよねー\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/10c34383c40d431d84d92e10f7c3f7c5/beauty_1751863936273.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>↑お迎え当初\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/eb23ee5b0fb64872ac9d4358709f0566/beauty_1764563946779.jpeg\" alt=\"\" width=\"1650\" height=\"928\">\u003C/figure>\u003Cp>↑今\u003C/p>\u003Cp>なにはともあれ、大きな病気もなく無事に1歳になってくれて本当によかったです！\u003C/p>\u003Cp>……ところで、ひとつ悩みが。\u003Cbr>切り替えのタイミングを見誤ったのか、子猫用のフードがあと5kgくらい残っているのですが、これどうしたらいいんですかね。\u003Cbr>当面の間は子猫気分でいてもらうことにします。\u003C/p>\u003Cp>それでは\u003C/p>",[141,142],{"id":78,"createdAt":79,"updatedAt":80,"publishedAt":79,"revisedAt":80,"slug":81,"name":82},{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":144,"createdAt":145,"updatedAt":146,"publishedAt":147,"revisedAt":146,"title":148,"content":149,"tags":150,"is_no_index":36},"5ybjx06von0","2025-11-06T18:20:06.910Z","2025-11-06T18:26:20.273Z","2025-11-06T18:24:32.966Z","RustのゲームサーバーをDockerで建てた","\u003Cp>どうも、わたしです。 \u003C/p>\u003Cp>先日、Rust(軽量でメモリ安全性が担保されているものではない方)が安くなっていたので、仲間内でサーバーを建ててマルチプレイをしよう、ということになりました。\u003Cbr>ただ生憎と、現状私の手元には自由に使えるIPv4アドレスの在庫が枯渇していまして、仕方がないので適当なVPSを契約し、そこにサーバーを構築しようとしました。\u003C/p>\u003Cp>導入方法を調べてみたところ、大筋としてはSteamCMDを使い、サーバーデータをダウンロードして必要な引数を渡して起動するだけ、と手順自体はシンプルなようでした。\u003Cbr>ところが、検索して出てくる記事の多くは、なぜかsnapでSteamCMDをインストールする方法だったり、無駄にsystemdのサービスを増やすようなものだったりと、本当に気持ちが悪いものばかり。\u003Cbr>何も考えずに色んなところからコピペしてコマンドを並べているだけなのかと疑うレベルの記事ばかりで、正直うんざりしていました。\u003C/p>\u003Cp>さらに、手軽に使えるDockerイメージも現存していないようでしたので、今回作成するに至りました。\u003C/p>\u003Cp>私の普段使いの環境がM4 Maxなのですが、ここで一つ問題にぶつかりました。\u003Cbr>SteamCMDがARMアーキに対応していなかったのです。\u003C/p>\u003Cp>このご時世においてARMのサポートをしていないなんて前時代的ですよね。有り得ない。\u003C/p>\u003Cp>とはいえ、嘆いても仕方がないので、ちゃっちゃとDockerfileを書き、互換レイヤを挟んで試みるもうまくいかず。\u003Cbr>結局面倒くさくなって適当な8664環境を作って解決しました。\u003C/p>\u003Cp>ちなみに、今回の成果物は、全てGitHub上で公開しています。\u003Cbr>\u003Ca href=\"https://github.com/chan-mai/docker-rust-gameserver\" target=\"_blank\" rel=\"noopener noreferrer nofollow\">https://github.com/chan-mai/docker-rust-gameserver\u003C/a> \u003C/p>\u003Cp>リポジトリ上に置いてある \u003Ccode>compose.yaml\u003C/code> をコピーしてきてもらい、適宜、環境変数を変えていただければ、そのまま使えます。\u003Cbr>詳しいことはREADMEに書いているので、そちらをご参照ください。\u003C/p>\u003Cp>これで面倒なことを考えずにRustで遊べますね。\u003C/p>\u003Cp>\u003C/p>",[151,152,153,154],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":47,"createdAt":48,"updatedAt":49,"publishedAt":48,"revisedAt":49,"slug":50,"name":51},{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},{"id":120,"createdAt":121,"updatedAt":122,"publishedAt":121,"revisedAt":122,"slug":123,"name":124},{"id":156,"createdAt":157,"updatedAt":158,"publishedAt":158,"revisedAt":158,"title":159,"content":160,"tags":161,"is_no_index":36},"w4q57e0zh0v1","2025-10-05T08:09:52.259Z","2025-10-05T08:20:42.619Z","サイトをリニューアルしたにょ","\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>どうも、わたしです。\u003C/p>\u003Cp>先日、このサイトにいくつかの変更を加えました。 \u003Cbr>元々は、壁打ちブログのつもりで運営していたのですが、承認欲求がとうとう無視できない大きさになってしまいまして。 \u003Cbr>ちなみに、ここで話すソースコードは全てGitHub上に公開しているので、もし気になる人がいれば、読んでみてもらえると嬉しいです。\u003Cbr>\u003Ca href=\"https://github.com/chan-mai\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/chan-mai\u003C/a>\u003C/p>\u003Cp>開発を始めた当初は、ただただコメントといいね機能を追加するだけの、簡単な改修のつもりでした。\u003Cbr>ところが、いざ作り始めると「コメントは絶対に自分の目で見てから承認したい」「どうせなら管理画面もちゃんと作りたい」と、次から次へとやりたいことが溢れてきてしまい、その結果、そこそこ本格的なWebアプリケーションへと変貌を遂げました。\u003Cbr>最初の動機を考えると、拍子抜けするほど大掛かりなものになってしまったな、というのが正直な感想です。\u003C/p>\u003Ch1 id=\"h2220f0ef7d\">やったこと\u003C/h1>\u003Cp>今回の改修の始まりは、サイトに外との接点となるインタラクション機能を設けることでした。\u003C/p>\u003Cp>まず手始めに、いいね機能に手を入れています。\u003Cbr>仕組みは簡単なもので、ユーザーがハートを押すとAPIが叩かれ、記事の\u003Ccode>contentId\u003C/code>やIPアドレスなんかが記録されます。\u003Cbr>同時にlocalStorageにuuidが保存されるのですが、これはいいねの解除時に使うためだけのものであって、IPベースでの制限はしていないので、スマホとPCから同じ記事に…みたいなことも普通に出来てしまいます。\u003Cbr>普通に欠陥な気もするのですが、ちゃんと実装する気力はなかったので仕様です。\u003C/p>\u003Cp>そして、コメント機能。\u003Cbr>だいたいコメントというのは常々、おぞましいほどに醜い言葉で溢れるのが大概で、私はそういうものを目にしたくないのです。\u003Cbr>だから、どうしてもコメントを完全にコントロールする手段が必要でした。\u003Cbr>その解決策が、投稿されたコメントを一つひとつ自分の目で確認し、手動で承認するという運用フローと、それを実現するための管理コンソールだったわけです。\u003C/p>\u003Cp>ここからは、技術的な話をちょっとだけします。\u003C/p>\u003Ch1 id=\"h55235f9fca\">コメント機能の裏側\u003C/h1>\u003Cp>まず、コメント機能そのものの話から。\u003C/p>\u003Cp>ユーザーがコメントを投稿すると、\u003Ccode>POST /api/comment/[contentId]\u003C/code>というAPIが叩かれます。\u003Cbr>バックエンドでは、ユーザー入力値の基本的なバリデーションと、お気持ち程度のTurnstileのtoken検証のみを行なっています。\u003Cbr>投稿されたコメントは、まずデータベースに\u003Ccode>PENDING\u003C/code>ステータスで保存されます。\u003Cbr>このステータス管理が肝で、Prismaのスキーマに\u003Ccode>CommentStatus\u003C/code>というenumを定義して、\u003Ccode>PENDING\u003C/code>、\u003Ccode>APPROVED\u003C/code>、\u003Ccode>REJECTED\u003C/code>の3つの状態を持たせました。\u003Cbr>承認されるまでAPIの返り値を含めフロントには一切露出しない、完全な事前承認制です。\u003C/p>\u003Ch1 id=\"heb9db543a7\">データベース\u003C/h1>\u003Cp>これらのデータを保存しているのが、CockroachDBという分散SQLデータベースです。\u003Cbr>所謂NewSQLとかいうやつですね。\u003Cbr>PostgreSQLと互換性がありつつ、スケーラビリティと耐障害性に優れている面白い子で、名前が気持ち悪いことを除けば結構好きです。\u003C/p>\u003Cp>ORMにはPrismaを選びました。\u003Cbr>「型安全でマイグレーションが簡単！」とは言うものの、最近のORMであれば大体は似たようなことができる気がします。\u003Cbr>選定理由は単なる好みです。\u003Cbr>名前かわいいし！\u003C/p>\u003Cp>今回追加した主なモデルは、いいね用の\u003Ccode>Favorites\u003C/code>、コメント用の\u003Ccode>Comments\u003C/code>、そして管理者情報を格納する\u003Ccode>AdminUser\u003C/code>と権限を管理する\u003Ccode>AdminPermission\u003C/code>。\u003C/p>\u003Cdiv data-filename=\"prisma/schema.prisma\">\u003Cpre>\u003Ccode>// いいね\nmodel Favorites {\n  id        String   @id @default(uuid(7))\n  contentId String   @map(&quot;content_id&quot;)\n  userIp    String   @map(&quot;user_ip&quot;)\n  createdAt DateTime @default(now()) @map(&quot;created_at&quot;)\n  updatedAt DateTime @updatedAt @map(&quot;updated_at&quot;)\n\n  @@index([contentId])\n  @@index([userIp])\n  @@map(&quot;favorites&quot;)\n}\n\n// コメントステータス\nenum CommentStatus {\n  PENDING // 承認待ち\n  APPROVED // 承認\n  REJECTED // 拒否\n}\n\n// コメント\nmodel Comments {\n  id        String        @id @default(uuid(7))\n  contentId String        @map(&quot;content_id&quot;)\n  name      String\n  comment   String\n  userIp    String        @map(&quot;user_ip&quot;)\n  status    CommentStatus @default(PENDING)\n  createdAt DateTime      @default(now()) @map(&quot;created_at&quot;)\n  updatedAt DateTime      @updatedAt @map(&quot;updated_at&quot;)\n\n  @@index([contentId])\n  @@index([userIp])\n  @@index([status])\n  @@map(&quot;comments&quot;)\n}\n\n// 権限の種類\nenum Permission {\n  COMMENT_VIEW      // コメント閲覧\n  COMMENT_ADMIN     // コメント管理\n  FAVORITE_VIEW     // お気に入り閲覧\n  FAVORITE_ADMIN    // お気に入り管理\n  ADMIN_USER_VIEW   // 管理者ユーザー閲覧\n  ADMIN_USER_ADMIN  // 管理者ユーザー管理\n}\n\n// 管理者ユーザー\nmodel AdminUser {\n  id              String            @id @default(uuid(7))\n  githubUsername  String            @unique @map(&quot;github_username&quot;)\n  githubUserId    BigInt            @map(&quot;github_user_id&quot;)\n  displayName     String?           @map(&quot;display_name&quot;)\n  email           String?\n  avatarUrl       String?           @map(&quot;avatar_url&quot;)\n  isActive        Boolean           @default(true) @map(&quot;is_active&quot;)\n  createdAt       DateTime          @default(now()) @map(&quot;created_at&quot;)\n  updatedAt       DateTime          @updatedAt @map(&quot;updated_at&quot;)\n  permissions     AdminPermission[]\n\n  @@index([githubUsername])\n  @@index([isActive])\n  @@map(&quot;admin_users&quot;)\n}\n\n// 管理者権限\nmodel AdminPermission {\n  id         String     @id @default(uuid(7))\n  adminId    String     @map(&quot;admin_id&quot;)\n  permission Permission\n  createdAt  DateTime   @default(now()) @map(&quot;created_at&quot;)\n  updatedAt  DateTime   @updatedAt @map(&quot;updated_at&quot;)\n  admin      AdminUser  @relation(fields: [adminId], references: [id], onDelete: Cascade)\n\n  @@unique([adminId, permission])\n  @@index([adminId])\n  @@index([permission])\n  @@map(&quot;admin_permissions&quot;)\n}\u003C/code>\u003C/pre>\u003C/div>\u003Cp>\u003C/p>\u003Ch1 id=\"h495fd6e106\">管理コンソール\u003C/h1>\u003Cp>この管理コンソールこそ、今回の改修で最も大きな作業となった代物です。\u003Cbr>「コメントは絶対に自分の目で見てから承認したい」という要件が、この巨大な機能を生み出すきっかけでした。\u003Cbr>最初は適当なBASIC認証でなんとかしようと思っていたのですが、「どうせならとログイン機能も…」と考えたのが運の尽きです。\u003C/p>\u003Cp>認証には手軽なGitHub OAuthを採用しました。\u003Cbr>ユーザーがログインするとGitHubの認証ページに飛び、認可が済むとコールバックURLに戻ってくる。\u003Cbr>GitHubから受け取ったユーザー情報が\u003Ccode>AdminUser\u003C/code>テーブルに登録されていて、かつアクティブならセッションを発行する、という流れです。\u003C/p>\u003Cp>セッション管理には\u003Ccode>nuxt-auth-utils\u003C/code>を利用しました。\u003Cbr>内部的にJWTを使い、いい感じにサーバーサイドでセッションを検証してくれます。\u003Cbr>認証関連の処理は\u003Ccode>server/utils/auth.ts\u003C/code>にまとめていて、特に\u003Ccode>requireAdminSession\u003C/code>関数では、リクエストごとに管理者の存在とアクティブ状態をDBに確認しにいく割と厳格な権限確認を行っています。\u003Cbr>Middlewareで未認証ユーザーをサインインページに弾いてくれるので、部外者が管理画面を覗くことはできません。\u003C/p>\u003Cp>そして極め付けが、RBACの実装です。\u003Cbr>このサイトの管理者は私一人しかいないのに、いくつかの細かい権限を定義しています。完全に過剰な機能ですね。\u003C/p>\u003Cp>でも、この設計のおかげで、将来「この人にはコメントの承認だけ任せたい」なんてことが可能になりました。\u003Cbr>各APIエンドポイントの冒頭で\u003Ccode>requirePermission\u003C/code>関数を呼び出して権限をチェックし、フロント側でもComposableで、権限に応じた表示に切り替えています。\u003C/p>\u003Cp>UIも割といい感じにできたので自慢がてら見せびらかしておきます。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/a0e5f14bbe1c4e50a04cb7770218956d/image.png\" alt=\"\" width=\"3600\" height=\"2338\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/a257735d764c4c85b995d6f9b42517ea/image.png\" alt=\"\" width=\"3600\" height=\"2338\">\u003C/figure>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/554a3692ecaa488880af06b58022b603/image.png\" alt=\"\" width=\"3600\" height=\"2338\">\u003C/figure>\u003Cp>\u003C/p>\u003Ch1 id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp>今回のサイト改修は、過去のちょっとした機能追加が嘘のように、大規模なものとなりました。 \u003Cbr>承認欲求という、どちらかといえばネガティブな感情から始まった作業でしたが、いざ手を動かし始めると、技術的な好奇心がすべてを上回ってしまった感じです。\u003C/p>\u003Cp>満足したので安心して眠れます。\u003Cbr>それでは。\u003C/p>",[162,163,164],{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},{"id":93,"createdAt":94,"updatedAt":95,"publishedAt":94,"revisedAt":95,"slug":96,"name":97},{"id":166,"createdAt":167,"updatedAt":168,"publishedAt":169,"revisedAt":168,"title":170,"content":171,"tags":172,"is_no_index":36},"svgkndwg3ng9","2025-09-29T13:06:03.316Z","2026-06-26T14:50:56.142Z","2025-09-29T13:16:44.358Z","独自ドメインでのメールアドレス運用をやめ、Hide My Emailに移行した話","\u003Cp>どうも、わたしです。\u003Cbr>今日は、長らく頭を悩ませていたメールアドレスの運用について、その移行経緯と最終的な結論を記録しておこうと思います。\u003C/p>\u003Ch1 id=\"h8d027c8ed3\">はじめに\u003C/h1>\u003Cp>かつては自宅サーバでメールサーバを運用していましたが、自宅サーバ群の完全撤廃に伴い、その運用も当然ながら終了しました。\u003Cbr>以前はHomeNOCより割り当ていただいたIPで運用していましたが、自宅の一般回線はOP25Bの影響を避けられないため、代替としてAmazon Simple Email Service (SES)を暫定的に利用していた、というのがこれまでの経緯です。\u003C/p>\u003Cp>SESのコストや機能に大きな不満はなかったものの、ごく稀に発生するGmailへの転送失敗という、再現性の低い問題が看過できなくなり、本格的に移行先を探すことにしました。\u003C/p>\u003Ch1 id=\"h408cdaab63\">検討と検討と検討\u003C/h1>\u003Cp>まず、国内でよく名前が挙がる安価なメールサービス、例えばConoHaやさくらのメールボックスあたりから検討を始めましたが、これらはその仕様のお粗さから、候補にすら入りませんでした。\u003C/p>\u003Cp>特にさくらのメールボックスに関しては、価格の安さからスパム業者の温床になっているという話は有名で、実際にAS単位でメールサービスからブロックされることも珍しくありません。\u003Cbr>私のような真っ当な利用者が、なぜスパマーのせいでメールが届かないリスクを負わなければならないのか。\u003Cbr>サービス設計としてあり得ない話です。\u003Cbr>たまったものではありません。\u003C/p>\u003Cp>そもそも私の要件は極めてシンプルです。\u003C/p>\u003Col>\u003Cli>独自ドメインで、大量のアドレスを生成・受信できること。\u003C/li>\u003Cli>それらを普段使いのメールボックスに転送できること。\u003C/li>\u003Cli>生成した大量のアドレスからメールを送信できること。\u003C/li>\u003C/ol>\u003Cp>メインで利用しているメールアドレスを、素性の知れないウェブサービスに登録するのが生理的に受け付けない、というだけの理由で、サービスごとにアドレスを使い分けるためだけに独自ドメインを利用しています。\u003Cbr>プライバシがどうこうという崇高な理念は、あいにくと持ち合わせていません。\u003Cbr>現代において、ビッグテックから完全に情報を秘匿することが、現代においてどれほど非現実的か理解しているつもりですので。\u003C/p>\u003Cp>Tech系の界隈を見渡すと、Zoho MailやProtonMailを利用している層がかなり観測できます。\u003Cbr>しかし、私のユースケースはサービス登録の都度、数百から数千といった単位でアドレスを量産することにあるため、エイリアス数に課金されるこれらのサービスはコスト的に全く見合いません。\u003C/p>\u003Cp>コストだけを考えればCloudflare Email Routingも候補でしたが、基本的に受信専用のものでした。\u003Cbr>送信もそれなりに行うため、機能的に片手落ちであり、これも除外。(これを書いている少し前に\u003Ca href=\"https://blog.cloudflare.com/email-service/\" target=\"_blank\" rel=\"noopener noreferrer\">Cloudflare Email Service’s\u003C/a>なるものがプライベートベータとしてリリースされたようですが、検討していた時点では存在しなかったため、考慮していません)\u003C/p>\u003Cp>正直なところ、VPSを借りて再びメールサーバを構築することも一瞬考えました。\u003Cbr>しかし、あの不毛な設定と、セキュリティアップデートやスパム対策に追われる運用保守に、再び貴重なリソースを投下するのはあまりにも非合理的だと判断し、即座に却下しました。\u003Cbr>あんな面倒なこと、二度とやりたくありません。\u003C/p>\u003Ch1 id=\"h046bdabcec\">Apple Hide My Email、お前だったのか\u003C/h1>\u003Cp>ここで私はiCloud+に含まれるHide My Email機能の存在に行き着きます。\u003C/p>\u003Cp>最近の私の身の回りは比較的Apple製品で固められており、そのエコシステムとの親和性は言うまでもありません。\u003Cbr>そして何より、私の目的はアドレスを使い分けることであり、独自ドメインの利用は、その目的を達成するための単なる手段に過ぎませんでした。\u003Cbr>その手段へのこだわりを捨てることに、何のためらいもありません。\u003C/p>\u003Cp>むしろ、独自ドメインを手放すことには予期せぬメリットすらありました。\u003Cbr>PictLinkのような、特定のドメイン以外からの登録を受け付けない、前時代的で愚かな仕様を持つサービスが未だに存在しますが、\u003Ccode>icloud.com\u003C/code>というドメインパワーの前では、そうした問題も発生しにくい。\u003Cbr>これはうれしい。我ながらかなり合理的な判断です。\u003C/p>\u003Cfigure>\u003Cimg src=\"https://images.microcms-assets.io/assets/3aba23b5bd6f4b79800a0305d0e4f8aa/eae3d94adc674e3b89835222a24fd6ef/D510F5C4-01C7-4CC9-966C-29245F32CE0D.JPG?w=600&amp;h=1303\" alt=\"\" width=\"600\" height=\"1303\">\u003C/figure>\u003Cp>一つ問題だったのは、パスワード管理に利用しているVaultwarden(Bitwarden互換)のクライアントから、直接Hide My Emailのアドレスを生成できない点でした。\u003Cbr>サービス登録のたびに手動でアドレスを生成し、コピペするのは普通にしんどいですし、UXとして最悪です。\u003C/p>\u003Cp>しかし、この問題は\u003Ca href=\"https://misskey.vip/@n\" target=\"_blank\" rel=\"noopener noreferrer\">お友達のまくらくら\u003C/a>が作っていたブリッジツールによって解決しました。\u003Cbr>\u003Ca href=\"https://github.com/lqvp/hme_bridge\" target=\"_blank\" rel=\"noopener noreferrer\">https://github.com/lqvp/hme_bridge\u003C/a>\u003C/p>\u003Cp>外向きにはSimpleLoginのAPIとして振る舞うことで、Bitwardenクライアントを騙し、内部でiCloudのAPIを叩いているようです。\u003Cbr>Rustで書かれていたのでコードの詳細は読んでいませんが、きちんと動くので多分問題ないでしょう。\u003Cbr>ありがたく利用させてもらうことにしました。\u003C/p>\u003Cp>各種サービスに登録していたメールアドレスの変更も概ね完了し、現在はiCloud基盤で安定して稼働しています。\u003Cbr>SES + Lambdaの環境で発生していたようなメールのロストもなく、不満はありません。\u003C/p>\u003Ch1 id=\"h1afe451c43\">さいごに\u003C/h1>\u003Cp>最近のサービスはSSOを前提とし、ユーザにメールアドレスの入力すらさせず、GoogleアカウントやiCloudアカウントでログインさせるものが増えているように感じます。\u003Cbr>この風潮の背景には、「原則としてユーザは馬鹿で愚かで無能なものなので、まともにアカウント管理など到底できる訳がない」という、サービス提供者側の諦観にも似た思想があるのでしょう。\u003Cbr>それ自体は否定しませんし、私も同感です。\u003C/p>\u003Cp>しかし、例えばGoogleのような単一の認証基盤に、あらゆるサービスの認証を依存させるアーキテクチャには、強い違和感を覚えます。\u003Cbr>これは、すこし考え方を変えて見れば、SPOFを意図的に作り出しているに等しいあまりにも稚拙で傲慢な設計です。\u003Cbr>一つのサービスから情報が流出しただけで、他の全アカウントに影響が及びかねない構造など、本来あってはならない。\u003Cbr>どうやら世の中の多くの人間に、まともなセキュリティ感覚はないらしいようです。\u003C/p>\u003Cp>GoogleがDon&apos;t be evilを捨てて久しいですが、そのGoogleアカウントに生活の全てを預けることを、なぜ誰も疑問に思わないのでしょうか。\u003Cbr>なーにがゼロトラストだ。口だけでフルトラストじゃないか。\u003C/p>",[173,174,175],{"id":30,"createdAt":31,"updatedAt":32,"publishedAt":31,"revisedAt":32,"slug":33,"name":34},{"id":47,"createdAt":48,"updatedAt":49,"publishedAt":48,"revisedAt":49,"slug":50,"name":51},{"id":6,"createdAt":7,"updatedAt":8,"publishedAt":7,"revisedAt":8,"slug":9,"name":10},23,12,1783975282494]