
ホームラボを管理しよう。Ansible × Semaphore UI による一元管理を構築してみる
ansible ユーザーを作成し、FIPS モード環境では ED25519 ではなく ECDSA 鍵を使うなど、実運用でつまずいた点も整理しています。さらに、node_exporter の導入を OS 標準の DNF/YUM に任せる設計や、Semaphore UI の BoltDB 設定、cookie 鍵設定によるログインエラーの対処もまとめています。はじめに
自宅で複数のサーバーや Raspberry Pi などを運用する「ホームラボ」を楽しんでいると、避けて通れないのが「サーバーの管理コスト」です。台数が増えるにつれて、OS のアップデートや設定変更を 1 台ずつ手動で行うのは難しくなってきます。
こうした構成管理の自動化に向いているツールが Ansible です。Ansible には「冪等性(へきとうせい)」という特徴があり、Playbook(定義書)を何度実行しても、期待する状態に収束するように処理できます。これにより、「このサーバー、設定したっけ?」という不安を減らし、安全に複数サーバーの構成を維持できます。

Ansibleの冪等性のイメージ
しかし、サーバーが増えてくると「手元の PC から毎回コマンドラインで実行する」「実行ログがコンソールから消えてしまう」「実行ユーザーを間違える」といった新たな課題も出てきます。もっと手軽に、ブラウザの GUI 画面からボタンを押すだけで Playbook を実行したくなります。
そこで今回は、軽量な Web UI ツールである Semaphore UI を導入し、ホームラボの「管理母艦」として Ansible を一元管理する環境を構築してみます。
Semaphore UIとは
Semaphore UI は、Ansible の Playbook 実行をブラウザ(GUI)から管理・実行できるようにするオープンソースの Web UI ツールです。
一般的に Ansible の GUI 管理ツールといえば、Red Hat 公式が主導する AWX(Ansible Automation Platform の上流プロジェクト) が有名です。ただし、ホームラボ(個人開発・自宅サーバー環境)では、Semaphore UI の方が軽量で扱いやすく、親和性が高いと感じました。
公式ブログの比較記事「Ansible AWX vs. Semaphore UI: 正直なオープンソース比較 (2026)」でも解説されていますが、主な違いは以下の通りです。
AWX と Semaphore UI の比較
| 項目 | AWX | Semaphore UI |
|---|---|---|
| 推奨リソース | 8 GB RAM / 4 コア CPU 以上 | 512 MB RAM / 1 コア CPU 以上 |
| デプロイ方法 | Kubernetes / K3s が必要 | Docker、バイナリ、パッケージ等(軽量・簡単) |
| 対応ツール | 主に Ansible | Ansible, Terraform/OpenTofu, Bash, Python, PowerShell |
| 手軽さ | 構築・維持に数時間〜数日(K8s の知識要) | 数分で立ち上げ完了(Docker 1コマンド) |
| 開発状況 (2026年時点) | 統合リリースは 2024年7月の v24.6.1 で停止中 | 活発(継続的なアップデートあり) |
ホームラボでの採用経緯
個人で管理するホームラボ環境において、AWX の「Kubernetes 前提の構成」や「大きめのメモリ要求」はかなり重く、構築コストがかかります。自宅サーバーのリソースの多くを管理ツールの維持だけに割くのは現実的ではありません。
その点、Semaphore UI は非常に軽量で、小さな VM や Docker コンテナでも動かしやすい構成です。また、今回は Ansible を実行するために導入しますが、シェルスクリプト(Bash)や Terraform/OpenTofu もサポートしているため、「とりあえず作ったお役立ちスクリプトをブラウザから実行できるようにする」といった、ホームラボにありがちな雑多な運用自動化にも向いています。
この「軽さ」「手軽さ」「拡張性の高さ」が、今回のホームラボ管理の母艦として Semaphore UI を採用した大きな理由です。
構築するシステム構成
今回構築したホームラボの構成は以下の通りです。

