2026年3月20日 本番アップデートノート — セキュリティ強化・構造化データ修正・DXバグ修正

目次
NOUMIN ENGINEERING TECH GUIDE

💬 くるるちゃんのワンポイント図解解説

【技術背景・解説】
この記事(2026年3月20日 本番アップデートノート — セキュリティ強化・構造化データ修正・DXバグ修正)におけるIT技術の基本概念と重要ポイントを、わかりやすく整理・解説しています。

【アイキャッチ図解のポイント】
構成要素とデータフローを視覚的に整理し、初心者でも要点を掴みやすいグラフィック構造で表示しています。

【資格・要点ノート】
シラバス用語、基本概念の理解、実務への応用ポイント

はじめに

本日2026年3月20日、kurutann.com に対して大規模なアップデートを実施しました。今回のアップデートは大きく分けて4つの領域にまたがっています。

  1. VPSセキュリティアップデートとカーネル更新
  2. Google構造化データ(JSON-LD)のバグ修正
  3. DX Office シートの操作不能バグ修正
  4. 睡眠改善アプリ「Sleep Recovery」の本番追加

この記事では、それぞれの変更内容と背景、そして再発防止策について詳しく記録します。

1. VPSセキュリティアップデート

パッケージ更新

Oracle Linux 10.1 で利用可能な10件のパッケージを更新しました。主な対象は以下の通りです。

  • containerd.io 2.2.2 — Docker コンテナランタイムの最新版
  • samba 4.22.4 — samba-client-libs, samba-common 等のネットワーク共有ライブラリ群
  • shadow-utils 4.15.0 — ユーザー管理コマンド群のセキュリティ修正
  • tzdata 2026a — タイムゾーンデータの最新版。日本時間の扱いに影響する重要な更新
  • sos 4.10.1 — 障害診断ツール

カーネル更新と再起動

カーネル(kernel-core)が事前に更新されており、適用のためにVPSの再起動を実施しました。再起動後、5つのDockerコンテナ(noujyuku-web, noujyuku-nginx, noujyuku-redis, noujyuku-pgbouncer, noujyuku-mail)はすべて restart: unless-stopped ポリシーにより自動復旧しました。IPSセンサー関連の3つのsystemdサービス(kurutann-ips, kurutann-nft-sync, kurutann-nft-ips)もすべて正常に起動しています。

SSH ブルートフォース試行の観測

再起動前後のログ確認で、複数の国外IPアドレスからSSHブルートフォース試行を確認しました。侵入されていません。

2. IPS KPI 二重控除バグの修正

症状

IPSダッシュボードで以下の矛盾した数値が表示されていました。

  • Blocked Total = 0
  • Blocked 429 = 4,000件
  • Block Rate = 0.00%

429(レート制限)によるブロックが4,000件も発生しているにもかかわらず、合計ブロック数が0という論理的にありえない状態でした。

原因: テストIP除外の二重控除

バグの根本原因は、テストIPアドレス(VPS自己監視用)のブロック数を2回差し引いていたことでした。具体的には、Redisの5分バケットをループする際に、各バケットで keep_ratio によるスケールダウンが行われ、blocked_429 等の値は既にテストIP分を除外済みの状態でした。しかしループ後に、さらに test_ip_blocked_24(テストIPの生のブロック数)を total_blocked から再度差し引いていました。

結果として、テストIPが全体の大部分を占める場合、total_blocked は常に0に張り付き、一方で blocked_429 はループ内のスケーリング結果がそのまま表示されるため、内訳と合計が乖離するという不整合が発生していました。

修正

ループ後の二重控除を削除しました。blocked_429_24 + blocked_403_24 + blocked_503_24 の合算値がそのまま total_blocked になります。ループ内のスケーリングで既にテストIP除外は完了しているため、追加の減算は不要です。

3. IPSセンサーの認証障害と復旧

missing_nonce エラー

VPS再起動後、IPSセンサー(Rustバイナリ)がDjangoサーバーへの接続で 401 Unauthorized: missing_nonce エラーを返し続けていました。連続失敗数は226回に達していました。原因は、認証設定の不整合が原因でした。サーバー側の認証要件とセンサー側の対応バージョンにずれがあり、設定の同期漏れが発生していました。

根本的なデプロイ問題の発覚

この障害をきっかけに、より深刻な問題が明らかになりました。従来のデプロイ手順が「変更したファイルだけを個別にtar転送してdocker cpで注入する」方式であったため、デプロイ漏れが頻繁に発生していたのです。今回も 設定ファイルだけでなく、プロジェクト全体が古いコードのまま運用されていました。

デプロイ手順の刷新

再発防止のため、デプロイ手順を以下のように統一しました。

  1. rsync でローカルリポジトリ全体をVPSの /opt/noujyuku-bbs/ に同期(完了を待つ)
  2. docker compose build web でDockerイメージを再構築(完了を待つ)
  3. docker compose up -d web でコンテナを切り替え
  4. 必要に応じて python manage.py migrate を実行

rsync と build は必ず順番に実行します。並行実行すると、rsync完了前の古いコードでイメージがビルドされるためです(実際に今回この問題が発生し、quiz.company モジュールが見つからないエラーでコンテナが起動不能になりました)。

4. Google 構造化データ(JSON-LD)の修正

症状

Google Search Console で「解析不能な構造化データ」「値の型が正しくありません」というエラーが報告されていました。

原因

<script type="application/ld+json"> ブロック内で JavaScript の gettext() 関数を使用していました。JSON-LD はブラウザによって純粋な JSON として解析されるため、gettext() のような関数呼び出しはリテラル文字列としてそのまま出力されます。結果として、Google のバリデーターが値の型エラーを報告していました。

