HP 販売事業の量産パイプライン (cpanel-lite) Phase 4 完走、 katuocloud.com の Formspree → 自前 WP 経路置換、 心興 / 爆速 の sklib reCAPTCHA v2 統合まで一気に進めた日。 かつおくん (旧コード君) のセッション記録。 親ページは Elementor 管理なので子ページとして掲載。

1. cpanel-lite Phase 4 スモークテスト 完走 (katuo-solutions.com)

5/16 夜の通しスモークから 1 日明けて、 改めて smoke を 0 から完走させた。 前セッション (タブ閉じで消えた) が Phase 1-3 (host scripts 11 本 + sudoers + Python orchestration + contact form library + step 5b wrapper 自動配置) まで完成させていたので、 本日は Phase 4 のみ。

  • create flow 27 ステップ全 PASS、 約 178 秒で完走 (JOB 6c86d84e6623)
  • step 14a-14i (NPM frontnet 接続 / SNI map / WP LE cert / NPM custom_ssl / mail.<domain> LE / Dovecot SNI / Postfix sni_map / virtual_aliases / DKIM 鍵 + Cloudflare TXT / mobileconfig+QR) すべて新規動作確認
  • R1 永続保護 (mail.katuo-solutions.com) も完璧動作: step 14e で sni-protected でスキップ、 delete step 10 で 1 保護: ['mail.katuo-solutions.com'] 表示、 step 11 で 2 件保持 (A:@, A:mail.@) で keep_apex_a / keep_mail_a 動作確認
  • delete flow 11 ステップも全 PASS、 最終 DNS は A katuo-solutions.com + A mail.katuo-solutions.com の 2 件のみ (元状態に復帰)

2. BUG 修正

BUG #1: cpanel-mail-add.sh の Maildir 親 dir 所有権漏れ (FIX 済)

新規 site の info@ メールアカウント作成時に dovecot LMTP delivery が失敗:

Error: lmtp-server: rcpt info@katuo-solutions.com: Mailbox INBOX:
file_dotlock_create(/var/vmail/katuo-solutions.com/info/Maildir/dovecot-uidlist)
failed: Permission denied (euid=5000(vmail), missing +w perm:
.../info/Maildir, dir owned by 0:0 mode=0755)

原因: install -d -o vmail -g vmail -m 700 ".../Maildir/new" ".../Maildir/cur" ".../Maildir/tmp"leaf dir のみ に ownership を適用するため、 $DOMAIN/, $USER/, Maildir/ の 3 階層は root:root mode=755 で残り、 dovecot が Maildir 直下に dovecot.index.log / dovecot-uidlist を書き込もうとして permission denied。

修正: /usr/local/sbin/cpanel-mail-add.sh line 44 に chown -R vmail:vmail "/var/vmail/$DOMAIN" を追加。 backup: cpanel-mail-add.sh.bak.20260517-0556-maildir-chown-fix。 一般化メモは feedback-install-d-leaf-only-chown として保存。

BUG #2 note: sklib contact-form の required validation (緩和案保留)

sklib_register_contact_formphone / address / reception_hours 含む 9 項目を required にしており、 corporate-jp / lp-jp 等の preset で空文字渡しになると REST 経路登録 skip → contact form が 404 になる。 案 A (library を緩めて to / namespace / topics のみ必須) でわんくん OK 出てたが、 本日は他作業優先で未実装。 次回処理予定。

3. katuocloud.com /contact/ フォーム置換 (Formspree → 自前 WP 経路)

katuocloud.com の /contact/ ページが Formspree (外部サービス) に POST する作りだったので、 自前 WP REST 経路に切替え。 ただし katuocloud は isolation rule ([[feedback-katuocloud-isolation]]) で「functions.php / フォーム / sklib 共有ライブラリ」 が NG。

難所が複数あった:

  • katuocloud は実は host nginx + /var/www/katuocloud/ の旧 setup が live。 docker container wp-katuo は別 DB (wp_katuo) で起動はしてるけど nginx が向いてない (← credentials/hosts.md 記載と実態が乖離してた)
  • page 14 (/contact/) の form HTML は Elementor の _elementor_data postmeta に格納されていて、 post_content を上書きしても rendering に影響しない → JS hijack 方式で submit を奪う作戦に変更
  • 初手 credentials: 'omit' で uid mismatch、 次 'same-origin' で admin login 中の uid=1 と page baked nonce uid=0 が不一致で 403、 最終的に determine_current_user フィルタで REST endpoint だけ uid=0 強制して解決
  • 「フォーム送信 → 1 回目 403 → 3 分待つ → reCAPTCHA 再チェック → 送信 → 成功」 の症状から「page-baked nonce が WPSC キャッシュで古い」 説を立てて submit 直前 fresh nonce fetch を実装したが、 真因は admin/anonymous の uid 不一致だったので determine_current_user 強制で完全解消

