カテゴリー: ガジェット Page 1 of 93

Growi v7.1.x・v.7.2.x→v7.3.0へのアップデート

概要

Growi 7.1/7.2からv7.3.0Growiアップグレードの手順です。
Elasticsearchの全文検索を利用している方は「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 【バージョン】

リリースタグは再確認しましょう。

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

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

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

Growi v7.3.0へのバージョンアップに伴う全文検索負荷への対応。(Elasticsearchのバージョンアップ)

Growi をv7.2.10→v7.3.0へとアップグレード後、全文検索ができなくなったので、その対処方法をメモに残します。

環境

  • Growi v7.3.0
    • systemdによってサービス化
  • ElasticSearch v8.19.3
  • Ubuntu 24.04
  • MongoDB v6.0.26
  • node v20.19.2
  • Apache 2.4によるリバースプロキシ

エラー内容

Growiの管理>全文検索管理で以下のエラーが出ました。

Accept version must be either version 8 or 7, but found 9

エラーの原因

Growi v7.3.0のリリースノートで確認したところ、このバージョンからElasticsearch v9がサポート(必須化)されたことが判明しました。

support: Elasticsearch v9 (#10127)

  • Growi(クライアント側): v9形式でリクエストを送信
  • 既存環境(サーバー側): v8.19.3であったため、v9形式のリクエストを拒否

このバージョンの不一致が原因で、検索機能が停止していたと判明。対処を行います。

エラーを解決した手段

Elasticsearchをv9.1.3にバージョンアップしたことで解決しました。

手段によるサーバへの影響

「Elasticsearchバージョンアップ」です。他にこれを使うアプリが同一サーバ上にある場合、その影響を十分に確認ください。

対処方法のさっくりとした手順

  1. Elasticsearch/Growiを停止します。
  2. Elasticsearchのデータディレクトリのバックアップを行います。
  3. Elasticsearchのリポジトリをv9に併せます。
  4. Elasticsearchのバージョンアップを行います。
  5. Elasticsearchのプラグインのアンインストール/インストールを行います。
  6. Elasticsearch/Growiを起動します。
  7. エラーの解消を確認します。

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

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. インデックスの再構築を実行し、エラーが発生せず、正常に完了することを確認します。

その後、Growi上でキーワード検索を行い、検索結果が正しく表示されることを確認しました。

不審なアクセスの解析スクリプト、運用終了。 

  • Apacheのアクセスログから不審なエラーを選び
  • アクセス元を調べ
  • ログに出力する

というスクリプト。新サーバでも使っていましたが、終了の運びとなりました。

スクリプト内容

#!/bin/bash

# 変数定義
LOG_DIR="/var/log/bookstack"
ERROR_LOG="$LOG_DIR/bs_error.log"
COUNTRY_LIST="//home/hoge/script/config/country_list.csv"
OUTPUT_DIR="/home/hoge/script/log/blocked_list"
DATE=$(date +%Y%m%d)
LIST_FILE="$OUTPUT_DIR/ip.$DATE.csv"
RESULT_FILE="$OUTPUT_DIR/ip_list.$DATE.csv"
CRON_MODE=true  # cron処理の場合はtrue、標準出力に残す場合はfalse

cd $LOG_DIR

# error.logからIPアドレスだけを抜き出します
awk 'match($0,/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/) { print  substr($0, RSTART, RLENGTH) }' $ERROR_LOG | sort > $LIST_FILE

# ip.YYYYMMDD.csvファイルがない場合にエラーを返します
if [ ! -f $LIST_FILE ]; then
echo "ファイル $LIST_FILE が存在しないので終了します。"
exit 1
fi

# 国コード,国の名前が書かれたcountry_list.csvがない場合にエラーを返します
if [ ! -f $COUNTRY_LIST ]; then
echo "ファイル $COUNTRY_LIST が存在しないので終了します。"
exit 1
fi

# IPアドレスに国名を付与したファイルを定義します。(ip_list.YYYYMMDD.csv)
> $RESULT_FILE

while read -r line; do
# IPアドレスを逆順に並び替えます。(例: 1.2.3.4 → 4.3.2.1)
ip_revers=$(echo "$line" | awk -F'.' '{print $4"."$3"."$2"."$1}')
# 並び替えたIPアドレスをcc.wariate.jpに並び替えて、国コードを抜き出します。(JP,CH,ESなど)
country_code=$(nslookup -type=TXT ${ip_revers}.cc.wariate.jp | grep '"' | awk -F'"' '{print $2}')
# 国コードをcountry_list.csvから参照して国名を抜き出します。
country_name=$(grep "$country_code" $COUNTRY_LIST | cut -d"," -f2)

# 標準出力に返す処理を行います。cron処理する場合はコメントアウトします。
if [ "$CRON_MODE" = false ]; then
echo "${line},${country_name}"
fi

# IPアドレス,国名の形式にして同ディレクトリのip_list.YYYYMMDD.csvに保存します
echo "${line},${country_name}" >> $RESULT_FILE
sleep 1
done < $LIST_FILE

# ip_list.csv.YYYYMMDDを読み込んで、IPアドレスをキー、国を値とする連想配列を作成します
declare -A countries
while read -r line; do
# CSVの1列目をIPアドレス、2列目を国とします
ip=$(echo $line | cut -d',' -f1)
country=$(echo $line | cut -d',' -f2)
# 連想配列に格納します
countries[$ip]=$country
done < $RESULT_FILE

# 結果を格納するための変数を定義します
result=""

# 連想配列を反復処理します
for ip in "${!countries[@]}"; do
# 各IPアドレスの件数を数えます
count=$(grep -c $ip $RESULT_FILE)
# 件数、IPアドレス、国をカンマ区切りで結合します
line="$count,$ip,${countries[$ip]}"
# 結果に追加します
result="$result\n$line"
done

# カウントした結果をcounted_ip.YYYYMMDD.csvに出力します
COUNTED_FILE="$OUTPUT_DIR/counted_ip.$DATE.csv"
echo -e $result > $COUNTED_FILE

# 最終結果をsorted_ip.$DATE.csvに出力します
SORTED_FILE="$OUTPUT_DIR/sorted_ip.$DATE.csv"
cat $COUNTED_FILE | LC_ALL=C sort -n -r > $SORTED_FILE

# 最終結果以外のログファイルを削除します
rm $LIST_FILE
rm $RESULT_FILE
rm $COUNTED_FILE

exit 0

このスクリプト、最初、それこそ日に10件もあればいい時代の頃に作ったモノで、Cron処理を行っていました。

しかし、アクセス数が(特にクローラーで)圧倒的になった今、このスクリプトは

  • for / whileの多様
  • 逐次nslookup
  • さらに連想配列による処理 

が重なり、ただのスワップ喰い虫となっていたのです。

  • 今は別手段により不審なアクセスを弾いていること
  • サーバの容量節約

のため、こちらは停止の運び。

2年以上にわたってよくぞここまで運用してくれたという感じです。

Growiのリポジトリ変更に伴う対応。

Growiのリポジトリが

https://github.com/weseek/growi

から

https://github.com/growilabs/growi

に移行したというTwitter(現X)の投稿がありました。今後のサポートなどを踏まえ、今利用しているGrowiのリポジトリの大本を変えます。

環境

  • Ubuntu 24.04
  • Growi v7.2.10
    • Growiの実行ユーザはroot

さっくりとした手順

  1. 現在のリポジトリを確認します。
  2. リポジトリのURLをgitコマンドで変更します。
  3. リポジトリの変更を確認します。

Growiのディレクトリに移動

cd /path/to/growi && pwd

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

gitの参照リポジトリを確認

  • gitコマンドによる確認
sudo  git remote -v
  • 参照結果
origin  https://github.com/weseek/growi (fetch)
origin  https://github.com/weseek/growi (push)

上記を確認。

gitコマンドによるリポジトリ変更

  • リポジトリ変更
sudo git remote set-url origin https://github.com/growilabs/growi.git

gitの参照リポジトリの変更確認

  • gitコマンドによる確認
sudo  git remote -v
  • 参照結果
origin  https://github.com/growilabs/growi.git (fetch)
origin  https://github.com/growilabs/growi.git (push)
  • 最新の履歴確認
sudo git fetch origin
  • ローカルとリモートの差分確認
sudo git status

Your branch is behind 'origin/main' by X commits...
(あなたのブランチは、リモートよりX個のコミット分遅れています)
のように表示されれば、新しいgrowilabsリポジトリへの接続は成功しており、そこに新しい更新が存在することを確認できます。

なお、筆者は別環境で「リポジトリ変更後、新しいバージョン(v7.2.9→v7.2.10)へのバージョンアップを、新しいリポジトリを介して行えたことを補足しておきます。

Growiでテンプレートを作る。(サーバ直接編集)

VPSをXServerに変えたことによる極めて大きな収穫は「安定してGrowiが稼働すること」です。

それを更に便利に使うため、日々のテンプレートを作成しました。

ビルトインのテンプレートではなく、下部のエディタメニューから挿入できるようにしています。

環境

  • Ubuntu 24.04
  • Growi 27.1.0
    • アプリ実行権限はroot
  • Apache2.4によるリバースプロキシ
  • その他必要な環境(MongoDB、Node等)

さっくりとした手順

  1. テンプレートが格納されているディレクトリに移動します。
  2. 備わっているテンプレートをコピーし、それをひな形として新たなテンプレートを作成します。

ディレクトリ移動

  • Growiルートディレクトリに移動
cd /path/to/growi/directory && pwd

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

  • テンプレート格納ディレクトリに移動
cd packages/preset-templates/dist && pwd
  • ファイルの内容確認
ls -l

以下のようなディレクトリが表示されます。

drwxr-xr-x 8 root root 4096  9月  9 13:11 ./
drwxr-xr-x 5 root root 4096  8月  4 14:48 ../
drwxr-xr-x 5 root root 4096  8月  4 14:46 daily-report/
drwxr-xr-x 5 root root 4096  8月  4 14:46 displaying-child-pages/
drwxr-xr-x 5 root root 4096  8月  4 14:46 marp-example/
drwxr-xr-x 5 root root 4096  8月  4 14:46 minutes/
drwxr-xr-x 5 root root 4096  8月  4 14:46 project-proposal/

ディレクトリ一式のコピー

  • 日報テンプレートをコピー(一番使いやすいため)
sudo cp -pir daily-report my_template

名前は自分の環境などに合わせます。

  • コピーしたテンプレートのディレクトリに移動
cd my_template/ja_JP
  • ファイルの内容確認
ls -l

以下の2ファイルがあります。これを編集していきます。

meta.json
template.md

テンプレートの編集

以下の2つのファイルを編集します。

  • meta.json
{
  "title": "日報(ここをテンプレートタイトルとして編集)"
}
  • template.md
# {{yyyy}}/{{MM}}/{{dd}} 日報

## 今日の目標
- 目標1
    - 〇〇の完了
- 目標2
    - 〇〇を〇件達成


## 内容
- 10:00 ~ 10:20 今日のタスク確認
- 10:20 ~ 11:00 全体会議

ここを自分の運用に合わせて修正していきます。このとき、{{yyyy}}/{{MM}}/{{dd}}をそのまま残しておくと、日付がそのまま自動挿入されます。 (2025/09/11等)

内容確認

任意のWiki編集ページを開きます。

エディタメニューの下部のテンプレートの選択をクリックし、

  • 冒頭の画像で示したテンプレートが選ぶことができる
  • それをWikiページに挿入できる

の2つが確認できれば設定完了です。

Ubuntu24.04にPiwigoインストール。(PHP-FPM対応版)

概要

画像管理に特化したオープンソースのフォトギャラリー「Piwigo」。Ubuntu24.04での構築メモです。

前提/環境

  • Ubuntu 24.04の基本的な設定が完了している。
  • Apache, MySQL, PHP-FPMがインストール済みである。
    • PHP及びPHP-FPMは8.3
    • Apacheの実行ユーザはwww-data
  • Piwigoを公開するドメイン名と、対応するSSL証明書が用意されている。

さっくりとした手順

  1. データベースの作成: Piwigoが使用するMySQLデータベースとユーザーを作成します。
  2. PHP拡張機能の確認: Piwigoの動作に必要なPHP拡張機能がインストールされているか確認します。
  3. Piwigoの配置: プログラム本体をサーバーに配置します。
  4. Apacheの設定: ApacheがPiwigoを正しく表示できるように設定します。
  5. Webインストーラーの実行: ブラウザから初期設定を完了させます。

データベースの作成

  • MySQLログイン
sudo mysql -u root -p
  • DB作成
CREATE DATABASE piwigo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
  • ユーザー作成と権限付与(【】内は強固なパスワードに置き換えてください)
CREATE USER 'piwigo'@'localhost' IDENTIFIED BY '【YOUR_STRONG_PASSWORD】';
GRANT ALL PRIVILEGES ON piwigo.* TO 'piwigo'@'localhost';
FLUSH PRIVILEGES;
EXIT;
  • DB作成確認
mysql -u piwigo -p

先ほど作成したDBユーザです。

SHOW DATABASES;

作成したDBが表示されることを確認します。

EXIT

確認後、MySQLコンソールから抜けます。

PHP拡張機能の確認・インストール

Piwigoは、画像の処理のためにgdimagemagickといったPHPの拡張機能を必要とします。
これらがインストールされているか確認します。(ない場合は以下の手順でインストール)

  • 既存のPHP拡張機能で不足しているものをインストールする例
sudo aptitude install php8.3-gd php8.3-imagick php8.3-mysql

筆者の好みに合わせてaptitudeを用いています。必要に応じてaptに読み替えます。

Piwigoの配置

  • Web公開用ディレクトリに移動
cd /var/www/html && pwd

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

  • git cloneによる配置
sudo -u www-data git clone https://github.com/Piwigo/Piwigo.git piwigo

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

Apacheの設定

  • ログディレクトリの作成
sudo mkdir -p /var/log/piwigo

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

  • ディレクトリの権限変更
sudo chown -R www-data:www-data /var/log/piwigo

Piwigo用のApache設定ファイル(例: /etc/apache2/sites-available/piwigo.conf)を以下の内容で作成します。

<VirtualHost *:80>
    # ドメイン名を指定します
    servername photo.example.com
    # HTTPアクセスを強制的にHTTPSにリダイレクトします
    RewriteEngine On
        RewriteCond %{HTTPS} off
        RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerName photo.example.com
    # アクセスログ
    CustomLog /var/log/piwigo/piwigo_access.log combined
    # エラーログ
    ErrorLog /var/log/piwigo/piwigo_error.log

    # PHP-FPMと連携するための設定
    <FilesMatch \.php$>
        SetHandler "proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost/"
    </FilesMatch>
    DocumentRoot /home/www-data/piwigo
    <Directory /home/www-data/piwigo>
        AllowOverride All
        Require all granted
    </Directory>

    #SSL設定
      SSLEngine on
    Protocols h2 http/1.1

    # 推奨されるSSL/TLS設定 (Mozilla Intermediate Compatibility)
    SSLProtocol             all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite          ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384
    SSLHonorCipherOrder     on
    SSLCompression          off
    SSLSessionTickets       off # PFSを強化する場合

    # SSL証明書を指定します
    SSLCertificateFile 【SSL証明書のパスを絶対パスで指定】
    # 秘密鍵を指定します
    SSLCertificateKeyFile 【SSL証明書に対応した秘密鍵のパスを絶対パスで指定】

    #セキュリティヘッダー付与
        Header always set Strict-Transport-Security "max-age=63072000"
        Header always set X-Content-Type-Options "nosniff"
        Header always set X-Frame-Options "SAMEORIGIN"
        Header always set X-XSS-Protection "1; mode=block"
</VirtualHost>
  • 設定ファイルの有効化
sudo a2ensite piwigo.conf
  • 設定ファイルの整合性確認
sudo apache2ctl configtest

Syntax OKを確認します。

  • apacheリスタート
sudo systemctl restart apache2.service
  • apacheリスタート確認
systemctl status apache2.service

active(running)を確認します。

Webインストーラーの実行

  1. ブラウザで、設定したドメイン(https://【photo.example.com】)にアクセスします。
  2. Piwigoの初期設定ウィザードが表示されます。
  3. 画面の指示に従い、データベース情報(ステップ1で作成したもの)や、管理者アカウントの情報を入力します。

インストーラーが完了すれば、Piwigoのフォトギャラリーが利用可能になります。

“布教用”ThinkPad。

カウントダウンとなったWindows10のEOL。それに備えて、知り合いより「何かいい出物のPCがないか」という依頼があり探してきました。

Thinkpad X390。2019年ほどのモデルでありますがヘビーな使用感はなく、スペックも

  • Core i5-8365U
  • 16GB Memory
  • 256GB SSD
  • Win 11Pro

と必要十分。これでいて3万円でおつりが来るスペックというのはそうそう見つかるものではありません。

先行して用いているPCは

  • Core i7
  • 16GB Memory
  • 500GB SSD
  • Win 11 Home

と若干のスペックアップ。何よりも指紋認証付きであるため、こちらはそのまま自分が使います。

手帳の彩り。(百均グッズによるシール整理)

百均で売られているこの手のシール。もう少し使いやすくしようと思います。

商品を手に持ったとき、「これはL判ジャストサイズ」という直感があったので、これらのシールとともにフォトアルバムも購入。

もくろみ通り、しっかりとアルバム内に収まりました。

視認性も高いため、このまま使っても大丈夫です。

そして、一ひねりです。ほぼ日手帳別売品、カバーにそのままつけられるフォトアルバムを利用しましたら、まさにジャストサイズ。

こうして、手帳の彩りを豊かにするシール群が見た目も収納性も確保した上で持ち歩けるようになりました。

実行中のプロセスのメモリ量を昇順で表示するワンライナー。

概要

LinuxでWebサーバを運用していく中で気になるメモリの使用量。

「どのプロセスが一番メモリを消費しているのか?」

を調査してみます。

ワンライナーの設定

通例、メモリの使用量を見るのは

ps aux

とするのですが、

  • 全ての情報が見えてしまうので探しにくい
  • 単位が分からない

等の問題が発生します。そこで、

現在利用中のプロセスから、一番メモリを使用しているサービスを昇順で5つ抜き出し、そのメモリ量を見やすい形で成形するワンライナー

を生成AIにて作ってもらいます。(Gemini 2.5 Proを利用)

物理メモリ使用量(RSS: Resident Set Size)を基準にして、MB単位で表示するワンライナー

ps aux | tail -n +2 | sort -k 6 -rn | head -n 5 | sort -k 6 -n | awk '{cmd=""; for(i=11;i<=NF;i++){cmd=cmd" "$i}; printf "%10.2f MB   %s\n", $6/1024, cmd}'

コマンドの解説

ps aux
  • 現在実行中の全ユーザーのプロセスを詳細な情報付きで表示します。
tail -n +2
  • ps コマンドが出力する結果の1行目(ヘッダー行)を除外し、2行目以降のプロセス情報のみを次のコマンドに渡します。
sort -k 6 -rn
  • 6列目にある RSS(物理メモリ使用量) を基準に、数値を大きい順(降順)に並べ替えます。
  • -k 6: 6列目をソートキーに指定します。
  • -r: 逆順(降順)でソートします。
  • -n: 文字列ではなく数値としてソートします。
head -n 5
  • 降順にソートされた結果から、上位5つのプロセス(最もメモリを使用している5つ)を抽出します。
sort -k 6 -n
  • 抽出された5つのプロセスを、再度6列目のRSSを基準に、今度は小さい順(昇順)に並べ替えます。
awk '{ ... }'
  • 最終的な出力を見やすい形式に整形します。
  • cmd=""; for(i=11;i<=NF;i++){cmd=cmd" "$i}: 11列目以降の文字列をすべて連結し、スペースを含む完全なコマンド名を変数 cmd に格納します。
  • printf "%10.2f MB %s\n", $6/1024, cmd}: 6列目のRSS(KB単位)を1024で割ってMB単位に変換し、小数点以下2桁までの浮動小数点数としてフォーマットします。メモリ量を右寄せ10桁で表示した後、コマンド名を表示します。

表示例

ps aux | tail -n +2 | sort -k 6 -rn | head -n 5 | sort -k 6 -n | awk '{cmd=""; for(i=11;i<=NF;i++){cmd=cmd" "$i}; printf "%10.2f MB   %s\n", $6/1024, cmd}'
    236.36 MB    node -r dotenv-flow/config dist/server/app.js
    288.86 MB    Passenger RubyApp: /home/www-data/redmine1 (production)
    379.55 MB    Passenger RubyApp: /home/www-data/redmine2 (production)
    543.54 MB    /usr/sbin/mysqld
    654.73 MB    /usr/share/elasticsearch/jdk/bin/java -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j2.formatMsgNoLookups=true -Djava.locale.providers=CLDR -Dorg.apache.lucene.vectorization.upperJavaFeatureVersion=24 -Des.distribution.type=deb -Des.java.type=bundled JDK --enable-native-access=org.elasticsearch.nativeaccess,org.apache.lucene.core --enable-native-access=ALL-UNNAMED --illegal-native-access=deny -XX:ReplayDataFile=/var/log/elasticsearch/replay_pid%p.log -Des.entitlements.enabled=true -XX:+EnableDynamicAgentLoading -Djdk.attach.allowAttachSelf=true --patch-module=java.base=lib/entitlement-bridge/elasticsearch-entitlement-bridge-8.19.2.jar --add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,java.logging,java.net.http,java.naming,jdk.net -XX:+UseG1GC -Djava.io.tmpdir=/tmp/elasticsearch-10892987525338221374 --add-modules=jdk.incubator.vector -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=/var/log/elasticsearch/gc.log:utctime,level,pid,tags:filecount=32,filesize=64m -Xms256m -Xmx256m -XX:MaxDirectMemorySize=134217728 -XX:G1HeapRegionSize=4m -XX:InitiatingHeapOccupancyPercent=30 -XX:G1ReservePercent=15 --module-path /usr/share/elasticsearch/lib --add-modules=jdk.net --add-modules=jdk.management.agent --add-modules=ALL-MODULE-PATH -m org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch

と、一番はElasticsearch(Growiで利用)。次いでMySQL、Redmineと続きます。nodeはGrowi関係です。

メモリ使用率(%MEM)を基準にして、MB単位で表示するワンライナー

続いて、システム全体のメモリ使用率を基準にする場合。

ps aux | tail -n +2 | sort -k 4 -rn | head -n 5 | sort -k 4 -n | awk '{cmd=""; for(i=11;i<=NF;i++){cmd=cmd" "$i}; printf "%5s%%   %s\n", $4, cmd}'

ソートの基準をRSS(6列目)から %MEM(4列目) に変更している点が主な違いです。

  4.3%    node -r dotenv-flow/config dist/server/app.js
  4.8%    Passenger RubyApp: /home/www-data/redmine1 (production)
  6.4%    Passenger RubyApp: /home/www-data/redmine2 (production)
  9.1%    /usr/sbin/mysqld
 11.0%    /usr/share/elasticsearch/jdk/bin/java -Des.networkaddress.cache.ttl=60 -Des.networkaddress.cache.negative.ttl=10 -XX:+AlwaysPreTouch -Xss1m -Djava.awt.headless=true -Dfile.encoding=UTF-8 -Djna.nosys=true -XX:-OmitStackTraceInFastThrow -Dio.netty.noUnsafe=true -Dio.netty.noKeySetOptimization=true -Dio.netty.recycler.maxCapacityPerThread=0 -Dlog4j.shutdownHookEnabled=false -Dlog4j2.disable.jmx=true -Dlog4j2.formatMsgNoLookups=true -Djava.locale.providers=CLDR -Dorg.apache.lucene.vectorization.upperJavaFeatureVersion=24 -Des.distribution.type=deb -Des.java.type=bundled JDK --enable-native-access=org.elasticsearch.nativeaccess,org.apache.lucene.core --enable-native-access=ALL-UNNAMED --illegal-native-access=deny -XX:ReplayDataFile=/var/log/elasticsearch/replay_pid%p.log -Des.entitlements.enabled=true -XX:+EnableDynamicAgentLoading -Djdk.attach.allowAttachSelf=true --patch-module=java.base=lib/entitlement-bridge/elasticsearch-entitlement-bridge-8.19.2.jar --add-exports=java.base/org.elasticsearch.entitlement.bridge=org.elasticsearch.entitlement,java.logging,java.net.http,java.naming,jdk.net -XX:+UseG1GC -Djava.io.tmpdir=/tmp/elasticsearch-10892987525338221374 --add-modules=jdk.incubator.vector -XX:+HeapDumpOnOutOfMemoryError -XX:+ExitOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/elasticsearch -XX:ErrorFile=/var/log/elasticsearch/hs_err_pid%p.log -Xlog:gc*,gc+age=trace,safepoint:file=/var/log/elasticsearch/gc.log:utctime,level,pid,tags:filecount=32,filesize=64m -Xms256m -Xmx256m -XX:MaxDirectMemorySize=134217728 -XX:G1HeapRegionSize=4m -XX:InitiatingHeapOccupancyPercent=30 -XX:G1ReservePercent=15 --module-path /usr/share/elasticsearch/lib --add-modules=jdk.net --add-modules=jdk.management.agent --add-modules=ALL-MODULE-PATH -m org.elasticsearch.server/org.elasticsearch.bootstrap.Elasticsearch

と、実メモリ6GB中の11%をElasticsearchが占めていることが明らかになりました。

Apache & PHP-FPM 管理スクリプト (引数対応版)。

Webサーバを運用する上で役立ている

  1. Apacheで有効になっているサイトの設定情報を表示
  2. 構文を確認
  3. 問題が無ければApache再起動
  4. 再起動後にステータスを表示する

スクリプト。非常に便利なものでしたが、VPS新調に際してPHP-FPMを導入。

そこで、

  1. PHP-FPMも構文チェックを行う
  2. 他、引数による処理

を改訂しました。(元ネタ:ChatGPT、リファクタリングはdeepseekとGemini)

スクリプト内容

  • apache2-check.sh
#!/bin/bash

#================================================================
# Apache & PHP-FPM 管理スクリプト (引数対応版)
#================================================================
#
# 機能:
# 1. Apacheで有効になっているサイトの設定情報を表示します。
# 2. ApacheとPHP-FPMの設定ファイルの構文をチェックします。
# 3. ApacheとPHP-FPMの再起動を個別に確認し、実行します。
# 4. 再起動後に各サービスのステータスを表示します。
#
# 引数:
#  -y : 確認プロンプトをすべてスキップし、自動で'yes'と応答します。
#  -a : Apacheのみを対象とします。
#  -p : PHP-FPMのみを対象とします。
#  -h : このヘルプを表示します。
#
#================================================================

# --- 設定項目 ---

# Apacheのサイト設定が格納されているディレクトリ
SITES_DIR="/etc/apache2/sites-enabled"

# 操作対象のPHPバージョン (例: "8.3", "8.2", "7.4")
PHP_VERSION="8.3"

# --- 設定ここまで ---


# --- スクリプトの動作を制御するフラグ ---
AUTO_YES=false
RESTART_APACHE=true  # デフォルトでは両方実行
RESTART_PHP=true     # デフォルトでは両方実行
EXCLUSIVE_MODE=false # -a または -p が指定されたかを判定するフラグ

# --- ヘルプ表示関数 ---
usage() {
    echo "Usage: $(basename "$0") [-y] [-a] [-p] [-h]"
    echo "  -y : 確認プロンプトをすべてスキップし、自動で'yes'と応答します。"
    echo "  -a : Apacheのみを対象とします。"
    echo "  -p : PHP-FPMのみを対象とします。"
    echo "  -h : ヘルプを表示します。"
    echo "引数なしの場合は、ApacheとPHP-FPMの両方が対象となります。"
    exit 0
}

# --- 引数解析 ---
while getopts "yaph" opt; do
  case $opt in
    y)
      AUTO_YES=true
      ;;
    a)
      if ! $EXCLUSIVE_MODE; then
          # -a or -p が初めて指定された場合、排他モードにしてデフォルトをリセット
          RESTART_APACHE=false
          RESTART_PHP=false
          EXCLUSIVE_MODE=true
      fi
      RESTART_APACHE=true
      ;;
    p)
      if ! $EXCLUSIVE_MODE; then
          # -a or -p が初めて指定された場合、排他モードにしてデフォルトをリセット
          RESTART_APACHE=false
          RESTART_PHP=false
          EXCLUSIVE_MODE=true
      fi
      RESTART_PHP=true
      ;;
    h)
      usage
      ;;
    \?)
      # 不正なオプション
      usage
      ;;
  esac
