投稿者: manualmaton Page 1 of 278

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. 各種機能(ページ閲覧や編集)などが正常に行えるかを確認します。

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

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

Linuxサーバ、稼働中のサービスのバージョンを確認するワンライナー。

概要

Linuxサーバの構築時に非常に面倒で厄介な「動いているサービス(systemctl status hoge.service でenabledになっているもの)だけを取り出し、表に転記するという作業が

  • 限りなく単調で
  • とてもミスが多い

重箱の隅をつつくような作業を一発で解消するワンライナーの紹介です。

前提

RHEL系Linuxで動きます。(筆者環境Rocky Linux)

ワンライナー

※これは

sudo su 

としてから入力した方が無難です。(パッケージによっては一般的権限では見られないため)

 { echo -e "| ソフトウェア名 | バージョン |\n| --- | --- |"; systemctl list-unit-files --type=service --no-legend | awk '{print $1}' | grep -v '@\.service$' | xargs -r systemctl show -p FragmentPath | sed 's/^FragmentPath=//' | grep '^/' | sort -u | xargs -I {} sh -c 'if rpm -qf "{}" >/dev/null 2>&1; then rpm -qf "{}" --qf "| %{NAME} | %{VERSION}-%{RELEASE} |\n"; else echo "| $(basename "{}") | (not owned by any package) |"; fi' | sort -u; } 

スクリプトの解説

このコマンドは大きく分けて「ヘッダーの出力」「サービスファイルのパス特定」「パッケージ情報の取得と整形」の3つのフェーズで動いています。

1. 表のヘッダーを作成

  • { echo -e "| ソフトウェア名 | バージョン |\n| --- | --- |"; ... }
    • 最初にMarkdown形式の表の1行目(項目名)と2行目(区切り線)を出力します。
    • 全体を { } で囲むことで、ヘッダーと後の実行結果を一つの出力ストリームとしてまとめています。

2. サービス一覧からファイルパスを特定

ここからがメインのパイプラインです。

  • systemctl list-unit-files --type=service --no-legend
    • システム上の全サービスユニットを表示します。--no-legend でヘッダー行を省きます。
  • awk '{print $1}'
    • 出力結果から1列目(サービス名)だけを抜き出します(例: sshd.service)。
  • grep -v '@\.service$'
    • インスタンス化されたユニット(user@.service など)を除外します。これらは実ファイルが少し特殊なためです。
  • xargs -r systemctl show -p FragmentPath
    • 各サービスに対して、その定義ファイル(ユニットファイル)がディスク上のどこにあるか(FragmentPath)を取得します。
  • sed 's/^FragmentPath=//'
    • 出力に含まれる FragmentPath= という文字列を削除し、純粋なパス名だけにします。
  • grep '^/'
    • 空行や無効なパスを除外し、/ から始まる絶対パスのみを残します。
  • sort -u
    • 重複したパスを削除します。

3. RPMによるパッケージ照会と整形

特定されたファイルパスを一つずつ RPM データベースと照合します。

  • xargs -I {} sh -c '...'
    • 各パス({})に対して、シェルスクリプトを実行します。
  • if rpm -qf "{}" >/dev/null 2>&1; then ...
    • そのファイルが RPM パッケージによって管理されているかを判定します。
    • 管理されている場合: rpm -qf を使い、パッケージ名とバージョンを Markdown の行形式 | 名前 | バージョン | で出力します。
    • 管理されていない場合: (手動で作成したサービスなど)「(not owned by any package)」と出力します。
  • sort -u(最後)
    • 最終的なリストをソートし、重複を排除して綺麗に並べます。

実行結果のイメージ

コマンドを実行すると、以下のような結果が得られます。

ソフトウェア名バージョン
chrony4.1-3.el9
openssh-server8.7p1-10.el9
my-custom-script.service(not owned by any package)
systemd250-6.el9

このワンライナーの利点

  • 徹底した合理性。
    • なにせ「目視確認」という手段が排除されます。一切のヒューマンエラーがなくなります。
  • 一覧性と整合性。
    • 「最新の情報を全て表示せよ」という要求に対してもコマンドを叩くだけで済みます。
  • 再利用性
    • これが一番大きいです。2020年代ITで最も使いやすいMarkdownのテーブル形式。そのため、
      • Redmine
      • VS Code
      • Notion
        などにいくらでも反映可能。そして、一度テーブルにしてしまえばExcelへの転記も一発です。

まとめ

「ウサギとカメの寓話」は、コツコツやる者が強いパターンではありますが、「60分の道を頑張って55分に縮めるよりも、30分かけて『1分で終わる手段を考える』」方が、本当の「タイムパフォーマンス」だと思った次第です。

備考

Ubuntuサーバでも、このようにすれば動きます。

