午前2時。本番環境のアプリが接続タイムアウトエラーを連発していた。ログを確認すると、Redisクライアントが接続できていない。午後にセットアップしたFedora Serverに Redis をインストールし終えたばかりで、ローカルでredis-cli pingを実行するとPONGが返ってきていた——しかし別サーバーのアプリからは完全にタイムアウトしていた。
これはFedoraを使い始めて最初に学んだ教訓だ:FedoraはUbuntuではない。SELinux enforcingとfirewalldははるかに厳格で、bind address、firewall、SELinuxという三つの層をすべて対処しなければ、朝まで debug しても解決できない。
実際に直面した問題
Redisをインストールしてサービスを起動し、サーバー上で直接テストすると問題なかった。しかし同じ内部ネットワーク上の別サーバーで動いているNode.jsアプリが接続しようとすると、ちょうど30秒後にタイムアウトしてしまう。
/var/log/redis/redis.logを確認——異常なし。systemctl status redisを確認——起動中。ファイアウォールを疑いfirewall-cmd --list-portsを確認——port 6379がない。ポートを開けてリロードして再テスト——それでもタイムアウト。
そこでようやく思い出した:FedoraはデフォルトでSELinuxをenforcingモードで動かしている。Ubuntuは通常AppArmorをもっと緩いプロファイルで使う。FedoraはSELinuxが最初から厳格で、誰も事前に教えてくれなかった。
原因の分析
調べてみると、同時に対処しなければならないことが三つあった——一つずつデバッグしていたのが1時間以上かかった原因だった:
- Redis bind address:デフォルトでRedisは
127.0.0.1のみリッスンしている——ローカルアクセスのみで、別サーバーのアプリからは絶対に接続できない - firewalld:port 6379はデフォルトで完全にブロックされており、例外なし
- SELinux:ファイアウォールを開放しても、SELinuxがRedisのポートバインドや他プロセスからのネットワーク接続をブロックする可能性がある
この三つはすべて対処する必要がある。一つでも見落とすとまたデバッグの繰り返しになる。
Fedora ServerへのRedisのインストール
ステップ1:デフォルトリポジトリからRedisをインストール
メインの開発マシンとしてFedoraを2年間使っているが、FedoraリポジトリのRedisは常に比較的新しく、現在は7.xで外部リポジトリは不要だ。policycoreutils-python-utilsパッケージは後のSELinuxのステップで使うaudit2allowとaudit2whyのために一緒にインストールする。
sudo dnf install redis policycoreutils-python-utils -y
# バージョン確認
redis-server --version
ステップ2:Redisの設定
主な設定ファイルは/etc/redis/redis.confにある。編集前にバックアップを取る:
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
sudo nano /etc/redis/redis.conf
変更が必要な行:
# localhostとサーバーの内部IPの両方にバインド
# 192.168.1.100を内部ネットワークインターフェースの実際のIPに置き換える
bind 127.0.0.1 192.168.1.100
# パスワードを設定——ネットワークに公開する場合は必須
# Redis 6+はより強力なACLをサポートするが、シンプルな設定にはrequirepassで十分
requirepass YourStrongPassword123!
# メモリ制限——目安:サーバーの全RAMの約25〜30%
# 512mbはRAM 2〜4GBのサーバーに適している
maxmemory 512mb
maxmemory-policy allkeys-lru
# デフォルトポート
port 6379
bind addressについて:アプリとRedisが同じサーバーにある場合は127.0.0.1のままにする。別サーバーからの接続が必要な場合は内部インターフェースのIPを追加する。ファイアウォールが十分に設定されていない限り、本番環境で0.0.0.0は使わないようにする。
ステップ3:サービスの有効化と起動
sudo systemctl enable redis --now
sudo systemctl status redis
SELinux問題の解決
このセクションが最もスキップされやすい部分だ——ほとんどのRedisチュートリアルはUbuntu向けに書かれており、SELinuxについてはほとんど触れていない。Fedoraでは違う:最初からenforcingモードで動いており、setenforce 0で無効化すべきではない。正しい方法はpolicyを作成することだ。
SELinuxがブロックしているかの確認
# Redisに関連する最近のdenyを確認
sudo ausearch -m avc -ts recent | grep redis
# setroubleshootのメッセージを確認
sudo journalctl -t setroubleshoot | tail -50
Redisに関連するavc: denied \{ name_connect \}のような行が見えたら——間違いなく、SELinuxがブロックしている。
方法1:既存のSELinux booleanを有効化する
# Redisに関連するすべてのbooleanを確認
sudo getsebool -a | grep redis
# 必要なネットワーク接続を許可
sudo setsebool -P redis_can_network_connect on
booleanの名前はFedoraのバージョンによって異なる——redis_can_network_connectがリストにない場合は、方法2に進む。
方法2:auditログからSELinux policyを作成する(最も正確な方法)
こちらの方法をよく使う——実際にブロックされているものからpolicyを作成するので、推測がいらない:
# ブロックされた理由を確認
sudo ausearch -m avc -ts recent | grep redis | audit2why
# policyモジュールを作成
sudo ausearch -m avc -ts recent | grep redis | audit2allow -M redis_custom
# policyを適用
sudo semodule -i redis_custom.pp
# モジュールがロードされているか確認
sudo semodule -l | grep redis
Redisのデータディレクトリを変更した場合
デフォルトの/var/lib/redis以外のディレクトリにデータを変更した場合、SELinuxコンテキストを再設定する必要がある:
# /data/redisへの変更例
sudo semanage fcontext -a -t redis_db_t "/data/redis(/.*)?"
sudo restorecon -Rv /data/redis
firewalldの設定
ポートを開放する——正しい方法で
すべてのIPに対してport 6379を完全に開放するのは速いが安全ではない。rich ruleを使って内部サブネットのみを許可する:
# 192.168.1.0/24サブネットのみRedis接続を許可
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="6379" protocol="tcp" accept'
sudo firewall-cmd --reload
# ルールが適用されているか確認
sudo firewall-cmd --list-rich-rules
特定のアプリサーバーだけが接続する必要がある場合:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.50" port port="6379" protocol="tcp" accept'
sudo firewall-cmd --reload
rich rulesの代わりにinternalゾーンを使用する
専用の内部ネットワークインターフェース(例:eth1)がある場合、internalゾーンの方がすっきりしていて後から管理しやすい:
# 内部インターフェースをinternalゾーンに追加
sudo firewall-cmd --permanent --zone=internal --add-interface=eth1
# internalゾーンでRedisポートを開放
sudo firewall-cmd --permanent --zone=internal --add-port=6379/tcp
sudo firewall-cmd --reload
FedoraでのセキュアなRedisデプロイチェックリスト
午前2時のトラブルを何度か経験した後、本番環境で実行している手順がこれだ——この順番で:
# 1. インストール
sudo dnf install redis policycoreutils-python-utils -y
# 2. パスワードとbind addressでRedisを設定
sudo cp /etc/redis/redis.conf /etc/redis/redis.conf.bak
# /etc/redis/redis.confのbind、requirepass、maxmemoryを編集
# 3. サービスを起動
sudo systemctl enable redis --now
# 4. SELinuxがauditイベントを生成するよう約5分動かしてからpolicyを作成
sudo ausearch -m avc -ts recent | grep redis | audit2allow -M redis_custom
sudo semodule -i redis_custom.pp
# 5. 内部サブネットのファイアウォールを開放
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="6379" protocol="tcp" accept'
sudo firewall-cmd --reload
# 6. ネットワーク内の別のマシンからテスト
redis-cli -h 192.168.1.100 -p 6379 -a YourStrongPassword123! ping
セットアップ後の確認
# Redisが正しいインターフェースをリッスンしているか確認
sudo ss -tlnp | grep redis
# 認証テスト
redis-cli -h 127.0.0.1 -a YourStrongPassword123! ping
# サーバー情報を確認
redis-cli -a YourStrongPassword123! info server | grep -E "redis_version|uptime|connected_clients"
オプション:systemdでリソースを制限する
追加する価値のある制御レイヤーがもう一つある——Redisがメモリリークに遭遇したりリクエストのfloodを受けた場合に備えてsystemdレベルで制限する:
sudo systemctl edit redis
以下の内容を追加する:
[Service]
LimitNOFILE=65535
MemoryMax=512M
sudo systemctl daemon-reload
sudo systemctl restart redis
三つの保護レイヤー——SELinux、firewalld、パスワード認証——は互いを補完する。どれか一つを省いても不必要な脆弱点を生み出すことになる。最初に15分かけて正しくセットアップすれば、午前2時の2時間のデバッグを防げる。