ホームラボ構成
設計のこだわり
- エージェントレスと専用ユーザーの作成
セキュリティと監査ログの観点から、各サーバーに専用の管理ユーザー(ansible)を作成し、パスワードレス sudo 権限を付与して一元管理します。 - ローカル接続の最適化
母艦自身への Ansible 実行(localhost)は、SSH を経由しないローカル接続(ansible_connection: local)にすることで、無駄な SSH 鍵の管理を排除します。
ターゲットサーバーの初期セットアップ(手動による事前準備)
まず、管理対象となる各 Raspberry Pi(Fedora, AlmaLinux)および母艦サーバー自身に、Ansible 専用の ansible ユーザーをセットアップします。
各 Linux サーバーで実行するコマンド
# 1. ユーザー作成 (ホームディレクトリを必ず作成する)
sudo useradd -m -s /bin/bash ansible
sudo usermod -aG wheel ansible
# 2. パスワード不要で sudo を実行できるように設定
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible
sudo chmod 440 /etc/sudoers.d/ansible
~/.ssh/authorized_keys)として利用するほか、Ansible が実行時に一時ファイルを転送・実行する領域(~/.ansible/tmp/)として機能するためです。SSH 公開鍵登録と「FIPS モード」の罠
母艦の ansible ユーザーから各ターゲットへパスワードなしで SSH ログインできるように鍵を配布します。ここで、エンタープライズな RHEL ならではの罠に遭遇しました。
トラブル:ED25519 keys are not allowed in FIPS mode
母艦の RHEL で FIPS(連邦情報処理規格)モード が有効になっていたため、よく使われる ED25519 鍵がシステムによって拒否されました。FIPS モード環境では、環境のポリシーに合う ECDSA または RSA(3072bit 以上) を使用する必要があります。
対策:ECDSA 384bit で鍵を生成する
母艦の ansible ユーザーで、暗号強度とパフォーマンスのバランスが良い ECDSA(384bit) を指定して鍵を作成しました。
# 母艦の ansible ユーザーで実行
ssh-keygen -t ecdsa -b 384
パスワード認証拒否(AlmaLinux)への手動対処
AlmaLinux サーバーなどでパスワードによる SSH ログインが禁止(PasswordAuthentication no)されている場合、通常の ssh-copy-id コマンドが通りません。
この場合は、現在ログインできる個人ユーザーでログインし、手動で公開鍵を流し込みます。
# 1. 母艦側で公開鍵の中身を表示してコピーする
cat ~/.ssh/id_ecdsa.pub
# 2. AlmaLinux側にログインし、ansibleユーザーのディレクトリに配置する
sudo mkdir -p /home/ansible/.ssh
sudo chmod 700 /home/ansible/.ssh
echo "【コピーした公開鍵のテキスト】" | sudo tee /home/ansible/.ssh/authorized_keys
sudo chmod 600 /home/ansible/.ssh/authorized_keys
sudo chown -R ansible:ansible /home/ansible/.ssh
これで、母艦から各ターゲットへパスワードなしでログインできるようになります。
インベントリファイルの作成 (inventory/hosts.yml)
母艦ローカル(モニターサーバー自身)と、リモートの Raspberry Pi 群をグループ分けして 1 つのインベントリにまとめました。
all:
children:
# --- リモート管理対象サーバー (ラズベリーパイ) ---
rpis:
hosts:
fedora-pi:
ansible_host: 192.168.1.151
almalinux-pi:
ansible_host: 192.168.1.152
vars:
ansible_user: ansible
ansible_python_interpreter: /usr/bin/python3
# --- 母艦サーバー自身 (ローカル実行用) ---
local:
hosts:
localhost:
vars:
ansible_connection: local
ansible_python_interpreter: /usr/bin/python3
OSパッケージ管理(DNF)に寄り添った Playbook の設計
監視に必要な node_exporter を展開するにあたり、当初は Ansible 側で GitHub からバイナリをダウンロードし、直接 /opt/ に配置するタスクを書いていました。しかし、「すでに手動や DNF で導入している環境と競合する」という問題が発生しました。
自宅インフラの既存環境を汚さず、安全かつ冪等性を保つため、「OS 標準のパッケージ管理(DNF/YUM)に任せるクリーンなロール」に設計変更しました。
roles/node_exporter/tasks/main.yml
---
# ターゲットサーバーの OS パッケージマネージャーを利用して node_exporter をインストール
- name: Ensure node_exporter package is installed (via OS repository)
package:
name: node_exporter
state: present
# サービスの有効化と起動
- name: Ensure node_exporter service is enabled and started
systemd:
name: node_exporter
enabled: yes
state: started
この設計により、すでに DNF で導入済みのサーバーに対しては不要な変更を行わず、新規のサーバーが追加された場合は自動でパッケージをインストールする、安全で見通しの良い挙動になりました。
Semaphore UI の導入と 2 つのトラブルシューティング
Ansible の Playbook をブラウザの画面から実行・管理できるようにするため、軽量な Web UI ツールである Semaphore UI を導入しました。この導入過程で、いくつかの技術的なハードルを解決しました。
トラブル1:panic: open : no such file or directory(BoltDB キー問題)
現象
初期ユーザー追加時に Semaphore UI がパニックで強制終了しました。
原因
Semaphore UI で組み込み DB の BoltDB を使用する際、config.json 内のデータベースファイルのパス指定キーは、"path" ではなく "host" である必要がありました。キーが違ったため、パスが空と解釈されてエラーになりました。
bolt は deprecated とされています。新規構築で長く使うなら SQLite / PostgreSQL / MySQL を選ぶ方が無難です。今回は実際にハマったポイントの記録として BoltDB の例を残しています。対策
config.json のテンプレートのキー名を以下のように修正しました。
{
"bolt": {
"host": "/var/lib/semaphore/database.boltdb"
}
}
トラブル2:securecookie: hash key is not set / invalid key size 0
現象
ログイン画面で ID/パスワードを入力してログインボタンを押した瞬間、Semaphore UI が 502 エラーまたは上記パニックでクラッシュしました。
原因
ログインセッションを管理する securecookie が必要とする cookie_hash と cookie_encryption には、十分な長さのランダムなシークレットを設定する必要があります。特に cookie_encryption は AES の鍵として使われるため、デコード後のサイズが 16 / 24 / 32 バイトのいずれかになっていないと invalid key size で失敗します。今回は平文の短い文字列を指定していたため、鍵サイズが不正になり AES 暗号化エラーが起きました。
また、設定ファイルを更新した後に systemd サービスが再起動されていなかったため、古い設定が残っていました。
対策
Playbook 内で b64encode を使ってランダムな Base64 エンコードデータを生成し、同じ値を継続利用できるようにファイルへ保持します。/dev/null を指定すると毎回ランダム値が変わってしまうため、設定ファイルが毎回更新され、不要な再起動やセッション無効化につながります。
あわせて、設定ファイル更新時には systemd を自動で再起動する handlers を実装しました。
# Playbook の変数定義部分
semaphore_cookie_hash: "{{ lookup('password', playbook_dir + '/.secrets/semaphore_cookie_hash length=32 chars=ascii_letters,digits') | b64encode }}"
semaphore_cookie_encryption: "{{ lookup('password', playbook_dir + '/.secrets/semaphore_cookie_encryption length=32 chars=ascii_letters,digits') | b64encode }}"
semaphore_access_key_encryption: "{{ lookup('password', playbook_dir + '/.secrets/semaphore_access_key_encryption length=32 chars=ascii_letters,digits') | b64encode }}"
access_key_encryption は Key Store に保存した SSH 鍵などの暗号化にも関わるため、こちらも同じ考え方で固定値として保持します。
Web UI(Semaphore UI)での接続・実行設定
以上のトラブルシューティングを経て Semaphore UI が正常に起動した後は、ブラウザから http://{母艦の内部IP}:3005 にアクセスします。