done

# PHP-FPMのサービス名とコマンド名を変数から生成
PHP_FPM_SERVICE="php${PHP_VERSION}-fpm"
PHP_FPM_COMMAND="php-fpm${PHP_VERSION}"

#
# サービスを再起動し、ステータスを表示する関数
#
restart_and_check_service() {
    local service_name="$1"
    local service_label="$2" # 表示用の名前
    local confirm_action="n"

    if [ "$AUTO_YES" = true ]; then
        confirm_action="y"
        echo "${service_label} を再起動します... (-yオプションにより自動確認)"
    else
        read -p "${service_label} を再起動しますか? (y/n): " confirm_action
    fi

    if [[ "$confirm_action" =~ ^[Yy]$ ]]; then
        if [ "$AUTO_YES" = false ]; then
          echo "--- ${service_label} を再起動します... ---"
        fi
        if ! systemctl restart "$service_name"; then
            echo "エラー: ${service_label} の再起動に失敗しました。"
        else
            echo "${service_label} が正常に再起動されました。"
            echo
            echo "==== ${service_label} ステータス ===="
            systemctl status "$service_name" --no-pager
            echo "=================================="
        fi
    else
        echo "${service_label} の再起動はキャンセルされました。"
    fi
    echo
}

# スクリプトを root ユーザーで実行しているかチェック
if [ "$EUID" -ne 0 ]; then
    echo "エラー: このスクリプトは root 権限で実行する必要があります。"
    exit 1
