2026年5月24日

2026年5月24日

ファイアウォールで特定IPだけ許可する設定(ufw・firewalld・nftables)

SSH や管理画面、データベースのポートを「自分のIPアドレスからだけ接続できる」ようにするには、ファイアウォールで「特定の送信元IPを許可するルール」を先に入れ、そのあとで「それ以外を拒否する」順番で設定します。順番を逆にすると、作業中の自分の接続まで切れてしまいます。この記事では、締め出しを防ぐ準備から、ufw・firewalld・nftables それぞれの書き方、クラウドのセキュリティグループや Docker との関係、確認方法までを説明します。

先に決めておくこと:何を、誰に許可するのか

IP制限は「どのポートを」「どの送信元に」開けるかを決める作業です。Webサイトとして公開している80/443番は、一般の訪問者が接続するので通常は全体に開けたままにします。特定IPだけに絞る対象になるのは、たとえば次のようなものです。

  • SSH(22番、または変更したポート)
  • データベース(MySQL/MariaDB の3306番など。そもそも外部に開ける必要がないことが多い)
  • 監視エージェントや管理ツールのポート
  • 検証環境のWebサイト全体

WordPress のログイン画面(wp-login.php)や管理画面だけを制限したい場合は、ポート単位で動くファイアウォールではなく、Webサーバー(Nginx や Apache)の設定で URL ごとに制限するのが向いています。ファイアウォールで443番を絞ると、サイト全体が見えなくなるためです。

許可するIPアドレスは、自宅や会社の回線が「固定IP」かどうかを確認しておきます。一般的な家庭向け回線は、再接続などでIPアドレスが変わることがあります。IPが変わる回線で厳しく絞ると、ある日突然SSHに入れなくなります。その場合は、固定IPのある踏み台サーバーやVPN(WireGuard など)を経由し、許可するのは踏み台やVPNのアドレスだけにする方法が現実的です。

締め出しを防ぐ準備

リモートのサーバーでファイアウォールを触るときは、設定を誤ると自分のSSH接続が切れ、元に戻せなくなることがあります。作業の前に次の準備をしてください。

  • VPS やクラウドの管理画面から使える「コンソール接続」(ブラウザ上のシリアルコンソールなど)の入り方を確認しておく
  • 現在のルールを保存しておく(後述のコマンドで出力をファイルに残す)
  • SSH のセッションを2つ開いておき、片方で設定、もう片方で接続が維持されるかを確かめる
  • 自分の今のグローバルIPを、サーバー側から確認する

サーバー側から見た自分の送信元IPは、SSHで接続した状態で次のように確認できます。

# SSH 接続元のIPアドレス(左側が自分の送信元)
echo "$SSH_CLIENT"
who -m

ブラウザで「IP確認サイト」を見る方法もありますが、会社のプロキシやVPNを通っていると、サーバーに届くアドレスと異なることがあります。許可ルールには、サーバー側で見たアドレスを使ってください。

ufw(Ubuntu・Debian)で特定IPだけ許可する

ufw はルールを上から順に評価し、最初に一致したルールが適用されます。そのため「許可したいIP」のルールが、より広い拒否ルールよりも上にある必要があります。

# 1. 現在の状態を確認(無効なら inactive と表示される)
sudo ufw status verbose

# 2. 既定の方針:受信は拒否、送信は許可
sudo ufw default deny incoming
sudo ufw default allow outgoing

# 3. 自分のIP(例:203.0.113.10)からの SSH だけ許可
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp comment 'admin ssh'

# 4. 公開している Web は全体に許可
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# 5. ルールを確認してから有効化
sudo ufw show added
sudo ufw enable

すでに 22/tcp を全体に許可するルール(OpenSSH のアプリケーションプロファイルなど)がある場合は、IP限定のルールを追加しただけでは意味がありません。新しいルールで接続できることを確かめてから、全体許可のルールを削除します。

sudo ufw status numbered
# 番号を確認してから削除(例:3番)
sudo ufw delete 3

ネットワーク単位で許可するなら 203.0.113.0/24 のようにCIDR表記で書けます。IPv6 で接続している場合は IPv6 のアドレスも同じように許可が必要です。ufw の IPv6 対応は /etc/default/ufw の IPV6=yes で有効になります(多くの環境で既定値です)。

firewalld(RHEL・AlmaLinux・Rocky Linux など)で特定IPだけ許可する

firewalld は「ゾーン」という単位で、どの送信元やインターフェースにどのサービスを許可するかを管理します。管理用のゾーンを作り、そこに許可するIPとSSHを登録して、公開用のゾーンからSSHを外す、という形にすると整理しやすくなります。

# 現在の設定を確認
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --zone=public --list-all

# 管理用ゾーンを作成し、許可するIPと SSH を登録
sudo firewall-cmd --permanent --new-zone=admin
sudo firewall-cmd --permanent --zone=admin --add-source=203.0.113.10/32
sudo firewall-cmd --permanent --zone=admin --add-service=ssh
sudo firewall-cmd --reload

# admin ゾーン経由で SSH できることを、別セッションで確かめてから
# 公開用ゾーンの SSH 許可を外す
sudo firewall-cmd --permanent --zone=public --remove-service=ssh
sudo firewall-cmd --reload

