<p><!--META
{
"title": "WP-CLIによるWordPress管理自動化",
"primary_category": "DevOps",
"secondary_categories": ["WordPress", "Automation", "Systemd"],
"tags": ["WP-CLI", "systemd", "jq", "curl", "Bash", "WordPress"],
"summary": "WP-CLIを用いたWordPressの自動管理について、安全なBashスクリプト、systemdタイマー、権限分離の具体的な実装例を解説します。",
"mermaid": true,
"verify_level": "L0",
"tweet_hint": {"text":"WP-CLIでWordPress管理を自動化!systemdと安全なBashスクリプト、権限分離のベストプラクティスを解説。#WordPress #WPCLI
#DevOps #自動化","hashtags":["#WordPress","#WPCLI","#DevOps"]},
"link_hints": ["https://wp-cli.org/ja/", "https://www.freedesktop.org/software/systemd/man/systemd.timer.html"]
}
-->
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。</p>
<h1 class="wp-block-heading">WP-CLIによるWordPress管理自動化</h1>
<p>WordPressの運用において、コア、プラグイン、テーマの更新、データベースの最適化といった日常的な管理作業は多岐にわたります。これらの作業を手動で行うと、時間と労力がかかるだけでなく、ヒューマンエラーのリスクも伴います。WP-CLIを活用し、systemdタイマーと組み合わせることで、これらの管理作業を自動化し、効率的かつ安全な運用を実現できます。</p>
<h2 class="wp-block-heading">要件と前提</h2>
<h3 class="wp-block-heading">要件</h3>
<ul class="wp-block-list">
<li><p><strong>冪等性 (idempotent)</strong> の確保:スクリプトが複数回実行されても同じ結果になるように設計します。</p></li>
<li><p><strong>安全なBashスクリプト</strong>:<code>set -euo pipefail</code>、<code>trap</code>、一時ディレクトリの安全な管理(<code>mktemp -d</code>)を使用します。</p></li>
<li><p><strong>JSON処理</strong>:<code>jq</code>コマンドを用いたJSONデータのパース例を含めます。</p></li>
<li><p><strong>HTTPリクエスト</strong>:<code>curl</code>コマンドによるTLS接続、再試行、バックオフの例を示します。</p></li>
<li><p><strong>systemdユニット/タイマー</strong>:定期実行のための<code>.service</code>と<code>.timer</code>ファイルの具体的な設定例を示します。</p></li>
<li><p><strong>権限分離</strong>:最小権限の原則に基づき、WordPress関連のコマンドは適切なユーザー(例: <code>www-data</code>)で実行します。</p></li>
</ul>
<h3 class="wp-block-heading">前提</h3>
<ul class="wp-block-list">
<li><p>Linux環境(systemdが利用可能)。</p></li>
<li><p>WP-CLIがサーバーにインストールされており、WordPressサイトのルートディレクトリにアクセスできること。</p></li>
<li><p><code>jq</code>と<code>curl</code>がシステムにインストールされていること。</p></li>
<li><p>対象となるWordPressサイトのパスが特定されていること。</p></li>
</ul>
<h2 class="wp-block-heading">実装</h2>
<h3 class="wp-block-heading">自動化ワークフローの概要</h3>
<p>WP-CLIによるWordPress管理自動化の一般的なフローは以下の通りです。</p>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
flowchart TD
A["systemd Timer"] --> |スケジュール実行| B("systemd Service");
B --> |root権限で起動し、Userをwww-dataに切り替え| C{"シェルスクリプト実行"};
C --> |WP-CLIコマンドを実行し、WordPressと連携| D["WordPressサイト"];
D --> |更新や最適化を反映| E("ログ出力");
E --> |journalctlでログを確認| F["ログ監視"];
</pre></div>
<h3 class="wp-block-heading">1. WP-CLIスクリプトの作成</h3>
<p>まず、WP-CLIコマンドを実行するBashスクリプトを作成します。ここでは、WordPressコア、プラグインの更新、データベースの最適化、および外部APIからのデータ取得とWordPressオプションへの設定を行う例を示します。</p>
<p>ファイル: <code>/usr/local/bin/wp_automation_script.sh</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">#!/bin/bash
# -----------------------------------------------------------------------------
# スクリプト名: wp_automation_script.sh
# 概要: WP-CLIを使用してWordPressの定期的なメンテナンス(更新、DB最適化)と
# 外部API連携を自動化するスクリプト。
# 前提:
# - WP-CLIがインストール済み。
# - jq, curlがインストール済み。
# - WordPressのルートディレクトリがWP_PATHに正しく設定されている。
# - systemdサービスからwww-dataユーザーとして実行できるようsudo設定済み。
# -----------------------------------------------------------------------------
# スクリプトの安全な実行設定
# -e: コマンドが失敗した場合、即座に終了
# -u: 未定義の変数を使用しようとした場合、エラーを出して終了
# -o pipefail: パイプライン中のコマンドが失敗した場合、パイプライン全体を失敗させる
set -euo pipefail
# ログファイルの設定
# 標準出力と標準エラーをこのファイルとコンソール(tee)にリダイレクト
log_file="/var/log/wp_automation.log"
exec > >(tee -a "$log_file") 2>&1
# 一時ディレクトリの作成とクリーンアップ設定
# mktemp -d: 安全な一時ディレクトリを作成
# trap: スクリプト終了時(EXIT)に一時ディレクトリを削除
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
echo "$(date +'%Y-%m-%d %H:%M:%S JST') - WordPress自動化スクリプトを開始します。"
# WordPressのパスとWP-CLIを実行するユーザーを設定
# WP_PATH: ご利用のWordPressインストールパスに合わせて変更してください
WP_PATH="/var/www/html/wordpress"
# WP_CLI_USER: WordPressファイルを所有し、WP-CLIを実行する権限を持つユーザー
# 通常はWebサーバーのユーザー(例: www-data, apache)
WP_CLI_USER="www-data"
# WP-CLIコマンドの実行関数
# 権限分離のため、sudo -u を使用して指定ユーザーとして実行
run_wp_cli() {
sudo -u "$WP_CLI_USER" wp "$@" --path="$WP_PATH"
if [ $? -ne 0 ]; then
echo "エラー: WP-CLIコマンド '$@' の実行に失敗しました。"
exit 1
fi
}
echo "WP-CLI自体の更新を確認しています..."
run_wp_cli cli update --yes
echo "WordPressコアの更新を確認しています..."
run_wp_cli core update
echo "WordPressプラグインの更新を確認しています..."
run_wp_cli plugin update --all
echo "WordPressデータベースを最適化しています..."
run_wp_cli db optimize
# 外部APIからデータを取得し、WordPressオプションを更新する例
echo "外部APIからデータを取得し、WordPressオプションを更新します..."
# 前提: インターネット接続、jqがインストール済み
# 入力: EXTERNAL_API_URL
# 出力: WordPressオプション 'my_external_todo_title' が更新される
# 処理時間: ネットワーク呼び出しの遅延、JSONパースの時間
# メモリ: 一般的に小さなJSONオブジェクトを扱うため、低消費
EXTERNAL_API_URL="https://jsonplaceholder.typicode.com/todos/1" # 公開テストAPI
MAX_RETRIES=5 # 最大再試行回数
RETRY_DELAY=5 # 各再試行間の遅延(秒)
RETRY_MAX_TIME=30 # 再試行に費やす合計時間の上限(秒)
# curlコマンドで外部APIからデータを取得
# -sS: サイレントモードでエラー表示
# --fail: HTTPステータスコードが400以上の場合にエラー終了
# --retry: 指定回数再試行
# --retry-delay: 再試行間の遅延
# --retry-max-time: 再試行の合計時間上限
external_data=$(curl -sS --fail --retry "$MAX_RETRIES" --retry-delay "$RETRY_DELAY" --retry-max-time "$RETRY_MAX_TIME" "$EXTERNAL_API_URL")
if [ $? -eq 0 ] && [ -n "$external_data" ]; then
# 取得したJSONデータから'title'フィールドをjqで抽出
# 例: {"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}
todo_title=$(echo "$external_data" | jq -r '.title' 2>/dev/null)
if [ -n "$todo_title" ] && [ "$todo_title" != "null" ]; then
echo "WordPressオプション 'my_external_todo_title' を'${todo_title}'に設定します。"
run_wp_cli option set my_external_todo_title "$todo_title"
else
echo "エラー: 外部APIレスポンスから'title'をパースできませんでした、または値が空/nullでした。"
echo "APIレスポンス: $external_data"
exit 1 # パース失敗もエラーとして扱う
fi
else
echo "エラー: ${EXTERNAL_API_URL} からデータを取得できませんでした (curl終了コード: $?)。"
exit 1 # curl失敗もエラーとして扱う
fi
echo "$(date +'%Y-%m-%d %H:%M:%S JST') - WordPress自動化スクリプトを終了しました。"
</pre>
</div>
<p><strong>root権限の扱いと権限分離の注意点:</strong>
スクリプト自体は<code>root</code>ユーザーで実行される<code>systemd</code>サービスから起動されますが、WordPress関連のWP-CLIコマンドは<code>sudo -u www-data</code>を使って<code>www-data</code>ユーザー(WordPressが動作するユーザー)として実行しています。これにより、WP-CLIが必要以上に高い権限を持つことを防ぎ、セキュリティを強化しています。<code>sudo</code>の設定(<code>/etc/sudoers</code>または<code>/etc/sudoers.d/</code>内のファイル)で、<code>root</code>が<code>www-data</code>としてWP-CLIを実行できるように許可する必要があります。</p>
<p>例: <code>/etc/sudoers.d/wpcli</code></p>
<pre data-enlighter-language="generic">root ALL=(www-data) NOPASSWD: /usr/local/bin/wp_automation_script.sh
</pre>
<p>上記は広すぎる権限を与える例です。より厳密には、<code>/usr/local/bin/wp_automation_script.sh</code>の中で<code>sudo -u www-data</code>で実行される<code>wp</code>コマンドをパスも含めて明示的に許可すべきです。ただし、スクリプト内で動的に引数を渡すため、通常はスクリプト全体を許可するか、<code>www-data</code>ユーザーで直接systemdサービスを実行する方がシンプルです。ここでは、<code>root</code>で起動し、スクリプト内で権限を降格させるパターンを提示します。</p>
<h3 class="wp-block-heading">2. systemdユニットの定義</h3>
<p>作成したスクリプトを定期的に実行するために、systemdのサービスユニットとタイマーユニットを定義します。</p>
<h4 class="wp-block-heading">2.1. サービスユニットファイル (.service)</h4>
<p>サービスユニットは、実行するコマンドやその実行環境を定義します。
ファイル: <code>/etc/systemd/system/wp-auto-update.service</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">[Unit]
Description=Automated WordPress Updates and Maintenance
# ネットワーク接続が確立されるのを待つ
Wants=network-online.target
After=network-online.target
[Service]
# One-shotタイプはコマンドが完了するとサービスが終了する
Type=oneshot
# スクリプトを実行するユーザー(systemdはrootで起動、スクリプト内でsudo -u www-dataを実行)
# WP-CLI自体はwww-dataで実行されますが、sudoコマンドはroot権限が必要です。
User=root
Group=root
# 実行するスクリプトのパス
ExecStart=/usr/local/bin/wp_automation_script.sh
# スクリプトの作業ディレクトリ(任意)
WorkingDirectory=/root
# 標準出力と標準エラーをジャーナルにリダイレクト
StandardOutput=journal
StandardError=journal
# systemdのセキュリティ強化オプション (systemd 229以降)
# システムの重要なディレクトリへのアクセスを制限
ProtectSystem=full
# ユーザーのホームディレクトリへのアクセスを制限
ProtectHome=true
# /tmpディレクトリをプライベートにし、スクリプト実行時のみ利用可能な一時領域を提供
PrivateTmp=true
[Install]
# マルチユーザー環境で利用可能にする
WantedBy=multi-user.target
</pre>
</div>
<h4 class="wp-block-heading">2.2. タイマーユニットファイル (.timer)</h4>
<p>タイマーユニットは、サービスユニットをいつ実行するかを定義します。
ファイル: <code>/etc/systemd/system/wp-auto-update.timer</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">[Unit]
Description=Run WordPress automation script every day
[Timer]
# 毎日午前3時00分 JSTに実行
OnCalendar=*-*-* 03:00:00
# システムがダウンしている間にタイマーが期限切れになった場合、次回起動時にサービスを実行
Persistent=true
# スケジュール時刻に最大5分間のランダムな遅延を追加し、
# 同時に多数のサーバーが起動する「サンダリング・ハーシュ」問題を避ける
RandomSec=300
[Install]
# タイマーを有効にする
WantedBy=timers.target
</pre>
</div>
<h3 class="wp-block-heading">3. systemdユニットの有効化と起動</h3>
<p>サービスユニットとタイマーユニットファイルを作成したら、systemdにそれらを認識させ、有効化します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># systemdに新しいユニットファイルを再読み込みさせる
sudo systemctl daemon-reload
# タイマーユニットを有効化し、システム起動時に自動的に開始するように設定
sudo systemctl enable wp-auto-update.timer
# タイマーをすぐに開始
sudo systemctl start wp-auto-update.timer
</pre>
</div>
<h2 class="wp-block-heading">検証</h2>
<h3 class="wp-block-heading">1. タイマーとサービスのステータス確認</h3>
<p>タイマーとサービスが正しく起動しているか確認します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># タイマーのステータス確認
sudo systemctl status wp-auto-update.timer
# サービスがアクティブな状態になっているか、または最終実行日時を確認
# サービスは実行後に終了するため、通常は inactive (dead) になりますが、
# 正常に実行された場合はログから確認できます。
sudo systemctl status wp-auto-update.service
</pre>
</div>
<h3 class="wp-block-heading">2. ログの確認</h3>
<p>スクリプトの実行結果は、systemdジャーナルとスクリプト内で指定したログファイルの両方で確認できます。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># systemdジャーナルでwp-auto-update.serviceのログを確認
sudo journalctl -u wp-auto-update.service --since "today" --pager-end
# スクリプト内で指定したログファイルを確認
sudo cat /var/log/wp_automation.log
</pre>
</div>
<p>ログには、WP-CLIの実行状況、curlによる外部APIアクセス結果、jqでのパース結果などが記録されているはずです。</p>
<h3 class="wp-block-heading">3. WordPress側での確認</h3>
<p>実際にWordPressの管理画面にログインし、以下を確認します。</p>
<ul class="wp-block-list">
<li><p><strong>WordPressコア、プラグイン、テーマのバージョン</strong>: 最新になっているか。</p></li>
<li><p><strong>サイトヘルス</strong>: 問題がないか。</p></li>
<li><p><strong>データベース</strong>: <code>wp db optimize</code>が正常に実行されたか(これは通常目視では分かりにくいですが、エラーが出ていないことを確認)。</p></li>
<li><p><strong>オプション値</strong>: <code>my_external_todo_title</code>などのカスタムオプションが外部APIから取得した値で更新されているか。</p></li>
</ul>
<h2 class="wp-block-heading">運用</h2>
<ul class="wp-block-list">
<li><p><strong>スクリプトのバージョン管理</strong>: <code>wp_automation_script.sh</code>はGitなどのバージョン管理システムで管理し、変更履歴を追跡します。</p></li>
<li><p><strong>ログ監視</strong>: <code>journalctl</code>や<code>/var/log/wp_automation.log</code>を定期的に監視し、エラーや異常がないかを確認する仕組み(例: ELK Stack, Prometheus + Grafana)を導入します。</p></li>
<li><p><strong>通知システム</strong>: スクリプトの実行失敗時やWP-CLIのエラー時に、メールやSlackなどで管理者への通知を行う仕組みを導入すると、迅速な対応が可能になります。</p></li>
<li><p><strong>権限の定期的なレビュー</strong>: <code>sudoers</code>の設定を含め、不要な権限が付与されていないか定期的に確認します。</p></li>
</ul>
<h2 class="wp-block-heading">トラブルシュート</h2>
<h3 class="wp-block-heading">1. systemdタイマー/サービスが起動しない</h3>
<ul class="wp-block-list">
<li><p><code>sudo systemctl daemon-reload</code> を実行し忘れていないか確認。</p></li>
<li><p><code>sudo systemctl status wp-auto-update.timer</code> および <code>sudo systemctl status wp-auto-update.service</code> でエラーメッセージを確認。</p></li>
<li><p><code>wp-auto-update.timer</code>が<code>enabled</code>になっているか確認。<code>sudo systemctl is-enabled wp-auto-update.timer</code></p></li>
</ul>
<h3 class="wp-block-heading">2. スクリプトが途中で終了する、またはエラーになる</h3>
<ul class="wp-block-list">
<li><p><code>sudo journalctl -u wp-auto-update.service</code> で詳細なログを確認し、どのコマンドでエラーが発生しているか特定。</p></li>
<li><p><code>/var/log/wp_automation.log</code> の内容も確認。</p></li>
<li><p><strong>権限の問題</strong>: <code>sudo -u www-data</code>で実行されるWP-CLIコマンドに必要なディレクトリ(例: WordPressルート、<code>wp-content</code>)への<code>www-data</code>ユーザーの書き込み権限が不足している可能性があります。<code>ls -l</code>でディレクトリやファイルの所有者・権限を確認し、必要であれば<code>chown</code>や<code>chmod</code>で修正します。</p></li>
<li><p><strong>WP-CLIのパス</strong>: <code>WP_PATH</code>が正しいか確認。</p></li>
<li><p><strong><code>jq</code>や<code>curl</code>のエラー</strong>: コマンドラインで手動で実行してみて、予期せぬ出力やエラーがないか確認します。</p></li>
<li><p><strong>ネットワークの問題</strong>: 外部APIへの接続に問題がないか確認します。</p></li>
</ul>
<h3 class="wp-block-heading">3. 予定通りに実行されない</h3>
<ul class="wp-block-list">
<li><p><code>sudo systemctl list-timers --all</code> でタイマーの次回の実行時刻を確認。</p></li>
<li><p><code>OnCalendar</code>の設定(タイムゾーンを含む)が正しいか確認。</p></li>
<li><p><code>Persistent=true</code>が設定されているか確認。</p></li>
</ul>
<h2 class="wp-block-heading">まとめ</h2>
<p>WP-CLIとsystemdタイマーを組み合わせることで、WordPressの管理タスクを効率的かつ安全に自動化できます。本記事で示した<code>set -euo pipefail</code>、<code>trap</code>、<code>mktemp -d</code>による安全なBashスクリプトの記述、<code>jq</code>と<code>curl</code>を用いた外部連携、そして<code>systemd</code>の権限分離とログ管理のベストプラクティスを適用することで、安定したWordPress運用が実現可能です。定期的な検証とログ監視を通じて、自動化されたシステムが常に意図通りに機能していることを確認することが重要です。この自動化戦略は、DevOpsの原則に則り、インフラストラクチャの信頼性と効率性を向上させる強力な手段となります。</p>
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
WP-CLIによるWordPress管理自動化
WordPressの運用において、コア、プラグイン、テーマの更新、データベースの最適化といった日常的な管理作業は多岐にわたります。これらの作業を手動で行うと、時間と労力がかかるだけでなく、ヒューマンエラーのリスクも伴います。WP-CLIを活用し、systemdタイマーと組み合わせることで、これらの管理作業を自動化し、効率的かつ安全な運用を実現できます。
要件と前提
要件
冪等性 (idempotent) の確保:スクリプトが複数回実行されても同じ結果になるように設計します。
安全なBashスクリプト:set -euo pipefail、trap、一時ディレクトリの安全な管理(mktemp -d)を使用します。
JSON処理:jqコマンドを用いたJSONデータのパース例を含めます。
HTTPリクエスト:curlコマンドによるTLS接続、再試行、バックオフの例を示します。
systemdユニット/タイマー:定期実行のための.serviceと.timerファイルの具体的な設定例を示します。
権限分離:最小権限の原則に基づき、WordPress関連のコマンドは適切なユーザー(例: www-data)で実行します。
前提
Linux環境(systemdが利用可能)。
WP-CLIがサーバーにインストールされており、WordPressサイトのルートディレクトリにアクセスできること。
jqとcurlがシステムにインストールされていること。
対象となるWordPressサイトのパスが特定されていること。
実装
自動化ワークフローの概要
WP-CLIによるWordPress管理自動化の一般的なフローは以下の通りです。
flowchart TD
A["systemd Timer"] --> |スケジュール実行| B("systemd Service");
B --> |root権限で起動し、Userをwww-dataに切り替え| C{"シェルスクリプト実行"};
C --> |WP-CLIコマンドを実行し、WordPressと連携| D["WordPressサイト"];
D --> |更新や最適化を反映| E("ログ出力");
E --> |journalctlでログを確認| F["ログ監視"];
1. WP-CLIスクリプトの作成
まず、WP-CLIコマンドを実行するBashスクリプトを作成します。ここでは、WordPressコア、プラグインの更新、データベースの最適化、および外部APIからのデータ取得とWordPressオプションへの設定を行う例を示します。
ファイル: /usr/local/bin/wp_automation_script.sh
#!/bin/bash
# -----------------------------------------------------------------------------
# スクリプト名: wp_automation_script.sh
# 概要: WP-CLIを使用してWordPressの定期的なメンテナンス(更新、DB最適化)と
# 外部API連携を自動化するスクリプト。
# 前提:
# - WP-CLIがインストール済み。
# - jq, curlがインストール済み。
# - WordPressのルートディレクトリがWP_PATHに正しく設定されている。
# - systemdサービスからwww-dataユーザーとして実行できるようsudo設定済み。
# -----------------------------------------------------------------------------
# スクリプトの安全な実行設定
# -e: コマンドが失敗した場合、即座に終了
# -u: 未定義の変数を使用しようとした場合、エラーを出して終了
# -o pipefail: パイプライン中のコマンドが失敗した場合、パイプライン全体を失敗させる
set -euo pipefail
# ログファイルの設定
# 標準出力と標準エラーをこのファイルとコンソール(tee)にリダイレクト
log_file="/var/log/wp_automation.log"
exec > >(tee -a "$log_file") 2>&1
# 一時ディレクトリの作成とクリーンアップ設定
# mktemp -d: 安全な一時ディレクトリを作成
# trap: スクリプト終了時(EXIT)に一時ディレクトリを削除
tmpdir=$(mktemp -d)
trap 'rm -rf "$tmpdir"' EXIT
echo "$(date +'%Y-%m-%d %H:%M:%S JST') - WordPress自動化スクリプトを開始します。"
# WordPressのパスとWP-CLIを実行するユーザーを設定
# WP_PATH: ご利用のWordPressインストールパスに合わせて変更してください
WP_PATH="/var/www/html/wordpress"
# WP_CLI_USER: WordPressファイルを所有し、WP-CLIを実行する権限を持つユーザー
# 通常はWebサーバーのユーザー(例: www-data, apache)
WP_CLI_USER="www-data"
# WP-CLIコマンドの実行関数
# 権限分離のため、sudo -u を使用して指定ユーザーとして実行
run_wp_cli() {
sudo -u "$WP_CLI_USER" wp "$@" --path="$WP_PATH"
if [ $? -ne 0 ]; then
echo "エラー: WP-CLIコマンド '$@' の実行に失敗しました。"
exit 1
fi
}
echo "WP-CLI自体の更新を確認しています..."
run_wp_cli cli update --yes
echo "WordPressコアの更新を確認しています..."
run_wp_cli core update
echo "WordPressプラグインの更新を確認しています..."
run_wp_cli plugin update --all
echo "WordPressデータベースを最適化しています..."
run_wp_cli db optimize
# 外部APIからデータを取得し、WordPressオプションを更新する例
echo "外部APIからデータを取得し、WordPressオプションを更新します..."
# 前提: インターネット接続、jqがインストール済み
# 入力: EXTERNAL_API_URL
# 出力: WordPressオプション 'my_external_todo_title' が更新される
# 処理時間: ネットワーク呼び出しの遅延、JSONパースの時間
# メモリ: 一般的に小さなJSONオブジェクトを扱うため、低消費
EXTERNAL_API_URL="https://jsonplaceholder.typicode.com/todos/1" # 公開テストAPI
MAX_RETRIES=5 # 最大再試行回数
RETRY_DELAY=5 # 各再試行間の遅延(秒)
RETRY_MAX_TIME=30 # 再試行に費やす合計時間の上限(秒)
# curlコマンドで外部APIからデータを取得
# -sS: サイレントモードでエラー表示
# --fail: HTTPステータスコードが400以上の場合にエラー終了
# --retry: 指定回数再試行
# --retry-delay: 再試行間の遅延
# --retry-max-time: 再試行の合計時間上限
external_data=$(curl -sS --fail --retry "$MAX_RETRIES" --retry-delay "$RETRY_DELAY" --retry-max-time "$RETRY_MAX_TIME" "$EXTERNAL_API_URL")
if [ $? -eq 0 ] && [ -n "$external_data" ]; then
# 取得したJSONデータから'title'フィールドをjqで抽出
# 例: {"userId": 1, "id": 1, "title": "delectus aut autem", "completed": false}
todo_title=$(echo "$external_data" | jq -r '.title' 2>/dev/null)
if [ -n "$todo_title" ] && [ "$todo_title" != "null" ]; then
echo "WordPressオプション 'my_external_todo_title' を'${todo_title}'に設定します。"
run_wp_cli option set my_external_todo_title "$todo_title"
else
echo "エラー: 外部APIレスポンスから'title'をパースできませんでした、または値が空/nullでした。"
echo "APIレスポンス: $external_data"
exit 1 # パース失敗もエラーとして扱う
fi
else
echo "エラー: ${EXTERNAL_API_URL} からデータを取得できませんでした (curl終了コード: $?)。"
exit 1 # curl失敗もエラーとして扱う
fi
echo "$(date +'%Y-%m-%d %H:%M:%S JST') - WordPress自動化スクリプトを終了しました。"
root権限の扱いと権限分離の注意点:
スクリプト自体はrootユーザーで実行されるsystemdサービスから起動されますが、WordPress関連のWP-CLIコマンドはsudo -u www-dataを使ってwww-dataユーザー(WordPressが動作するユーザー)として実行しています。これにより、WP-CLIが必要以上に高い権限を持つことを防ぎ、セキュリティを強化しています。sudoの設定(/etc/sudoersまたは/etc/sudoers.d/内のファイル)で、rootがwww-dataとしてWP-CLIを実行できるように許可する必要があります。
例: /etc/sudoers.d/wpcli
root ALL=(www-data) NOPASSWD: /usr/local/bin/wp_automation_script.sh
上記は広すぎる権限を与える例です。より厳密には、/usr/local/bin/wp_automation_script.shの中でsudo -u www-dataで実行されるwpコマンドをパスも含めて明示的に許可すべきです。ただし、スクリプト内で動的に引数を渡すため、通常はスクリプト全体を許可するか、www-dataユーザーで直接systemdサービスを実行する方がシンプルです。ここでは、rootで起動し、スクリプト内で権限を降格させるパターンを提示します。
2. systemdユニットの定義
作成したスクリプトを定期的に実行するために、systemdのサービスユニットとタイマーユニットを定義します。
2.1. サービスユニットファイル (.service)
サービスユニットは、実行するコマンドやその実行環境を定義します。
ファイル: /etc/systemd/system/wp-auto-update.service
[Unit]
Description=Automated WordPress Updates and Maintenance
# ネットワーク接続が確立されるのを待つ
Wants=network-online.target
After=network-online.target
[Service]
# One-shotタイプはコマンドが完了するとサービスが終了する
Type=oneshot
# スクリプトを実行するユーザー(systemdはrootで起動、スクリプト内でsudo -u www-dataを実行)
# WP-CLI自体はwww-dataで実行されますが、sudoコマンドはroot権限が必要です。
User=root
Group=root
# 実行するスクリプトのパス
ExecStart=/usr/local/bin/wp_automation_script.sh
# スクリプトの作業ディレクトリ(任意)
WorkingDirectory=/root
# 標準出力と標準エラーをジャーナルにリダイレクト
StandardOutput=journal
StandardError=journal
# systemdのセキュリティ強化オプション (systemd 229以降)
# システムの重要なディレクトリへのアクセスを制限
ProtectSystem=full
# ユーザーのホームディレクトリへのアクセスを制限
ProtectHome=true
# /tmpディレクトリをプライベートにし、スクリプト実行時のみ利用可能な一時領域を提供
PrivateTmp=true
[Install]
# マルチユーザー環境で利用可能にする
WantedBy=multi-user.target
2.2. タイマーユニットファイル (.timer)
タイマーユニットは、サービスユニットをいつ実行するかを定義します。
ファイル: /etc/systemd/system/wp-auto-update.timer
[Unit]
Description=Run WordPress automation script every day
[Timer]
# 毎日午前3時00分 JSTに実行
OnCalendar=*-*-* 03:00:00
# システムがダウンしている間にタイマーが期限切れになった場合、次回起動時にサービスを実行
Persistent=true
# スケジュール時刻に最大5分間のランダムな遅延を追加し、
# 同時に多数のサーバーが起動する「サンダリング・ハーシュ」問題を避ける
RandomSec=300
[Install]
# タイマーを有効にする
WantedBy=timers.target
3. systemdユニットの有効化と起動
サービスユニットとタイマーユニットファイルを作成したら、systemdにそれらを認識させ、有効化します。
# systemdに新しいユニットファイルを再読み込みさせる
sudo systemctl daemon-reload
# タイマーユニットを有効化し、システム起動時に自動的に開始するように設定
sudo systemctl enable wp-auto-update.timer
# タイマーをすぐに開始
sudo systemctl start wp-auto-update.timer
検証
1. タイマーとサービスのステータス確認
タイマーとサービスが正しく起動しているか確認します。
# タイマーのステータス確認
sudo systemctl status wp-auto-update.timer
# サービスがアクティブな状態になっているか、または最終実行日時を確認
# サービスは実行後に終了するため、通常は inactive (dead) になりますが、
# 正常に実行された場合はログから確認できます。
sudo systemctl status wp-auto-update.service
2. ログの確認
スクリプトの実行結果は、systemdジャーナルとスクリプト内で指定したログファイルの両方で確認できます。
# systemdジャーナルでwp-auto-update.serviceのログを確認
sudo journalctl -u wp-auto-update.service --since "today" --pager-end
# スクリプト内で指定したログファイルを確認
sudo cat /var/log/wp_automation.log
ログには、WP-CLIの実行状況、curlによる外部APIアクセス結果、jqでのパース結果などが記録されているはずです。
3. WordPress側での確認
実際にWordPressの管理画面にログインし、以下を確認します。
WordPressコア、プラグイン、テーマのバージョン: 最新になっているか。
サイトヘルス: 問題がないか。
データベース: wp db optimizeが正常に実行されたか(これは通常目視では分かりにくいですが、エラーが出ていないことを確認)。
オプション値: my_external_todo_titleなどのカスタムオプションが外部APIから取得した値で更新されているか。
運用
スクリプトのバージョン管理: wp_automation_script.shはGitなどのバージョン管理システムで管理し、変更履歴を追跡します。
ログ監視: journalctlや/var/log/wp_automation.logを定期的に監視し、エラーや異常がないかを確認する仕組み(例: ELK Stack, Prometheus + Grafana)を導入します。
通知システム: スクリプトの実行失敗時やWP-CLIのエラー時に、メールやSlackなどで管理者への通知を行う仕組みを導入すると、迅速な対応が可能になります。
権限の定期的なレビュー: sudoersの設定を含め、不要な権限が付与されていないか定期的に確認します。
トラブルシュート
1. systemdタイマー/サービスが起動しない
sudo systemctl daemon-reload を実行し忘れていないか確認。
sudo systemctl status wp-auto-update.timer および sudo systemctl status wp-auto-update.service でエラーメッセージを確認。
wp-auto-update.timerがenabledになっているか確認。sudo systemctl is-enabled wp-auto-update.timer
2. スクリプトが途中で終了する、またはエラーになる
sudo journalctl -u wp-auto-update.service で詳細なログを確認し、どのコマンドでエラーが発生しているか特定。
/var/log/wp_automation.log の内容も確認。
権限の問題: sudo -u www-dataで実行されるWP-CLIコマンドに必要なディレクトリ(例: WordPressルート、wp-content)へのwww-dataユーザーの書き込み権限が不足している可能性があります。ls -lでディレクトリやファイルの所有者・権限を確認し、必要であればchownやchmodで修正します。
WP-CLIのパス: WP_PATHが正しいか確認。
jqやcurlのエラー: コマンドラインで手動で実行してみて、予期せぬ出力やエラーがないか確認します。
ネットワークの問題: 外部APIへの接続に問題がないか確認します。
3. 予定通りに実行されない
sudo systemctl list-timers --all でタイマーの次回の実行時刻を確認。
OnCalendarの設定(タイムゾーンを含む)が正しいか確認。
Persistent=trueが設定されているか確認。
まとめ
WP-CLIとsystemdタイマーを組み合わせることで、WordPressの管理タスクを効率的かつ安全に自動化できます。本記事で示したset -euo pipefail、trap、mktemp -dによる安全なBashスクリプトの記述、jqとcurlを用いた外部連携、そしてsystemdの権限分離とログ管理のベストプラクティスを適用することで、安定したWordPress運用が実現可能です。定期的な検証とログ監視を通じて、自動化されたシステムが常に意図通りに機能していることを確認することが重要です。この自動化戦略は、DevOpsの原則に則り、インフラストラクチャの信頼性と効率性を向上させる強力な手段となります。
コメント