fi

# 1. 有効なサイト設定とドメインを表示
# このセクションは引数に関わらず常に表示される情報として実行します
echo "==== 有効なサイト設定ファイル ===="
if [ -z "$(ls -A "$SITES_DIR" 2>/dev/null)" ]; then
    echo "サイト設定が存在しません。"
else
    shopt -s nullglob
    for site in "$SITES_DIR"/*; do
        echo "設定ファイル: $(basename "$site")"
        entries=$(grep -hi -E "^\s*(ServerName|ServerAlias)\s+" "$site" | sed -E 's/^[[:blank:]]+//;s/[[:blank:]]*#.*//' | awk '{
            original_directive = $1
            directive = tolower(original_directive)
            proper_directive = (directive == "servername") ? "ServerName" : \
                               (directive == "serveralias") ? "ServerAlias" : original_directive
            for (i=2; i<=NF; i++) {
                domain = tolower($i)
                sub(/[;,]*$/, "", domain)
                gsub(/^[[:blank:]]+|[[:blank:]]+$/, "", domain)
                if (domain) {
                    printf "%s %s\n", proper_directive, domain
                }
            }
        }' | sort -u)
        if [ -z "$entries" ]; then
            echo "  ※ ServerName/ServerAliasが定義されていません"
        else
            echo "$entries" | sed 's/^/  /'
        fi
        echo
    done
    shopt -u nullglob