Semaphore UI ログイン画面
ログイン後、まずは自動化タスクを管理するためのプロジェクトを作成(ログイン後の初期設定)します。
プロジェクト作成後、プロジェクト内で以下の設定を登録しました。
- Key Store
母艦の SSH 秘密鍵(/home/ansible/.ssh/id_ecdsa)のテキストを登録。 - Repositories
今回の Git リポジトリ(RHEL 上のローカル絶対パス/usr/local/src/ansible-playbooks)を指定。 - Inventories
リポジトリから読み込むファイルとしてinventory/hosts.ymlを指定し、登録した SSH 鍵を紐付ける。 - Environment
名前をdefault-envとし、環境変数に{}(空の JSON)を登録。 - Task Templates
実行する Playbook にmonitoring.ymlを指定して作成。
これで、ブラウザ上の Run ボタンから、母艦サーバーの Prometheus 監視対象(自分自身、Raspberry Pi 2台、Windows Server の合計4つのターゲット)に対して、node_exporter の展開と監視設定の再読み込みを安全にデプロイできるようになりました。

Semaphore UI ダッシュボード画面
まとめ
当初の「インベントリを作りたい」という要件から、ユーザー権限の設計、OS 標準のパッケージ管理との整合、そして FIPS モードや Semaphore UI のパニックエラーへの対処を経て、堅牢で見通しの良い監視自動化環境を構築できました。
また、Semaphore UI は今回試した Ansible だけでなく、Terraform や OpenTofu もサポートしています。
今回は Ansible を使った構成管理と監視のデプロイを行いましたが、今後はサーバーのプロビジョニング(仮想マシンの切り出しなど)も含めて、Terraform × Semaphore UI によるインフラ全体の自動化・一元管理の拡張にも挑戦していきたいと考えています。
ホームラボの運用は、自動化と可視化があると障害対応が圧倒的に楽になります。ぜひ皆さんも Semaphore UI を使った Ansible GUI 管理に挑戦してみてください!