送信元アドレスが admin ゾーンに登録されているIPからの通信は admin ゾーンのルールで処理され、それ以外は public ゾーンのルールで処理されます。現在の firewalld では、admin ゾーンで許可していない通信は public ゾーンへ回されずに拒否される動作が基本です(古い版にあった「ゾーンドリフト」は無効化されています)。そのため、管理用のIPから自分のサイト(80/443)も見るなら、admin ゾーンにも --add-service=http と --add-service=https を追加しておきます。--permanent を付けたルールは再読み込み後に反映され、付けないルールは実行中の設定だけに入り、再起動で消えます。

試しに入れてみて問題があれば自動で消えるようにしたい場合は、--permanent を付けずに --timeout を指定する方法もあります。

# 5分間だけ有効なルール(実行中の設定のみ)
sudo firewall-cmd --zone=admin --add-service=ssh --timeout=300

trusted ゾーンに送信元IPを入れる方法もよく紹介されますが、trusted はすべての通信を許可するゾーンです。SSH だけを許可したい場合は、上のように必要なサービスだけを持つゾーンを使う方が意図に合います。

nftables で直接書く場合

ufw や firewalld を使わず、nftables のルールを直接管理する場合は、許可するIPを「セット」にまとめると管理しやすくなります。

#!/usr/sbin/nft -f
# /etc/nftables.conf の例(既存のルールを置き換えるので、適用前に内容を必ず確認する)
flush ruleset

table inet filter {
    set admin_v4 {
        type ipv4_addr
        flags interval
        elements = { 203.0.113.10, 198.51.100.0/24 }
    }

    chain input {
        type filter hook input priority 0; policy drop;

        ct state established,related accept
        ct state invalid drop
        iif "lo" accept
        meta l4proto { icmp, ipv6-icmp } accept

        ip saddr @admin_v4 tcp dport 22 accept
        tcp dport { 80, 443 } accept
    }
}
# 構文チェック(適用はしない)
sudo nft -c -f /etc/nftables.conf
# 適用
sudo nft -f /etc/nftables.conf

既存の接続を許可する ct state established,related accept を入れ忘れると、適用した瞬間に今のSSHセッションの応答が通らなくなることがあります。ICMP(特に IPv6 の ICMPv6)を止めると、IPv6 の通信自体が不安定になるので、通常は許可しておきます。ufw や firewalld が動いている環境で nftables を直接書き換えると、管理ツールのルールと混ざって分かりにくくなるため、どれか1つに統一してください。

クラウドのセキュリティグループや Docker との関係

クラウドやVPSのパケットフィルター

AWS のセキュリティグループや、VPS 事業者の管理画面にあるパケットフィルターは、OS のファイアウォールより手前で通信を止めます。どちらか一方だけで制限していても動作しますが、OS 側とクラウド側の両方で同じ方針にしておくと、片方の設定ミスがあっても守りが残ります。接続できないときは、両方のルールを確認するのが切り分けの基本です。

Docker が公開したポート

Docker で -p 8080:80 のように公開したポートは、Docker が iptables(または nftables)のルールを直接追加するため、ufw のルールを通らずに外部へ開いてしまうことがあります。ufw で拒否しているつもりでもコンテナのポートに外から接続できる、という状況はこれが原因であることが多いです。対策としては、コンテナを 127.0.0.1:8080:80 のようにローカルだけに公開する、Docker のドキュメントで説明されている DOCKER-USER チェーンに制限ルールを入れる、といった方法があります。Docker のバージョンによってファイアウォールとの連携の仕組みが変わることがあるため(2026年10月現在)、利用中のバージョンのドキュメントを確認してください。

CDN を前に置いている場合

Cloudflare などの CDN を経由している場合、Webサーバーに届く通信の送信元は CDN のIPアドレスです。オリジンサーバーの80/443を CDN からの接続だけに絞ることもできますが、CDN のIP範囲は変わることがあるので、公式に公開されている一覧を定期的に取り込む仕組みが必要です。

設定後の確認

設定が終わったら、許可したIPからは接続でき、それ以外からは接続できないことを、両方の立場から確認します。

# サーバー側でルールを確認
sudo ufw status verbose                     # ufw
sudo firewall-cmd --zone=admin --list-all   # firewalld
sudo nft list ruleset                       # nftables

# 許可していない別の回線(スマートフォンのテザリングなど)から
nc -vz -w 3 203.0.113.200 22   # 203.0.113.200 はサーバーのIPの例

許可していない回線から試してタイムアウトすれば、制限が効いています。最後に、サーバーを再起動してもルールが残るかを、コンソール接続を用意したうえで一度確かめておくと安心です。

まとめ

  • 先に「許可するIPのルール」を入れ、接続できることを確認してから「それ以外の拒否」や全体許可の削除を行います
  • 作業前にコンソール接続の方法を確認し、SSHセッションを2つ開いておくと締め出しを防げます
  • ufw は上から順に評価、firewalld は送信元ごとのゾーン、nftables はセットでまとめると管理しやすくなります
  • IPが変わる回線では、踏み台サーバーやVPNのアドレスを許可する方法が現実的です
  • クラウドのセキュリティグループ、Docker の公開ポート、CDN 経由の送信元IPも合わせて確認します

お気軽にご相談ください

お見積りへ お問い合わせへ
▲