fi
echo "=================================="
echo

# 2. 構文チェック
echo "--- 構文チェック ---"
SYNTAX_OK=true

# Apache構文チェック
if [ "$RESTART_APACHE" = true ]; then
    echo "Apache の構文をチェックしています..."
    if ! apachectl configtest 2>&1 | grep -q "Syntax OK"; then
        echo "エラー: Apacheの構文エラーが検出されました。"
        apachectl configtest # エラー詳細を再表示
        SYNTAX_OK=false
    else
        echo "Apacheの構文は正常です。"
    fi
    echo
fi

# PHP-FPMの存在確認と構文チェック
PHP_FPM_ENABLED=false
if [ "$RESTART_PHP" = true ]; then
    if systemctl list-units --type=service --all | grep -q "${PHP_FPM_SERVICE}.service"; then
        if command -v "$PHP_FPM_COMMAND" &>/dev/null; then
            PHP_FPM_ENABLED=true
            echo "${PHP_FPM_SERVICE} の構文をチェックしています..."
            if ! "$PHP_FPM_COMMAND" -t 2>&1 | grep -q "test is successful"; then
                echo "エラー: ${PHP_FPM_SERVICE} の構文エラーが検出されました。"
                "$PHP_FPM_COMMAND" -t # エラー詳細を再表示
                SYNTAX_OK=false
            else
                echo "${PHP_FPM_SERVICE} の構文は正常です。"
            fi
        else
            echo "警告: ${PHP_FPM_SERVICE} サービスは存在しますが、${PHP_FPM_COMMAND} コマンドが見つかりませ