{
  echo -e "| ソフトウェア名 | バージョン |\n| --- | --- |"
  # 1. サービスファイルのパス一覧を取得
  systemctl list-unit-files --type=service --no-legend | \
  awk '{print $1}' | \
  grep -v '@\.service$' | \
  xargs -r systemctl show -p FragmentPath | \
  sed 's/^FragmentPath=//' | \
  grep '^/' | \
  sort -u | \
  # 2. 1行ずつ読み込んで処理(whileループでシェル起動を最小化)
  while read -r path; do
    # dpkg-query -S は dpkg -S より高速で安定しています
    res=$(dpkg-query -S "$path" 2>/dev/null)
    if [ $? -eq 0 ]; then
      pkg=$(echo "$res" | cut -d: -f1)
      # 複数のパッケージがヒットする場合があるため、最初の1つを取得して詳細表示
      dpkg-query -W -f="| \${Package} | \${Version} |\n" "${pkg%%,*}"
    else
      echo "| $(basename "$path") | (not owned by any package) |"
    fi
  done | sort -u
}

2025年12月の差しボド記録。

今回は軽めのボードゲーム。

ひらがじゃん

やはりこれは面白い。単語の使い道や語彙力が囚われます。

また、新たなゲームとしてロストシティタイルゲーム」を実施。

初戦、敗北。2ゲーム目は勝利。三戦目、マイナスが発生しての敗北。

二戦のゲームではありましたが、三戦目に自分がマイナス点を取っての敗北という。言いゲームである以上に、友人との近況報告で盛り上がりました。。

mermaid.jsによる料理の手順。

以前も作った天かす入りのポテトサラダ。

今回、新たにツナも足しました。いい出来だったのでメモを残します。

材料

  • ジャガイモ4個
  • ツナ缶1個
  • 長ネギ、白いところ1本分
  • カニカマ
  • 天かす
  • マヨネーズ
  • 塩こしょう

使った器具

  • レンジ対応の耐熱ガラスボウル
  • ジャガイモピーラー
  • しゃもじ
  • 包丁 / まな板
  • 木のへら / 芋潰し

手順

ジャガイモの下ごしらえをします

  1. ジャガイモは皮をむき、新芽を取ります
  2. 二つ切りにして薄いくし切りにします
  3. 切ったジャガイモは耐熱ガラスボウルに入れてラップをかけ、9分ほどレンジに入れます。

待っている間に準備をします

  1. ネギをみじん切りにしておきます
  2. 各種材料を用意しておきます

混ぜていきます

ジャガイモにじゅうぶん火が通ったら調理開始。

ここからは「粗熱を取る必要はありません」。混ぜるさなかで冷えていくからです。
また、耐熱ガラスボウルに入れることで、他の器に入れることなくダイレクトに混ぜあわせが可能です。

  1. みじん切りしたネギを入れ、潰していきます。
  2. あらかた潰し終えたら、ツナ缶(油ごと)とマヨネーズを入れます。
  3. マヨネーズとツナを更に潰しながら混ぜ合わせます。
  4. 色が馴染んできたらカニカマを入れて混ぜ合わせます。
  5. 天かすを入れて混ぜ合わせます。
  6. 最後に味を調えます。

mermaid.jsによる手順

今回の流れはこちら。

sequenceDiagram autonumber participant 料理人 participant ボウル participant レンジ rect rgb(240, 240, 240) Note over 料理人, ボウル: 下ごしらえ 料理人->>料理人: 芋の皮むき・芽取り・カット 料理人->>ボウル: 芋を入れラップをする end par 加熱と準備 ボウル->>レンジ: 加熱(9分) and 料理人->>料理人: ネギをみじん切りにする 料理人->>料理人: 他の材料を準備する end レンジ-->>ボウル: 加熱完了 rect rgb(255, 245, 230) Note over 料理人, ボウル: 仕上げ(ボウル内で直接調理) 料理人->>ボウル: ネギを加え、芋を潰す 料理人->>ボウル: ツナ(油ごと)・マヨを入れ混ぜる 料理人->>ボウル: カニカマを入れ混ぜる 料理人->>ボウル: 天かすを入れ混ぜる 料理人->>ボウル: 塩こしょうで味を調える end

こういうちょっとした手順確認でも使えるので便利です

一人鍋セット。

最近のお一人様需要の恩恵に与りました。

近所のスーパーで売られていて、思わず手に取った鍋セット。

  • 具材(豆腐含む)
  • 調味料

がアルミ鍋とセットになっていて、

  1. 豆腐と鍋のもとをパックから取り出す
  2. 水を規定量入れる
  3. 豆腐と鍋の素を入れる
  4. 火にかける

火が通ったらできあがり。

できあがりはこちらです。

そもそも鍋は

  • 見た目以上にカロリーが低い
  • 油を使わない(場合が大概)
  • 野菜とタンパク質が豊富。
  • 何よりからだが暖まる

と、冬にうってつけの料理です。これを美味しく戴き

締めの雑炊もしっかり戴きました。

これの注意点は:アルミ鍋は耐久性がないため、二度目の加熱には向いていません。この時は別の鍋を使います

朝は朝で、

別に買っていたかき鍋を味噌汁代わりにした次第です。

Page 1 of 278

Powered by WordPress & Theme by Anders Norén