修正対象

  • templates/portal/index.html — Organization, WebSite, SoftwareApplication スキーマ
  • templates/diary/day_detail.html — Article スキーマの author/publisher
  • templates/kids/paint_draw.html — WebApplication スキーマ
  • templates/illastedit/home.html — WebApplication スキーマ

すべて gettext() を直接の日本語文字列に置換しました。

再発防止

リンタースクリプト scripts/lint_jsonld.py を新規作成しました。全テンプレート(336ファイル)を走査し、JSON-LD ブロック内の gettext()、ngettext()、new Date() 等のJavaScript関数呼び出しを検出します。また、CLAUDE.md にルールとして明文化し、AI エージェントによる将来の誤挿入を防止します。

5. DX Office シートのバグ修正

症状

/dx/office/sheets/2/ で列名の保存ボタンを押しても列が追加されず、キャンセルボタンも反応しない状態でした。

原因

dx/base.html の JavaScript カタログ(i18n翻訳)が <script defer> で読み込まれていますが、ページ内のインラインスクリプトは即座に実行されます。初期化時に renderGridEditor() が呼ばれ、その中で gettext() が実行されますが、defer スクリプトはまだ読み込まれていないため ReferenceError が発生します。このエラーにより、スクリプトの実行が中断され、その後に登録されるはずだった保存ボタン・キャンセルボタンのイベントリスナーが一切登録されませんでした。

修正

dx/base.html の extra_js ブロック直前に gettext / ngettext のフォールバック関数を追加しました。JavaScript カタログが読み込まれていない場合でも、引数をそのまま返す関数が定義されるため、ReferenceError は発生しません。カタログが読み込まれた後は正規の翻訳関数で上書きされます。この修正は全19のDXテンプレートに一括で適用されます。

6. SOC/XDR ダッシュボードの認証修正

SOC・XDR の各サービスダッシュボードにアクセスすると401エラーが返される問題がありました。環境変数にサービス間の認証トークンが未設定だったことが原因です。正しい値を設定して解決しました。

7. 睡眠改善アプリ「Sleep Recovery」の追加

今回のデプロイでは、新規アプリケーションとして睡眠改善プラットフォーム「Sleep Recovery」(/sleep/)を本番環境に追加しました。

アプリの概要

Sleep Recovery は、科学的根拠に基づく睡眠改善を支援する総合プラットフォームです。認知行動療法(CBT-i)のアプローチを中心に、睡眠の記録・分析・改善をワンストップで提供します。

主な機能

  • 睡眠ログ — 就寝時刻、入眠時刻、起床時刻、中途覚醒回数、睡眠の質(5段階)、日中の眠気、昼寝、カフェイン・スマートフォンの使用状況を毎日記録します。総睡眠時間、睡眠効率(%)、入眠潜時、中途覚醒時間などの指標を自動計算し、14日間の履歴を管理します。
  • CBT-i 睡眠制限療法 — 4つのフェーズ(初期→制限→安定→拡張)で段階的に睡眠の質を改善するプログラムです。固定の起床時刻と初期睡眠ウィンドウ(5〜9時間)を設定すると、システムがパーソナライズされた就寝許可時刻を計算します。週次の自動レビューで睡眠効率に基づきウィンドウを調整します。効率85%以上なら15分拡張、80〜84%は維持、79%以下なら15分短縮というルールで運用されます。
  • 瞑想・呼吸法 — 吸う・止める・吐く・休むのサイクルを設定可能な呼吸プログラムと、タイマー付きの瞑想セッションを提供します。フェードアウト付きのバックグラウンドサウンドと組み合わせることで、リラクゼーション効果を高めます。
  • 睡眠サウンド — 入眠・瞑想・離床時に使えるオーディオプレイヤーです。フェードアウトタイマーに対応し、共有メディアプロファイルから再利用可能な音源を管理します。
  • ナイトモードテーマ — 複数のダークテーマプリセットを用意しています。呼吸オーブ、ドリフトグラデーション、星のフェード、ミストウェーブなどのアニメーションをカスタマイズ可能です。明るさはソフト・バランス・読みやすいの3段階から選べ、reduce-motion のアクセシビリティにも対応しています。
  • ダッシュボード — 7日間・30日間の睡眠指標チャートで、睡眠効率のトレンドや平均睡眠時間を視覚的に確認できます。
  • 離床プロンプト — 眠れない時に起き上がることを促す機能です。CBT-iの原則に基づき、ベッドと睡眠の結びつきを強化するためのガイダンスを提供します。

技術的な特徴

Sleep Recovery は5つのDjangoアプリ(sleep_log, sleep_meditation, sleep_sound, sleep_theme, sleep_core)で構成されています。UIは完全にダークモードで設計されており、夜間使用時の光刺激を最小限に抑えています。テーマシステムはCSSカスタムプロパティを動的に生成し、一貫したナイトカラーを実現しています。

まとめ

今回のアップデートでは、セキュリティ(OS更新とIPS修正)、SEO(構造化データ修正)、機能(DX Office修正・Sleep Recoveryの追加)、インフラ(デプロイ手順刷新)と幅広い領域を改善しました。特にデプロイ手順の統一は、今後の運用品質に大きく寄与すると考えています。個別ファイル転送による「デプロイ漏れ」という根本的な問題を、Docker イメージの再構築という手順で解消しました。

読んだ内容を10問練習と実技で確認

記事で理解した用語を、StudyQuestの演習とクラウド実技ラボで定着させます。

10問練習 実技ラボ

コメント(0件)

まだコメントはありません。最初のコメントを投稿してください!

コメントを投稿