RHEL 実践 #1 Web サーバー運用: nginx、systemd、SELinux ポリシー

読了 5分

RHEL 実務トラックの基礎・中級・上級で systemd、SELinux、firewalld、ストレージを一つずつ身につけたなら、今度はそのピースを 一つのサービスを載せる 1 サイクル にまとめる番です。RHEL 実践トラックは個別機能を並べるのではなく、実際の運用で出くわすシナリオを最初から最後まで追うトラックです。その最初の記事として、最もよくある作業である Web サーバー運用 を扱います。

RHEL で nginx を載せる作業は、パッケージを一つインストールすれば終わりではありません。サービスを systemd で登録し、SELinux が塞ぐ部分を解き、firewalld でポートを開く三拍子が揃って初めて、外部からページが開きます。この三拍子が噛み合わないときにどこで詰まるかを、一緒に押さえます。

パッケージインストールとサービス登録 #

RHEL の標準リポジトリには nginx が含まれています。dnf でインストールした後、systemd で登録します。

# インストール
sudo dnf install -y nginx

# ブート時に自動起動 + 即時起動 (一度に)
sudo systemctl enable --now nginx

# 状態確認
systemctl status nginx

enable --now は enable (ブート時自動起動) と start (即時起動) を一度に処理します。RHEL 実務でサービスを載せるとき最もよく使う形です。インストール直後はローカルでまず応答を確認しましょう。

curl -I http://localhost

ここまでは SELinux も firewalld も介入しないので、だいたい一度で通ります。問題は 外部から接続するとき、そして デフォルト値を外れるとき に始まります。

firewalld でポートを開く #

素の状態の RHEL は firewalld が有効で、http (80)・https (443) が塞がっています。サービス単位で永続的に開放します。

# http・https サービスを永続的に許可
sudo firewall-cmd --add-service=http --permanent
sudo firewall-cmd --add-service=https --permanent

# 反映
sudo firewall-cmd --reload

# 確認
sudo firewall-cmd --list-all

--permanent を抜かすと、再起動後にルールが消えます。--permanent で永続ルールを作った後 --reload でランタイムに反映する二段階が、RHEL ファイアウォール作業の基本フローです。

SELinux が塞ぐポイント #

RHEL の SELinux はデフォルトが enforcing です。nginx が標準の場所 (/usr/share/nginx/html) から標準ポート (80・443) で動作する限り、SELinux は静かです。ところが ドキュメントルートを移したり非標準ポートを使ったりすると 即座に塞がれます。この二つが実務で最もよく遭遇する SELinux の事故です。

非標準ポートを開くとき #

nginx を 8080 ポートで動かすよう設定を変えると、設定自体は正しくてもサービスが上がりません。SELinux が 8080 を Web サーバーポートとして認めないからです。

# 現在 http_port_t に登録されているポート確認
sudo semanage port -l | grep http_port_t

# 8080 を Web ポートとして永続登録
sudo semanage port -a -t http_port_t -p tcp 8080

semanage が無ければ policycoreutils-python-utils パッケージをインストールします。ポートを登録した後 nginx を再起動すると正常に上がります。

ドキュメントルートを移すとき #

コンテンツを /srv/www のような非標準パスに移すと、そのディレクトリの SELinux コンテキストが Web コンテンツタイプではないため、nginx が読めません。コンテキストを永続的に付与して適用します。

# /srv/www 以下を Web コンテンツタイプとして永続登録
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"

# ディスクの実際のラベルに適用
sudo restorecon -Rv /srv/www

semanage fcontext でポリシーにルールを追加し、restorecon で実際のファイルに適用する二段階が肝心です。chcon でもコンテキストを変えられますが、chcon は一時的でリラベルや再起動時に戻ってしまうので、永続的な作業には semanage fcontext + restorecon を使います。

boolean で動作を許可 #

nginx が他のサーバーへリクエストを転送 (reverse proxy) したり、NFS・CIFS 上のコンテンツを読む必要があるときは、SELinux boolean をオンにします。

# ネットワーク接続を許可 (reverse proxy など)
sudo setsebool -P httpd_can_network_connect on

-P を付けて初めて再起動後も維持されます。どの boolean が必要かは getsebool -a | grep httpd で候補を絞り込み、塞がれたときは audit ログ (/var/log/audit/audit.log) から ausearchsealert で原因を探します。

塞がれたときの診断順序 #

Web サーバーが開かないときは、次の順序で絞り込んでいくと、たいてい原因が見えてきます。

  1. サービスが上がっているか。 systemctl status nginx、失敗時は journalctl -u nginx
  2. ローカルで開くか。 curl -I http://localhost で nginx 自体の問題と外部アクセスの問題を切り分ける
  3. ファイアウォールが開いているか。 firewall-cmd --list-all に http・https があるか
  4. SELinux が塞いでいるか。 sudo ausearch -m AVC -ts recent または journalctl に denied があるか、一時的に setenforce 0 して通れば SELinux が原因

特に 4 番では、setenforce 0 で少しの間 permissive に変えてみると、SELinux が原因かどうかが 1 秒で分かれます。ただし 確認用としてのみ 使い、原因を見つけた後は必ず setenforce 1 に戻してポリシーで解くのが正しい運用です。

まとめ #

この記事で押さえたこと:

  • Web サーバー運用は三拍子。 systemd サービス登録 (enable --now)、firewalld ポート開放 (--permanent + --reload)、SELinux ポリシー
  • SELinux が塞ぐ二つのポイント。 非標準ポート (semanage port -a)、非標準ドキュメントルート (semanage fcontext + restorecon)
  • boolean。 reverse proxy・リモートコンテンツは setsebool -P httpd_can_network_connect on
  • 診断順序。 サービス → ローカル curl → ファイアウォール → SELinux。setenforce 0 は確認用としてのみ

次回: DB 運用 #

Web 層を載せたので、その後ろを支えるデータ層へ進みます。

#2 DB 運用: PostgreSQL on RHEL では、RHEL の AppStream module で PostgreSQL をインストールして初期化する方法、データディレクトリと SELinux コンテキスト、リモート接続のための設定と firewalld、そしてバックアップとサービス運用まで 1 サイクルで整理します。

X