ん。PHP-FPMのチェックはスキップします。"
            RESTART_PHP=false # 実行フラグをオフにする
        fi
    else
        echo "情報: ${PHP_FPM_SERVICE} サービスが見つかりません。PHP-FPM関連の処理はスキップします。"
        RESTART_PHP=false # 実行フラグをオフにする
    fi
    echo
fi

# 構文エラーがあれば処理を中断
if [ "$SYNTAX_OK" = false ]; then
    echo "構文エラーが検出されたため、処理を中断します。"
    exit 1
fi
echo "--------------------"
echo

# 3. サービスの再起動
if [ "$RESTART_APACHE" = false ] && [ "$RESTART_PHP" = false ]; then
    echo "再起動対象のサービスがありません。"
    exit 0
fi

# Apacheの再起動
if [ "$RESTART_APACHE" = true ]; then
    restart_and_check_service "apache2" "Apache"
fi

# PHP-FPMの再起動
if [ "$RESTART_PHP" = true ] && [ "$PHP_FPM_ENABLED" = true ]; then
    restart_and_check_service "$PHP_FPM_SERVICE" "$PHP_FPM_SERVICE"
fi

スクリプトの動き

  1. sudo bash apache2-check.shとすることで
  2. A@acheを起動するか、PHP-FPMを起動するかの2択が生まれます。
  3. -yオプションの場合は全てyにしてプロンプトを省略します。
  4. -aでApacheのみの再起動-pはPHP-FPMのみの再起動

と、柔軟かつやりやすいスタイルへと仕上がりました。

Page 1 of 93

Powered by WordPress & Theme by Anders Norén