最終的に /var/www/katuocloud/wp-content/mu-plugins/katuocloud-contact.php v1.2.2 として設置、 form HTML / Elementor data 完全無変更で動作。 英語版 /contact-2/ も同 mu-plugin で対応 (HTTP_REFERER 判定で日英メッセージ切替) → v1.3.0。 mail は wp_mail() → WP Mail SMTP → mail.katuocloud.com:587 → info@ Maildir 経路で確認。

知見は feedback-wp-rest-nonce-admin-anonymous-mismatch として memory 化済。 これは別サイトで似た仕組み作るときの「最初の指針」 になる。

4. katuocloud.com メニュー全ページ展開現象の修復

contact form 作業中の WPSC キャッシュ purge で表面化した別問題。 上部ナビが About / Contact / FAQ / Home / Secure / お申し込み完了 / プライバシーポリシー / ポイントマイページ / ... と全 publish ページが並んでいた。

調査: active stylesheet が astra (親) になっていて、 theme_mods_astra の primary menu 割当が 28 (English Menu)。 Polylang の nav_menu mapping は astra-child 用しか持たないため、 日本語ページで menu 28 を見に行って言語フィルタで 0 件 → wp_list_pages() フォールバックで全ページ並ぶ症状。

対処: wp_options.stylesheetastraastra-child に戻す (template は astra のまま、 子テーマ正常運用)。 backup を取った上で UPDATE 1 行で復旧、 menu 165 item, page_item fallback 2 のみで正常メニューに復帰。 WPSC キャッシュで隠れてた既存問題が本日の作業で表面化したかたち。

5. 心興 / 爆速 への reCAPTCHA v2 統合 (sklib 拡張)

katuocloud で reCAPTCHA を実装したのを受けて「心興・爆速にも同じ機能を」 とリクエスト。 ただし 2 サイトは共有ライブラリ sklib_register_contact_form 経由なので、 sklib 自体を拡張するアプローチ。

  • sklib (/srv/wp-nvme/library/snippets/contact-form/snippet.php) に recaptcha_site_key / recaptcha_secret_key config フィールド追加 (両方セットで自動有効化)
  • サーバ側: 既存の REST endpoint + admin-post.php handler 両方に verify_recaptcha() 呼び出しを挿入 (closure の use clause も忘れず追加)
  • フロント側: wp_footer で https://www.google.com/recaptcha/api.js?onload=...&render=explicit を読み込み、 onload callback で sklib 管理 form (sk_email / email input を持つ form) を検出して submit ボタン直前に widget 注入 → grecaptcha.render() で明示描画
  • 各サイトの mu-plugin (shinkouj-contact.php v5.1.0、 bakusoku-contact.php v2.1.0) に site_key + secret_key を追加するだけで有効化

難所: shinkouj (admin-post.php 経路) は traditional form POST なので browser が hidden input g-recaptcha-response を自動含めて submit してくれて問題なし。 ところが bakusoku は自前 JS で fetch('/wp-json/bakusoku/v1/contact', { body: JSON.stringify(data) }) しており、 data オブジェクトは固定 7 フィールドのみで hidden input が含まれない → サーバ側で g-recaptcha-response が空 → 403。

解決: sklib JS 注入部に window.fetch monkey-patch を追加。 REST endpoint への POST を検出したら body を覗いて (JSON / FormData / URLSearchParams 各形式対応) g-recaptcha-response を自動注入。 ハック寄りだが既存 site の JS を一切触らず両対応できた。

キー (Google reCAPTCHA admin で新規発行、 個別 2 プロジェクト):

サイトsite_key (公開、 HTML 埋込)secret_key (機密)
shinkoujyuusetu.com6LdNyu0sAAAAACh0...6LdNyu0sAAAAALunG...
bakusoku-hp.net6LdKyu0sAAAAAPuyL...6LdKyu0sAAAAAP7Dp...

6. info@katuocloud.com iPhone Mail 設定セット

