[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"/api/social-links:{}":3,"/api/blogs/nginx-dns-resolution-failure:{}":9},{"links":4},[5],{"platform":6,"url":7,"icon":8},"note","https://note.com/morinoupa2020","simple-icons:note",{"post":10,"relatedPosts":39,"prevPost":117,"nextPost":118},{"id":11,"slug":12,"title":13,"date":14,"excerpt":15,"content":16,"thumbnail":17,"categories":18,"tags":23,"difficulty":35,"tldr":36,"readingTime":37,"relatedTech":38},9001,"nginx-dns-resolution-failure","nginxが一瞬のDNS失敗で起動不能になった話と、proxy_pass の落とし穴","2026-04-15T10:00:00","公開中のポートフォリオサイトが数日間ダウンしていた——原因はnginxの proxy_pass が起動時のDNS失敗で停止していたこと。切り分けの考え方から、変数経由＋resolverによる対策、再発防止の外形監視までを振り返ります。","\u003Ch2>はじめに\u003C/h2>\n\u003Cp>自分のポートフォリオサイトが数日間ダウンしていたことに気づかず、慌てて調査したところ、原因はnginxの \u003Ccode>proxy_pass\u003C/code> に書いていた外部ドメインが、起動タイミングで一瞬だけ名前解決に失敗したことでした。個人サイトとはいえ、公開している以上、落ちていることに気づかないのはさすがにまずい。今回の経緯と対策を、自分への戒めとして残しておきます。\u003C/p>\n\u003Ch2>事象サマリ\u003C/h2>\n\u003Cp>先に結論から書きます。\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>症状\u003C/strong>: HTTPS/HTTPともに Connection refused。ICMPは通る\u003C/li>\n\u003Cli>\u003Cstrong>真犯人\u003C/strong>: nginxが停止したまま数日間放置されていた\u003C/li>\n\u003Cli>\u003Cstrong>直接の引き金\u003C/strong>: 何らかのトリガーでnginxの再起動が走った際、\u003Ccode>proxy_pass\u003C/code> に書かれた外部ドメインの名前解決が一瞬失敗 → 設定テストが \u003Ccode>[emerg]\u003C/code> で落ちた\u003C/li>\n\u003Cli>\u003Cstrong>なぜ復旧しなかったか\u003C/strong>: systemd側の挙動で、設定テスト失敗時は起動せず自動リトライもしない構成だった\u003C/li>\n\u003Cli>\u003Cstrong>対策\u003C/strong>: upstream ドメインを変数経由に変更し、起動時解決を排除\u003C/li>\n\u003C/ul>\n\u003Ch2>環境構成\u003C/h2>\n\u003Cp>構成はよくあるヘッドレスWordPress + Nuxtです。\u003C/p>\n\u003Cpre>\u003Ccode>  [User Browser]\n        │\n        │ HTTPS\n        ▼\n  ┌─────────────────────┐\n  │       VPS           │\n  │  ┌───────────────┐  │\n  │  │    nginx      │  │\n  │  │ (リバースプロキシ) │\n  │  └───┬───────┬───┘  │\n  │      │       │      │\n  │      ▼       │      │\n  │   [Nuxt]     │      │\n  │   (127.0.0.1 │      │\n  │    :3000)    │      │\n  └──────────────┼──────┘\n                 │ HTTPS\n                 ▼\n        ┌─────────────────┐\n        │  WordPress      │\n        │  (別のホスト)    │\n        │  cms.example.com│\n        └─────────────────┘\u003C/code>\u003C/pre>\n\u003Cp>nginxはフロントの手前に立ちつつ、一部のパス（\u003Ccode>/wp-uploads/\u003C/code>）をCMS側のホストへプロキシしてメディアファイルを配信する役割も担っています。今回引き金になったのは、このプロキシ設定でした。\u003C/p>\n\u003Ch2>症状の切り分け\u003C/h2>\n\u003Cp>気づいたときの最初の確認はこんな感じです。\u003C/p>\n\u003Cpre>\u003Ccode class=\"language-bash\">curl -I https://morinoupa.jp\n# curl: (7) Failed to connect to morinoupa.jp port 443: Connection refused\n\nping -c 2 morinoupa.jp\n# 64 bytes from ...: icmp_seq=1 ttl=54 time=7.73 ms\u003C/code>\u003C/pre>\n\u003Cp>ここで頭に入れておきたい切り分けのロジックはシンプルです。\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>ICMPが通らない\u003C/strong> → サーバーダウン、ネットワーク断、ファイアウォール遮断などを疑う\u003C/li>\n\u003Cli>\u003Cstrong>ICMPは通るがポートが閉じている\u003C/strong> → リバースプロキシ／アプリが起動していない\u003C/li>\n\u003Cli>\u003Cstrong>接続は成立するが5xxが返る\u003C/strong> → アプリが落ちているが、プロキシは生きている\u003C/li>\n\u003C/ul>\n\u003Cp>今回は真ん中のパターンでした。アプリ（Nuxt）が落ちているだけなら、プロキシが \u003Ccode>502 Bad Gateway\u003C/code> を返すはずです。今回は接続自体が拒否されているので、プロキシ層そのものが死んでいる疑いが濃い。\u003C/p>\n\u003Ch2>原因調査のプロセス\u003C/h2>\n\u003Cp>とりあえずさくらVPSのコンソールから再起動してサイトを復旧させた後、落ち着いてログを掘っていきます。\u003C/p>\n\u003Ch3>systemdの起動履歴を遡る\u003C/h3>\n\u003Cpre>\u003Ccode class=\"language-bash\">last reboot\n# reboot   system boot  6.8.0-107-generic Tue Apr 14 18:56   still running\n# reboot   system boot  6.8.0-36-generic  Tue Feb 24 13:59   still running\u003C/code>\u003C/pre>\n\u003Cp>2月から4月まで再起動していないので、稼働中に何かが起きたことがわかります。\u003C/p>\n\u003Ch3>前ブートのログを見る\u003C/h3>\n\u003Cp>ブート単位でログを絞り込みたいときは \u003Ccode>journalctl -b\u003C/code> を使います。\u003Ccode>-b\u003C/code> 単独なら現在のブート、\u003Ccode>-b -1\u003C/code> でひとつ前のブートのログに絞れます。今回は停止していた時間帯を確認したいので、前ブートを指定します。\u003C/p>\n\u003Cpre>\u003Ccode class=\"language-bash\">journalctl -u nginx -b -1 --no-pager | tail -40\u003C/code>\u003C/pre>\n\u003Cp>出力の末尾にこれが残っていました。\u003C/p>\n\u003Cpre>\u003Ccode>Apr 10 06:48:03 Stopping nginx.service - A high performance web server and a reverse proxy server...\nApr 10 06:48:03 nginx[443481]: 2026/04/10 06:48:03 [emerg] 443481#443481:\n                 host not found in upstream \"cms.example.com\"\n                 in /etc/nginx/sites-enabled/morinoupa.jp:52\nApr 10 06:48:04 nginx[443481]: nginx: configuration file /etc/nginx/nginx.conf test failed\u003C/code>\u003C/pre>\n\u003Cp>そしてこの後に、\u003Ccode>Started nginx.service\u003C/code> のログがありません。つまり \u003Cstrong>4/10の朝に停止して以来、起動していない状態が続いていた\u003C/strong> ということ。4日近く落ちっぱなしだったことになります。\u003C/p>\n\u003Ch3>AIに伴走してもらった\u003C/h3>\n\u003Cp>ここまで書くと整然としていますが、実際の調査では途中からAIに手伝ってもらっています。\u003C/p>\n\u003Cp>私の手元ではAIにSSHの鍵へのアクセス権を渡していて、自分でサーバーにログインしてコマンドを叩ける状態にしてあります。ただし \u003Ccode>sudo\u003C/code> はこちらで叩くスタイルで、権限昇格が必要な操作は人が明示的に実行する運用です。\u003C/p>\n\u003Cp>この切り分けだと、AIは \u003Cstrong>ログ確認や設定の読み取りなど、コマンドを投げて結果を眺める系の作業\u003C/strong> で真価を発揮します。たとえば「前ブートのnginxログを遡って、emergなどの異常を抜き出して」と頼むと、\u003Ccode>journalctl -u nginx -b -1\u003C/code> を叩き、該当する行を抜粋して返してくれる。人間がやると、長大なログを眺めてパターンを探す時間が地味にかかる作業です。それを「ここにnginx停止の形跡があります」と数秒で返してくれると、思考の速度がまるで変わります。\u003C/p>\n\u003Cp>またメモリ不足を最初に疑ってから「OOM killerの形跡はない」と結論づけるまでの工程も、\u003Ccode>dmesg -T | grep -i oom\u003C/code> や関連journalを突き合わせて一緒に潰してくれるので、仮説を早く切り替えられました。\u003C/p>\n\u003Cp>\u003Cstrong>「危険な操作は人間、調査と提案はAI」\u003C/strong> という切り分けは、安全性とスピードのバランスが取りやすい運用だと感じています。\u003C/p>\n\u003Ch2>何が引き金だったのか\u003C/h2>\n\u003Cp>実ログだけでは、何が最初にnginxに再起動をかけたのか、完全には断定できませんでした。\u003Ccode>systemd\u003C/code> のログには \u003Ccode>Stopping nginx.service\u003C/code> と、その直後に \u003Ccode>nginx -t\u003C/code> が \u003Ccode>[emerg]\u003C/code> で失敗した記録だけが残っていて、そこから先の \u003Ccode>Started\u003C/code> が出ていない、という状態。時間帯的に見るとapt の unattended-upgrades による nginxパッケージ更新や、certbotの定期更新あたりが候補ですが、決定打は出せませんでした。\u003C/p>\n\u003Cp>いずれにせよ、\u003Cstrong>「設定テストに通らないため起動できない」状態に陥ったこと自体が問題\u003C/strong>で、トリガー側を追うよりもそちらを塞ぐ方が実効性が高いと判断しました。\u003C/p>\n\u003Ch2>なぜnginxが起動できなくなるのか\u003C/h2>\n\u003Cp>本題の技術要素はこちらです。\u003Ccode>proxy_pass\u003C/code> に外部ドメインをリテラルで書くと、起動時の名前解決に依存してしまいます。\u003C/p>\n\u003Cp>nginxの \u003Ccode>proxy_pass\u003C/code> には、ドキュメント上ふたつの挙動モードがあります。\u003C/p>\n\u003Ch3>モード1: リテラル記述\u003C/h3>\n\u003Cpre>\u003Ccode class=\"language-nginx\">location /wp-uploads/ {\n    proxy_pass https://cms.example.com/wp-content/uploads/;\n}\u003C/code>\u003C/pre>\n\u003Cp>この書き方だと、nginxは設定ファイルを読み込むとき（起動時 or reload時）に \u003Ccode>cms.example.com\u003C/code> の名前解決を一度だけ行い、IPアドレスをキャッシュします。以降はそのIPにアクセスし続ける。この挙動には以下の問題があります。\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>起動時にDNSが一瞬でも詰まっていると、設定テストが \u003Ccode>[emerg]\u003C/code> で失敗し、nginxが起動できない\u003C/strong>\u003C/li>\n\u003Cli>解決結果はキャッシュされるため、\u003Cstrong>起動後にupstreamのIPが変わっても追従しない\u003C/strong>（ELBやホスティング移行などで地味に困る）\u003C/li>\n\u003C/ul>\n\u003Ch3>モード2: 変数経由\u003C/h3>\n\u003Cpre>\u003Ccode class=\"language-nginx\">location /wp-uploads/ {\n    resolver 8.8.8.8 1.1.1.1 valid=300s ipv6=off;\n    set $cms_upstream \"cms.example.com\";\n    proxy_pass https://$cms_upstream;\n}\u003C/code>\u003C/pre>\n\u003Cp>\u003Ccode>proxy_pass\u003C/code> に変数が含まれると、nginxは起動時の名前解決をスキップし、リクエストが来たタイミングで \u003Ccode>resolver\u003C/code> を使って毎回解決します。このモードだと以下のメリットがあります。\u003C/p>\n\u003Cul>\n\u003Cli>起動時のDNS揺らぎに左右されない（設定テストは常に通る）\u003C/li>\n\u003Cli>upstreamのIP変動に自動追従する\u003C/li>\n\u003Cli>\u003Ccode>valid=\u003C/code> で指定した秒数だけキャッシュされるので、過度な問い合わせも防げる\u003C/li>\n\u003C/ul>\n\u003Ch2>対策として入れた変更\u003C/h2>\n\u003Cp>実際に適用した差分はこちらです。\u003C/p>\n\u003Ch3>変更前\u003C/h3>\n\u003Cpre>\u003Ccode class=\"language-nginx\">location /wp-uploads/ {\n    proxy_pass https://cms.example.com/wp-content/uploads/;\n    proxy_set_header Host cms.example.com;\n    proxy_set_header Authorization \"\";\n    proxy_http_version 1.1;\n    expires 7d;\n    add_header Cache-Control \"public, immutable\";\n}\u003C/code>\u003C/pre>\n\u003Ch3>変更後\u003C/h3>\n\u003Cpre>\u003Ccode class=\"language-nginx\">location /wp-uploads/ {\n    resolver 8.8.8.8 1.1.1.1 valid=300s ipv6=off;\n    resolver_timeout 5s;\n    set $cms_upstream \"cms.example.com\";\n    rewrite ^/wp-uploads/(.*)$ /wp-content/uploads/$1 break;\n    proxy_pass https://$cms_upstream;\n    proxy_set_header Host cms.example.com;\n    proxy_set_header Authorization \"\";\n    proxy_http_version 1.1;\n    proxy_ssl_server_name on;\n    expires 7d;\n    add_header Cache-Control \"public, immutable\";\n}\u003C/code>\u003C/pre>\n\u003Cp>いくつか補足します。\u003C/p>\n\u003Ch3>なぜ \u003Ccode>rewrite\u003C/code> が必要か\u003C/h3>\n\u003Cp>\u003Ccode>proxy_pass\u003C/code> にURIパス部分（\u003Ccode>/wp-content/uploads/\u003C/code>）を書いていると、nginxはlocationのプレフィックス（\u003Ccode>/wp-uploads/\u003C/code>）を自動的に置き換えてくれます。便利な機能ですが、\u003Cstrong>\u003Ccode>proxy_pass\u003C/code> に変数が入っている場合、このURI自動書き換えは使えません\u003C/strong>。\u003C/p>\n\u003Cp>そのため、パスの書き換えを \u003Ccode>rewrite\u003C/code> で明示する必要があります。\u003Ccode>break\u003C/code> フラグを付けることで、書き換え後のURIが同じlocation内で処理されるようにしています。\u003C/p>\n\u003Ch3>なぜ \u003Ccode>proxy_ssl_server_name on\u003C/code> が必要か\u003C/h3>\n\u003Cp>HTTPSでのupstream通信では、SNI（Server Name Indication）でホスト名を通知します。リテラル記述だと自動でSNIに載りますが、\u003Cstrong>変数経由だとSNIが載らなくなる\u003C/strong>ので、このディレクティブで明示的に有効化する必要があります。これを忘れると、共用ホスティング環境のupstreamでSSL証明書ミスマッチが発生することがあります。\u003C/p>\n\u003Ch3>\u003Ccode>resolver\u003C/code> の設定値\u003C/h3>\n\u003Cul>\n\u003Cli>\u003Ccode>8.8.8.8 1.1.1.1\u003C/code>: Google PublicDNSとCloudflareのDNSを併記。nginxの \u003Ccode>resolver\u003C/code> は複数指定時に片方をフォールバックに回すのではなく、並列で使う挙動になります\u003C/li>\n\u003Cli>\u003Ccode>valid=300s\u003C/code>: 解決結果を5分キャッシュ（TTLに近い短めの値）\u003C/li>\n\u003Cli>\u003Ccode>ipv6=off\u003C/code>: IPv6対応していないupstreamなら無駄なAAAA問い合わせを抑制\u003C/li>\n\u003Cli>\u003Ccode>resolver_timeout 5s\u003C/code>: 名前解決のタイムアウト。デフォルトの30秒は長すぎるので短縮\u003C/li>\n\u003C/ul>\n\u003Ch2>検証\u003C/h2>\n\u003Cp>設定を反映する前に \u003Ccode>nginx -t\u003C/code> で必ずチェックします。\u003C/p>\n\u003Cpre>\u003Ccode class=\"language-bash\">sudo cp /etc/nginx/sites-enabled/morinoupa.jp /etc/nginx/sites-enabled/morinoupa.jp.bak\n# ↑ 注意: sites-enabled/ にバックアップを置くとnginxが両方読み込んでconflictするので\n#        実際は /home/ubuntu/ など別の場所に退避させる\nsudo nginx -t\n# nginx: the configuration file /etc/nginx/nginx.conf syntax is ok\n# nginx: configuration file /etc/nginx/nginx.conf test is successful\n\nsudo systemctl reload nginx\n\ncurl -I https://morinoupa.jp\n# HTTP/2 200\u003C/code>\u003C/pre>\n\u003Cp>上のコメントに書いた通り、\u003Cstrong>バックアップファイルの置き場所には注意が必要\u003C/strong> です。\u003Ccode>/etc/nginx/nginx.conf\u003C/code> は通常 \u003Ccode>include /etc/nginx/sites-enabled/*;\u003C/code> で全ファイルを読み込むため、拡張子に関係なく同ディレクトリ内のファイルが読み込まれて server_name の重複警告が出ます。バックアップは別ディレクトリに置くのが安全です。\u003C/p>\n\u003Ch2>再発防止の他のアプローチ\u003C/h2>\n\u003Cp>今回入れた変数化だけでも同種の起動失敗はほぼ防げますが、二重化を考えるならいくつかの追加対策もあります。\u003C/p>\n\u003Ch3>1. systemdでの自動リトライ\u003C/h3>\n\u003Cp>nginxのsystemd unit fileに \u003Ccode>Restart=on-failure\u003C/code> + \u003Ccode>RestartSec=30\u003C/code> を入れておくと、設定テスト失敗後もリトライしてくれます。ただしこれは\u003Cstrong>設定そのものが壊れている場合に無限リトライで負荷になる\u003C/strong>リスクもあるので、回数制限 (\u003Ccode>StartLimitBurst\u003C/code>) と併用が推奨です。\u003C/p>\n\u003Ch3>2. certbot deploy-hookの見直し\u003C/h3>\n\u003Cp>certbotの更新で \u003Ccode>nginx reload\u003C/code> が走る際、失敗時の挙動を明示しておくと気付きやすくなります。hook内でreload失敗時にログ通知する、といった実装が有効。\u003C/p>\n\u003Ch3>3. 外形監視\u003C/h3>\n\u003Cp>今回の一番の反省点は、\u003Cstrong>4日気づかなかったこと\u003C/strong> 自体でした。UptimeRobot等の外形監視サービスは無料枠でも数分間隔で叩いてくれて、落ちたらメール通知してくれます。個人サイトでも導入コストは5分程度なので、本来は最初に入れておくべきです。\u003C/p>\n\u003Ch2>まとめ\u003C/h2>\n\u003Cp>振り返ってみると、以下が今回の学びです。\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>ICMPは通るがポートが閉じている\u003C/strong> というシグナルは、リバースプロキシ層のダウンを疑う典型\u003C/li>\n\u003Cli>nginxの \u003Ccode>proxy_pass\u003C/code> に外部ドメインをリテラルで書くと、\u003Cstrong>起動時のDNS解決失敗で設定テストが落ちる\u003C/strong> という落とし穴がある\u003C/li>\n\u003Cli>対策は \u003Cstrong>ドメインを変数経由に変えて、\u003Ccode>resolver\u003C/code> を明示指定\u003C/strong> する。ただし \u003Ccode>rewrite\u003C/code> と \u003Ccode>proxy_ssl_server_name on\u003C/code> の追加が必要な場面もある\u003C/li>\n\u003Cli>バックアップファイルを \u003Ccode>sites-enabled/\u003C/code> に置くとnginxが両方を読み込んでしまうので別の場所に退避させる\u003C/li>\n\u003Cli>設定の堅牢化と並行して、\u003Cstrong>外形監視を入れる\u003C/strong> のが再発防止の本丸\u003C/li>\n\u003C/ul>\n\u003Cp>構築して終わり、ではなく、落ちたときにすぐ気づける仕組みまで含めて「運用できている」と言える。当たり前のことを改めて自分に言い聞かせる回になりました。\u003C/p>\n","",[19],{"id":20,"name":21,"slug":22},44,"技術深掘り","deep-dive",[24,28,31],{"id":25,"name":26,"slug":27},91,"AI","ai",{"id":29,"name":30,"slug":30},89,"nginx",{"id":32,"name":33,"slug":34},90,"インフラ","infra","advanced","nginxの proxy_pass に外部ドメインをリテラルで書くと、起動時のDNS解決が一瞬失敗しただけで設定テストが落ち、起動不能になる。変数経由＋resolver で回避した実例と、rewrite・SNIの注意点をまとめました。","11",[],[40,60,91],{"id":41,"slug":42,"title":43,"date":44,"excerpt":45,"thumbnail":17,"categories":46,"tags":51,"difficulty":57,"tldr":58,"readingTime":59},9003,"ai-accounting-assistant","経理担当をAIに任せてみた","2026-06-16T10:00:00","個人事業で後回しにしがちな経理を、AIに「経理担当」として継続的に任せてみた記録。書類整理から仕訳の自動化まで、人間とAIの役割分担をどう設計したかを振り返ります。",[47],{"id":48,"name":49,"slug":50},42,"ワークスタイル","workstyle",[52,53],{"id":25,"name":26,"slug":27},{"id":54,"name":55,"slug":56},92,"フリーランス","freelance","beginner","散らかった経理書類の整理・突き合わせ・仕分けをAIに任せ、人間は判断に迷うものだけに集中する役割分担を作った話です。","7",{"id":61,"slug":62,"title":63,"date":64,"excerpt":65,"thumbnail":17,"categories":66,"tags":68,"difficulty":57,"tldr":89,"readingTime":90},254,"ai-markup-horizontal-expansion","AIエージェントが一番確実に活躍できるフロントエンドの仕事 — マークアップの横展開","2026-03-25T19:01:28","AIにコードを書かせる場面は増えてきました。ただ、「結局どこに使うのが一番効くの？」という問いに対して、まだ手探りの方も多いんじゃないかと思います。 自分はフリーランスのフロントエンドエンジニアとして、日常的にAIエージ [&hellip;]",[67],{"id":20,"name":21,"slug":22},[69,73,77,81,85],{"id":70,"name":71,"slug":72},78,"AI協働","ai-collaboration",{"id":74,"name":75,"slug":76},81,"Claude Code","claude-code",{"id":78,"name":79,"slug":80},84,"フロントエンド","%e3%83%95%e3%83%ad%e3%83%b3%e3%83%88%e3%82%a8%e3%83%b3%e3%83%89",{"id":82,"name":83,"slug":84},85,"マークアップ","%e3%83%9e%e3%83%bc%e3%82%af%e3%82%a2%e3%83%83%e3%83%97",{"id":86,"name":87,"slug":88},86,"実務","%e5%ae%9f%e5%8b%99","フロントエンドの実務でAIエージェントが最も確実に力を発揮するのはマークアップの横展開。レイアウトパターンごとに数ページ人間が作り、残りをAIに任せると圧倒的に速い。完璧ではないが、単純作業の負担を大幅に減らせる。","6",{"id":92,"slug":93,"title":94,"date":95,"excerpt":96,"thumbnail":17,"categories":97,"tags":99,"difficulty":114,"tldr":115,"readingTime":116},252,"wordpress%e3%83%90%e3%83%83%e3%82%af%e3%82%a8%e3%83%b3%e3%83%89%e3%82%92ai%e3%81%ab%e5%85%a8%e4%bb%bb%e3%81%9b%e3%81%97%e3%81%a6%e3%81%bf%e3%81%9f-%e6%84%9f%e6%80%a7%e3%81%8c%e8%a6%81","WordPressバックエンドをAIに全任せしてみた — 感性が要らない領域こそAI向きなのか検証する","2026-03-15T02:38:53","WordPressのバックエンド——カスタム投稿タイプの定義、REST APIの設計、管理画面のカスタマイズ。こうした作業は、仕様が明確でパターン化しやすい。 前回までの連載で「デザインやアニメーションなど、人間の感性に [&hellip;]",[98],{"id":20,"name":21,"slug":22},[100,101,102,106,110],{"id":70,"name":71,"slug":72},{"id":74,"name":75,"slug":76},{"id":103,"name":104,"slug":105},82,"PHP","php",{"id":107,"name":108,"slug":109},83,"REST API","rest-api",{"id":111,"name":112,"slug":113},31,"WordPress","wordpress","intermediate","ポートフォリオサイトのWordPressバックエンド（テーマ・REST API・管理画面）をAIに全任せで実装。定型的なバックエンド作業はAIの得意領域だが、実際に使い始めると「キー名の不一致」「運用を想定していない設計」など、細かい修正が必要になる場面があった。","8",{"slug":62,"title":63,"thumbnail":17},{"slug":42,"title":43,"thumbnail":17}]