.
2025/11/04 以下追記
[ 03. 海外からの接続ブロック設定 ]
・更新エラー時復旧用の iptables バックアップ処理の追加
[ 06. ルール適用エラーが発生した場合 ]
・更新エラー時の説明と復旧方法を追記
2025/11/02 以下訂正
[ 02. 事前設定 ]
誤:
以下を実施し、after.init を実行可能状態にしておきます
# chmod +x /etc/ufw/after.init
# chmod +x /etc/ufw/after.init.drop_except_jp
(ファイル (after.init.drop_except_jp) 作成されていない状態で、chmod を行っている)
正:
以下を実施し、after.init と after.init.drop_except_jp を 実行可能状態にしておきます
# chmod +x /etc/ufw/after.init
# touch /etc/ufw/after.init.drop_except_jp
# chmod +x /etc/ufw/after.init.drop_except_jp
新規環境構築時は、after.init.drop_except_jp が存在してないため、
初回は、事前設定として最初に touch で手動作成するように修正いたしました
また、after.init.drop_except_jp の chmod は、
drop_except_jp.sh 内でも実行しますが、そのまま初回時も実行とします
失礼いたしました
以前の記事
f16: xserver vps + ubuntu + 海外アクセス抑止 + 自動更新
https://qiita.com/cxfgp/items/ff18545adb3c1dc1bec2
の派生メモです
前回は ufw も使用しますが、
基本的には、iptables ダイレクト更新版でしたが、
少しわかりにくい部分があり、
ubuntu (debian系) なので、
シンプルな ufw 制御版に切り替えました
実施することは基本同じです
・ubuntu + ufw にて海外からのアクセス抑止設定を行います
・それらの定期自動更新の設定を行います
[ 00. メニュー ]
01. キッチン
02. 事前設定
03. 海外からの接続ブロック設定
04. ufw 再起動・設定更新
05. 自動更新 設定
06. ルール適用エラーが発生した場合
07. デザート
08. 参考
[ 01. キッチン ]
・Xserver VPS / 2GB プラン
-> Ubuntu 22.04 (64bit)
[ 02. 事前設定 ]
vi などで、/etc/ufw/after.init の start) に以下追記します
/etc/ufw/after.init.drop_except_jp
start)
# typically required
/etc/ufw/after.init.drop_except_jp
;;
以下を実施し、after.init と after.init.drop_except_jp を 実行可能状態にしておきます
# chmod +x /etc/ufw/after.init
# touch /etc/ufw/after.init.drop_except_jp
# chmod +x /etc/ufw/after.init.drop_except_jp
[ 03. 海外からの接続ブロック設定 ]
以下の実行で、
after.init (正確には after.init.drop_except_jp) に、
許可するポートや IP、例外などのルール設定を書き込みます
正確にいうと、海外(国外)抑止 (ブラックリスト) というよりも、
国内・例外許可 (ホワイトリスト) です
※日付や時間の表示形式は各環境により
違う場合がありますのでご注意ください
#!/bin/bash
# set script dir / log / init / cidr
s_dir=$(cd $(dirname $0) && pwd)
logs1=${s_dir}/logs/log-1.log
AFTER_INIT=/etc/ufw/after.init.drop_except_jp
cid1=${s_dir}/cidr.txt.gz
cid2=${s_dir}/cidr.txt
cid2tmp=${cid2}.tmp
#----------------------------------------
# バックアップ ( iptables backup )
#----------------------------------------
iptables-save > /home/userA/iptables-backup.$(date +%F)
#----------------------------------------
# 古い CIDR ファイル削除
#----------------------------------------
for fe2 in "$cid1" "$cid2"; do
if [ -f "$fe2" ]; then
rm -rf "$fe2"
sleep 1s; dates1=$(date +"%Y/%m/%d %T")
echo "$dates1 : delete OK: $fe2" >> "$logs1"
else
sleep 1s; dates1=$(date +"%Y/%m/%d %T")
echo "$dates1 : delete NG: not found $fe2" >> "$logs1"
fi
done
#----------------------------------------
# 新しい CIDR ファイル取得
#----------------------------------------
wget -q -N http://nami.jp/ipv4bycc/cidr.txt.gz -O "$cid1"
wget_status=$?
if [ $wget_status -eq 0 ] && [ -f "$cid1" ]; then
sleep 2s; dates2=$(date +"%Y/%m/%d %T")
echo "$dates2 : dl: OK: cidr.txt.gz" >> "$logs1"
else
sleep 2s; dates2=$(date +"%Y/%m/%d %T")
echo "$dates2 : dl: NG: wget failed ($wget_status)" >> "$logs1"
exit 1
fi
#----------------------------------------
# cidr.txt.gz を解凍
#----------------------------------------
if gunzip -f -c "$cid1" > "$cid2tmp"; then
mv "$cid2tmp" "$cid2"
sleep 2s; dates3=$(date +"%Y/%m/%d %T")
echo "$dates3 : OK: to gunzip cidr.txt.gz" >> "$logs1"
else
rm -rf "$cid2tmp"
sleep 2s; dates3=$(date +"%Y/%m/%d %T")
echo "$dates3 : NG: failed to gunzip cidr.txt.gz" >> "$logs1"
exit 1
fi
#----------------------------------------
# after.init にルール適用
#----------------------------------------
if [ -f "$cid2" ]; then
# after.init ファイル出力(ufw 用)
{
echo "#!/bin/sh"
echo "# drp_excep $(date +"%Y/%m/%d %T")"
echo ""
# 許可ポート設定
echo "ufw allow 80/tcp"
echo "ufw allow 443/tcp"
echo ""
# 例外許可IP設定
FIXED_IPS=(
# (例 google 一部)
"35.190.247.0/24" "35.191.0.0/16" "64.233.160.0/19" "66.102.0.0/20"
)
for ip2 in "${FIXED_IPS[@]}"; do
echo "ufw allow from $ip2"
done
# 国内許可IP設定
sed -n 's/^JP\t//p' "$cid2" | while read address; do
echo "ufw allow from $address"
done
} > "$AFTER_INIT"
chmod +x "$AFTER_INIT"
dates4=$(date +"%Y/%m/%d %T")
echo "$dates4 : OK: ufw after.init file updated" >> "$logs1"
else
dates4=$(date +"%Y/%m/%d %T")
echo "$dates4 : NG: not found cidr.txt or not a file" >> "$logs1"
exit 1
fi
[ 04. ufw 再起動・設定更新 ]
[ 03. 海外からの接続ブロック設定 ] にて
after.init (after.init.drop_except_jp)
に設定したルールを有効にするために、以下を実施します
やっていることは、
ufw の再起動 ( systemctl restart ufw ) だけ です
自動実行を想定しているため、付随で起動状況チェックしてます
( 後述しておりますが、after.init のルール適用に
30分くらいかかるため、プロンプトでの手動実行では
systemctl restart ufw 実行後に処理が返ってこないまま固まります
cron 実行では、およそ、30分後に、以下がログに書き込まれました
2025/10/30 03:46:40 : end ufw re-start
ので、テストを行う場合は、適用ルールを数件に絞るか、
cron で行ったほうがよさそうです )
#!/bin/sh
# set script dir / log
s_dir=$(cd $(dirname $0) && pwd)
logs2=${s_dir}/logs/log-2.log
logs3=${s_dir}/logs/log-3.log
#----------------------------------------
# ufw 再起動
#----------------------------------------
dates1=`date +"%Y/%m/%d %T"`
echo "$dates1 : str ufw re-start" >> $logs2
systemctl restart ufw
sleep 20s; dates2=`date +"%Y/%m/%d %T"`
echo "$dates2 : end ufw re-start" >> $logs2
#----------------------------------------
# ufw 起動状況確認
#----------------------------------------
# out ufw status to check log
systemctl status ufw -l> $logs3
sleep 2s; dates3=`date +"%Y/%m/%d %T"`
# set date(ymd) for checking ufw status is active or not
dates4=`date +"%Y-%m-%d"`
if grep -q "active (exited)" $logs3; then
comp4=`grep "Active:" $logs3 | { IFS= read -r lines && trimmed_lines=$(echo "$lines" | awk '{$1=$1};1'); echo "$trimmed_lines"; }`
echo "$dates3 : $comp4" >> $logs2
get_date=$(echo "$comp4" | awk '{print $6}')
# print $6 -> 2025-10-31 (以下 6項目目に記載の日付)
# Active: active (exited) since Fri 2025-10-31 03:36:16 JST; 9h ago
if [ "$get_date" = "$dates4" ]; then
echo "$dates3 : OK: ufw status: active (exited) + $get_date" >> $logs2
else
echo "$dates3 : NG: ufw status: active (exited) + date NOT-FOUND: $dates4" >> $logs2
exit 1
fi
else
grep "Active:" $logs3 | { IFS= read -r lines && trimmed_lines=$(echo "$lines" | awk '{$1=$1};1'); echo "$dates3 : NG: NOT-FOUND active: $trimmed_lines"; } >> $logs2
exit 1
fi
[ 05. 自動更新 設定 ]
実行後、after.init に設定した項目は以下で確認できます
# ufw status
cron の自動設定を行います
cron 例 ( root側 )
月、木 03:00am -> drop_except_jp.sh
月、木 03:30am -> restart_ufw.sh
[ 設定 ]
# crontab -u root -e
00 3 * * 1,4 bash /home/userA/drop_except_jp.sh
30 3 * * 1,4 sh /home/userA/restart_ufw.sh
※ drop_except_jp.sh は、bash に切り替えましたので、
bash /home/userA/drop_except_jp.sh です
※ restart_ufw.sh は、変わらず
sh /home/userA/drop_except_jp.sh です
[ 確認 ]
# crontab -l
( よくいわれます、crontab -r の削除オプションにはご注意ください )
ちなみに、
# systemctl is-enabled ufw
の値が enabled になっている場合、OSリブート後にも、
ufw の起動と、after.init の読み込み
が処理されますのでご注意ください
[ 06. ルール適用エラーが発生した場合 ]
drop_except_jp.sh の実行により、
after.init.drop_except_jp にルールが書き込まれ、
・restart_ufw.sh の実行
・systemctl restart ufw の直接実行
・OS 再起動時 (uwf enabled の場合)
いずれかの実行により、適用ルールが ufw を通して、
iptables に更新されるのですが、
まれに適用時エラーになることがあります
その際、ルールが空で更新された、ないしは、
ポート許可設定が更新されなかった場合は、
web アクセスも、ssh 接続も不可になります
復旧方法の事例が以下となります
A. VPS などの web コンソール上から、
シリアル接続にて、コンソールにログイン
B. drop_except_jp.sh で取得した
iptables backup のバックアップファイル
を用いてリストアを実施
( リストア例 )
cd で、バックアップファイル階層まで移動後、
NG になる以前のファイルを指定し、以下を実行します
# iptables-restore < iptables-backup.2025-10-30
C. リストア実施後、いずれかの実行
・restart_ufw.sh の実行
・systemctl restart ufw の直接実行
・OS 再起動時 (uwf enabled の場合)
これで NG になるまえのルールに戻りますので、
ssh 接続可能になったか等の確認を行います
(後述しますが、環境により、ルール適用に時間がかかりますので、
焦って即確認などをおこなわずに、通常適用完了時同等の完了まで
待ってから接続確認等を行います)
[ 07. デザート ]
今回確認しました CIDR の JP IP 件数
および、ルール適用状況は、以下の通りです
==========================================
2025/09/12 cidr.txt / JP IP -> 3154 件
==========================================
ufw 再起動後のルール適用時間
( ufw restart )
2025/10/30 03:20:01 : str ufw re-start (開始)
2025/10/30 03:46:40 : end ufw re-start (終了)
==========================================
今回の環境では、ざっくり、3000件 30分 (100件/分) でした
(ufw 再起動および、OS 再起動時に、バックグラウンドで30分処理)
環境にもよりますが、
ルールが膨大になることによる処理負荷の増大
および、
ufw ( iptables ) のルール数制限等にはご注意ください
[ 08. 参考にさせていただいた記事 ]
(こちらの記事は iptables 更新版です)
.