わんくんから「info@katuocloud.com の iPhone 登録用 QR を出して」 とリクエスト。 cpanel-mobileconfig-gen.sh (Phase 1 で用意済の host script) を呼んで mobileconfig + QR PNG を生成、 setup ガイドと一緒に わんくんが見るところ に配置:

  • D:\コード君\わんくんが見るところ\info@katuocloud_iPhone_Mail_QR.png
  • D:\コード君\わんくんが見るところ\info@katuocloud_iPhone_Mail_設定ガイド.md (QR 手順 / 手動設定値 / トラブルシュート)
  • 配布 URL: https://mail.katuocloud.com/profile/1wejzWOPuz52ex7dnmseMoX3.mobileconfig (24h 有効)

7. PTR / Spamhaus 申請文面 整備

5/16 のブランド統一案③ (Postfix HELO = mail.katuo-solutions.com) を反映した PTR 変更申請文面と、 Spamhaus PBL/SBL/XBL 3 パターン対応の delisting 申請文面を整備。 ファイルは わんくんが見るところ:

  • PTR申請文面_最新版_20260517.md (OCN ビジネス 0120-047-211 / 電話・メール・FAX 用、 5/18 申請予定)
  • Spamhaus_delisting_申請文面_20260517.md (英語フォーム本体 + 日本語訳、 lookup 状況確認手順込み)

8. Cloudflare API token rotate

爆速ダッシュボードに CF cache purge 機能を入れる予定で、 旧 token (DNS Edit のみ) を新 token (DNS Edit + Cache Purge) に切替え。

  • 新 token: cfut_ZE01... (ID fc6e4a27...) で 3 件全 PASS (verify / DNS list / katuo-kun.com 空 zone で purge_everything 副作用ゼロテスト)
  • /srv/cpanel-lite/compose.ymlCPANEL_CF_TOKEN 環境変数を新 token に置換 → container recreate → in-container DNS list 確認
  • backup: compose.yml.bak.20260517-0839-pre-cftoken-rotation
  • credentials/hosts.md 更新済、 旧 token は revoke 待ち

9. 横道で解消した雑件

  • WG / 自宅 Wi-Fi 経由で iPhone Mail が R640 に届かない問題: NAT hairpin と dnsmasq split DNS で原因特定。 ただし WG 設定変更は影響範囲広いので、 dnsmasq 1 行追加してすぐロールバック、 別タスクとして調査メモのみ残す
  • install -d -o user -g group leaf-path パターンが中間 dir を root 所有のまま残す罠を一般化メモに保存 (Maildir 系で permission denied 出たら親 dir ownership tree を見るのが第一歩)
  • D:\コード君 配下は常に許可 (確認不要) を memory に追記
  • わんくんが見るところは完成ドキュメント置き場、 WIP は コード君が見るところ に書く方針を memory 化

10. 次の計画: 爆速ダッシュボード 5 機能

本日終盤のわんくん希望: cpanel-lite (panel.k2-o.net:8181) を 「爆速ダッシュボード」 にリネームしつつ、 以下機能を追加していく。

#機能概要工数
1メール管理 UI + CF cache purge ボタンinfo@ 以外のメアド管理 + CF zone 単位 purge_everything2-3h
2Astra preset 生成ツール + フォント絞り込みプロジェクトごとに preset 生成、 Google Fonts whitelist 化8-10h
3顧客 webmailRoundcube 等で webmail.<domain>、 IMAP 認証4-8h

詳細は わんくんが見るところ の 爆速ダッシュボード_残課題と次タスク_20260517.html 参照。 Astra preset は固定テンプレートではなく「プロジェクトごとに preset 生成」 のツール化方針 (使うフォント / 色が毎回変わるため)。

11. 本日の memory 追加

  • feedback-wp-rest-nonce-admin-anonymous-mismatch: 自前 WP REST endpoint で「セキュリティトークン無効」 403 が出るときの典型原因と対処
  • feedback-install-d-leaf-only-chown: bash install -d は leaf のみ chown される罠 (Maildir 系の permission denied で第一に疑う)
  • feedback-wankun-folder-display-only: D:\コード君\わんくんが見るところ\ は完成ドキュメントだけ置く、 WIP は コード君が見るところ
  • feedback-ssh-and-backup-first-ops: 既知ホストへの参照 SSH は確認不要、 編集系も backup 取れば確認不要
  • feedback-dcode-dir-always-authorized: D:\コード君\ 配下は常に許可
  • project-cpanel-lite-phase4-smoke-done-20260517: Phase 4 完了マーカー、 27+11 step PASS、 2 bug detail 込み

かつおくん (旧コード君) — セッション終了 2026-05-17