【2026年5月26日時点の情報です】
firewalldは、AlmaLinuxに標準で入っているファイアウォールです。サーバーに届くアクセスを、「どこから」「どのサービス(ポート)へ」で許可したり拒否したりできます。
今の私のサーバーは、公開をCloudflare Tunnelだけにしていて、ルーターでポートも開けていないので、firewalldは止めています(AlmaLinux 9 初期設定の記事)。この記事は、Cloudflare Tunnelを使う前に使っていた設定です。
次のような場合には、firewalldを使ってアクセスを絞っておくことをおすすめします。
- ルーターでポートを開けて、サーバーを公開する場合
- 家のLANに、知らない機器がつながる可能性がある場合
スクリプトは、CentOSで自宅サーバー構築を参考にして、自分の環境に合わせています。
この設定でできること
| 設定 | 内容 |
|---|---|
| 家のPCからのアクセス | 管理に使うPC(例:192.168.0.4)からは、すべて許可 |
| SSH | 管理に使うPCからだけ許可 |
| 日本国内のゾーン | 日本国内のIPアドレスをまとめたゾーンを作り、「日本国内からだけ許可」を設定できるようにする |
| 攻撃の多い国 | 攻撃元として多い国のIPアドレスからのアクセスは、返事をしずに捨てる |
| そのほか | SYN Flood攻撃などへの対策(カーネルの設定) |
1. ファイアウォールを設定するスクリプトを作る
このスクリプトは、実行するたびに今のゾーンの設定を消してから作り直します(rm -f /etc/firewalld/zones/*)。ほかの方法で設定したルールは消えるので、設定はこのスクリプトにまとめて書いてください。また、SSHでつないでいる場合は、管理用PCのIPアドレスを間違えると接続できなくなるので注意してください。
[root@almalinux ~]# vi firewall.sh ※ファイアウォール設定スクリプトを作成
#!/bin/bash
#---------------------------------------#
# 設定開始 #
#---------------------------------------#
# 内部ネットワークのアドレス
LOCALNET=192.168.10.0/24
# 管理に使うPCのIPアドレス
ADMINPC=192.168.10.4
#---------------------------------------#
# 設定終了 #
#---------------------------------------#
#
# ファイアウォールの設定を初期化
#
systemctl stop firewalld
rm -f /etc/firewalld/zones/*
rm -f /etc/firewalld/ipsets/*
systemctl start firewalld
firewall-cmd --reload >/dev/null
#
# 内部からのアクセスを許可
# ※LAN全体を許可する場合は LOCALNET の行の # を外す
#
#firewall-cmd --add-rich-rule="rule family="ipv4" source address="${LOCALNET}" accept" --permanent >/dev/null
firewall-cmd --add-rich-rule="rule family="ipv4" source address="${ADMINPC}" accept" --permanent >/dev/null # 管理用PCからはすべて許可
#
# SYN Cookiesを有効にする(TCP SYN Flood攻撃対策)
#
sysctl -w net.ipv4.tcp_syncookies=1 > /dev/null
sed -i '/net.ipv4.tcp_syncookies/d' /etc/sysctl.conf
echo "net.ipv4.tcp_syncookies=1" >> /etc/sysctl.conf
#
# ブロードキャストアドレス宛のpingには応答しない(Smurf攻撃対策)
#
sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1 > /dev/null
sed -i '/net.ipv4.icmp_echo_ignore_broadcasts/d' /etc/sysctl.conf
echo "net.ipv4.icmp_echo_ignore_broadcasts=1" >> /etc/sysctl.conf
#
# ICMP Redirectパケットは拒否
#
sed -i '/net.ipv4.conf.*.accept_redirects/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_redirects=0 > /dev/null
echo "net.ipv4.conf.$dev.accept_redirects=0" >> /etc/sysctl.conf
done
#
# Source Routedパケットは拒否
#
sed -i '/net.ipv4.conf.*.accept_source_route/d' /etc/sysctl.conf
for dev in `ls /proc/sys/net/ipv4/conf/`
do
sysctl -w net.ipv4.conf.$dev.accept_source_route=0 > /dev/null
echo "net.ipv4.conf.$dev.accept_source_route=0" >> /etc/sysctl.conf
done
#
# 国別のIPアドレスリストを取得
#
IP_LIST=/tmp/cidr.txt
CHK_IP_LIST=/tmp/IPLIST
if [ ! -f ${IP_LIST} ]; then
wget -q http://nami.jp/ipv4bycc/cidr.txt.gz
gunzip -c cidr.txt.gz > ${IP_LIST}
rm -f cidr.txt.gz
fi
rm -f ${CHK_IP_LIST}
#
# 日本国内のゾーン(domestic)を作成
#
firewall-cmd --new-zone=domestic --permanent >/dev/null
firewall-cmd --new-ipset=domestic --type=hash:net --permanent >/dev/null
domestic_ipset=`mktemp`
for addr in `cat ${IP_LIST} | grep ^JP | awk '{print $2}'`
do
echo ${addr} >> ${domestic_ipset}
done
firewall-cmd --ipset=domestic --add-entries-from-file=${domestic_ipset} --permanent >/dev/null
rm -f ${domestic_ipset}
firewall-cmd --zone=domestic --add-source=ipset:domestic --permanent >/dev/null
grep ^JP ${IP_LIST} >> $CHK_IP_LIST # 更新チェック用に保存
#
# 攻撃の多い国からのアクセスを捨てる
# ※警察庁の観測情報を参考に、攻撃元の上位の国を指定(定期的に見直す)
# https://www.npa.go.jp/bureau/cyber/koho/observation.html
#
DROP_COUNTRY_LIST=(BG HK RO CN GB)
firewall-cmd --new-ipset=drop_country --type=hash:net --permanent >/dev/null
drop_ipset=`mktemp`
for country in "${DROP_COUNTRY_LIST[@]}"
do
for addr in `cat ${IP_LIST} | grep ^${country} | awk '{print $2}'`
do
echo ${addr} >> ${drop_ipset}
done
grep ^${country} ${IP_LIST} >> ${CHK_IP_LIST}
done
firewall-cmd --ipset=drop_country --add-entries-from-file=${drop_ipset} --permanent >/dev/null
rm -f ${drop_ipset}
firewall-cmd --zone=drop --add-source=ipset:drop_country --permanent >/dev/null
#----------------------------------------------------------#
# 公開するサービスの設定(ここから) #
#----------------------------------------------------------#
# SSH(TCP22番)は管理用PCからだけ許可
# ※publicゾーンからsshを外さないと、どこからでもつながってしまう
firewall-cmd --remove-service=ssh --zone=public --permanent >/dev/null
firewall-cmd --zone=public --add-rich-rule="rule family="ipv4" source address="${ADMINPC}" service name="ssh" accept" --permanent >/dev/null
# Cockpit(TCP9090番)を使わない場合は閉じる
firewall-cmd --remove-service=cockpit --zone=public --permanent >/dev/null
# HTTP/HTTPS(TCP80番/443番)を日本国内からだけ許可
# ※ルーターでポートを開けてWebサーバーを公開する場合だけ
#firewall-cmd --add-service=http --zone=domestic --permanent >/dev/null
#firewall-cmd --add-service=https --zone=domestic --permanent >/dev/null
# SMTP(TCP25番)を許可
# ※メールを受け取るサーバーを公開する場合だけ(Gmailへの送信だけなら不要)
#firewall-cmd --add-service=smtp --zone=domestic --permanent >/dev/null
#firewall-cmd --add-service=smtp --zone=public --permanent >/dev/null
# SUBMISSION(TCP587番)を日本国内からだけ許可
# ※メールサーバーを公開する場合だけ
#firewall-cmd --add-service=smtp-submission --zone=domestic --permanent >/dev/null
#----------------------------------------------------------#
# 公開するサービスの設定(ここまで) #
#----------------------------------------------------------#
# 拒否したいIPアドレスからのアクセスを捨てる
# ※/root/deny_ip に1行ずつ書いておく(ファイルがなければ何もしない)
if [ -s /root/deny_ip ]; then
for ip in `cat /root/deny_ip`
do
firewall-cmd --zone=drop --add-source=${ip} --permanent >/dev/null
done
fi
# 設定を反映
firewall-cmd --reload >/dev/null公開するサービスは、「公開するサービスの設定」の範囲で、使うものだけ # を外します。元のスクリプトには、POP3やIMAP、VPNなどの設定例もあるので、必要なら参考にしたサイトで確かめてください。
国別のIPアドレスリストは、nami.jp で公開されているものを使っています。リストが取得できない場合は、日本国内のゾーンと、攻撃の多い国の設定は動きません。
2. IPアドレスリストを毎日更新する
国別のIPアドレスリストはよく更新されるので、毎日自動で更新を確かめ、変わっていたらファイアウォールのスクリプトを実行し直します。変更が多すぎるときは、実行せずにroot宛てにメールで知らせます。
[root@almalinux ~]# vi /etc/cron.daily/iplist_check.sh ※IPアドレスリストの更新チェックのスクリプトを作成
#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# 新旧のリストの差分がこの件数を超えたら、スクリプトを実行しない(0ならチェックしない)
SABUN_CHK=100
[ $# -ne 0 ] && SABUN_CHK=${1}
# IPアドレスリストを取得
IP_LIST=/tmp/cidr.txt
CHK_IP_LIST=/tmp/IPLIST
wget -q http://nami.jp/ipv4bycc/cidr.txt.gz
gunzip -c cidr.txt.gz > $IP_LIST
rm -f cidr.txt.gz
# チェック対象のリストを最新にする
rm -f IPLIST.new
for country in `awk '{print $1}' $CHK_IP_LIST | uniq`
do
grep ^$country $IP_LIST >> IPLIST.new
done
# 更新があるかチェック
diff -q $CHK_IP_LIST IPLIST.new > /dev/null 2>&1
if [ $? -ne 0 ]; then
if [ ${SABUN_CHK} -ne 0 ]; then
if [ $(diff $CHK_IP_LIST IPLIST.new | grep -E -c '<|>') -gt ${SABUN_CHK} ]; then
(
diff $CHK_IP_LIST IPLIST.new
echo
echo "firewall.sh not executed."
) | mail -s 'IPLIST UPDATE' root
rm -f IPLIST.new
exit
fi
fi
/bin/mv IPLIST.new $CHK_IP_LIST
sh /root/firewall.sh > /dev/null
else
rm -f IPLIST.new
fi
[root@almalinux ~]# chmod +x /etc/cron.daily/iplist_check.sh ※実行できるようにする3. ファイアウォールを有効にする
[root@almalinux ~]# bash firewall.sh ※ファイアウォール設定スクリプトを実行
[root@almalinux ~]# systemctl enable firewalld ※自動起動も設定4. 設定を確かめる
次の出力は、上のスクリプト(SSHとCockpitを閉じる行を有効にしたもの)を実行したときの表示例です。
[root@almalinux ~]# firewall-cmd --get-active-zones ※使われているゾーンを確認
domestic
sources: ipset:domestic
drop
sources: ipset:drop_country
public
interfaces: enp0s3
[root@almalinux ~]# firewall-cmd --list-all --zone=drop ※dropゾーンを確認
drop
target: DROP ← アクセスを捨てる
sources: ipset:drop_country ← 攻撃の多い国のIPアドレス
(以下省略)
[root@almalinux ~]# firewall-cmd --list-all --zone=public ※publicゾーンを確認
public (active)
target: default ← 許可していないアクセスは拒否
interfaces: enp0s3
services: dhcpv6-client ← ssh や cockpit が入っていないことを確かめる
(途中省略)
rich rules:
rule family="ipv4" source address="192.168.0.4" service name="ssh" accept
rule family="ipv4" source address="192.168.0.4" acceptpublicゾーンの services に ssh が残っていると、SSHは管理用PC以外からもつながります。入っていないことを必ず確かめてください。
まとめ
firewalldで、SSHを管理用PCだけに許可し、攻撃の多い国からのアクセスを捨て、公開するサービスを日本国内からだけに絞れるようにしました。
今の私のサーバーは、Cloudflare Tunnelで公開しているので、firewalldは止めています。Cloudflare Tunnelの仕組みは自宅ネットワークの記事で紹介しています。



コメント