ufw enableしたから安全」と思い込んで、実は穴が空いたままのUbuntuサーバーは珍しくありません。UFW(Uncomplicated Firewall)は設定を簡単にする代わりに、内部で実際に通信を制御しているiptables(またはnftables)との間にズレが生まれやすい構造になっています。この記事では、Ubuntu 24.04を基準に ufw status verboseiptables -L -n の出力を実際に突き合わせて、「有効にしたつもり」の設定漏れを自分で見分ける手順をまとめます。

UFWは「有効」でも穴が空くことがある理由

UFWは自分でパケットを処理しているわけではなく、Linuxカーネルのパケットフィルタ(iptables/nftables)にルールを書き込むための操作しやすい窓口(フロントエンド)です。つまり「UFWの設定」と「実際にカーネルが使っているルール」は別物で、両者がズレていてもufw statusは平気で「active」と表示し続けます。

穴が空く典型パターン

パターン

何が起きるか

Dockerが動いている

Dockerは自分でiptablesにDOCKER-USERなどのルールを追加し、UFWのルールより先に通信を許可してしまうことがある。UFWで塞いだつもりのポートがコンテナ公開ポート経由で開いてしまう

IPv6を見落とす

/etc/default/ufwIPV6=yes設定に関わらず、IPv4だけ確認して満足してしまう

他のツールが直接iptablesを書き換える

導入したミドルウェアやインストールスクリプトがUFWを経由せず直接ルールを追加し、UFW側の一覧には出てこない

UFWの再起動漏れ

ルール変更後にリロードし忘れ、古いルールが残ったまま新ルールと混在する

sudo ufw status verboseで自分が設定したルールを確認する

まず「自分がUFWにどう指示したか」を確認します。

sudo ufw status verbose

このコマンドは、UFWが記憶している許可・拒否ルールと、デフォルトポリシー(何も一致しなかった通信をどう扱うか)を表示します。sudoが必要ですが、設定を変更するコマンドではないため何度実行しても安全です。

出力例:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80,443/tcp                 ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)
80,443/tcp (v6)             ALLOW IN    Anywhere (v6)

判断基準は次の2点です。

  • Status: activeになっているか(inactiveならUFW自体が動いていないので、下の突き合わせ以前の問題)
  • Default: deny (incoming)になっているか。ここがallow (incoming)だと、許可ルールに書いていないポートまで全部開いている状態

この一覧に見覚えのないポートが並んでいたら、それは「UFW側で誰かが許可した」記録です。まずsudo ufw status numberedで番号を確認し、心当たりがなければsudo ufw delete [番号]で削除します(削除もUFW経由の操作なので取り消しやすく、後から同じルールをufw allowで入れ直せば元に戻せます)。

sudo iptables -L -nで実際に効いているルールを確認する

次に「カーネルが実際に何を通しているか」を確認します。

sudo iptables -L -n

-Lは現在のルール一覧表示、-nはホスト名やサービス名を名前解決せず数値のまま表示するオプションです(名前解決を待つと表示が遅くなるため、点検用途では-nを付けるのが基本)。

出力例(UFW管理下の場合、INPUTチェーンからufw独自のチェーンに処理が渡る形になります):

Chain INPUT (policy DROP)
target          prot opt source     destination
ufw-before-input  all  --  0.0.0.0/0  0.0.0.0/0
ufw-after-input   all  --  0.0.0.0/0  0.0.0.0/0

Chain ufw-user-input (1 references)
target     prot opt source     destination
ACCEPT     tcp  --  0.0.0.0/0  0.0.0.0/0   tcp dpt:22
ACCEPT     tcp  --  0.0.0.0/0  0.0.0.0/0   tcp dpt:80
ACCEPT     tcp  --  0.0.0.0/0  0.0.0.0/0   tcp dpt:443

判断基準は次の2点です。

  • 1行目Chain INPUT (policy DROP)policyDROPREJECTになっているか(ACCEPTになっていたら、UFWが「deny」と言っていてもカーネルレベルでは全通しの状態)
  • ufw-user-inputチェーン以外の場所(DOCKERや独自チェーン名)に、見覚えのないACCEPTルールが挟まっていないか

iptables -Lはnftables経由の表示になっている点に注意

Ubuntu 24.04以降、iptablesコマンドはデフォルトでnftablesバックエンド(iptables-nft)を使う互換シムになっています。sudo iptables -Vを実行して

iptables v1.8.10 (nf_tables)

のように末尾が(nf_tables)となっていれば、実体はnftablesのルールセットです。より正確に見たい場合はsudo nft list rulesetで直接nftables側の全ルールを確認できます。Canonicalが2026年4月にリリースしたUbuntu 26.04 LTSはセキュリティ強化を掲げる中でnftables系ツールへの依存をさらに強める方向にあり、24.04環境でも「iptablesコマンドの裏側はnftables」という前提で見ておくと今後の移行でも読み方に迷いません。

2つを突き合わせて「穴」を見分ける

ufw status verboseとiptables -L -nを並べて、次の対応関係が崩れていないかを確認します。

確認項目

ufw status verboseでの表示

iptables -L -nでの対応

ズレていたら

デフォルトポリシー

Default: deny (incoming)

Chain INPUT (policy DROP)

iptables側がACCEPTなら、他のツールがポリシーを書き換えている

個別ポートの許可

To の一覧に載っているポート

ufw-user-inputチェーン内のACCEPT行

ufw側に無いのにiptables側にACCEPTがあれば、UFWを経由しない野良ルール

IPv4/IPv6

末尾に(v6)と付く行の有無

ip6tables -L -nの出力

ufwでv6の許可を出していないのにip6tables側で開いていれば要調査

Docker公開ポート

UFWのルールに記載なし

DOCKER-USER・DOCKERチェーンにACCEPT

UFWで塞いだつもりのポートがコンテナ経由で外部に開いている典型例

ズレを見つけたときの次の一手は次の通りです。

  1. そのポートやIPで待ち受けているプロセスをsudo ss -tulpnで特定し、心当たりのあるサービスかを確認する
  2. 身に覚えのない許可ルールであれば、追加した記憶のあるツール(Docker・Snap・VPNソフトなど)の設定変更履歴を洗う
  3. Dockerが原因の場合は、UFWとDockerの競合は既知の問題として広く報告されているため、対応方法(DOCKER-USERチェーンでの制御やdaemon.jsonでのiptables管理設定変更など)を調べてから対処する。勢いで削除するとコンテナの外部公開自体が止まる場合がある

ログイン試行の点検も合わせて行いたい場合は、journalctlでSSH侵入後のauthorized_keys改ざん確認2026/8の手順で認証ログ側の異常有無も確認しておくと、ファイアウォールの穴が実際に悪用された形跡がないかまで一通り点検できます。

確認だけなら安全。設定変更するときの注意

  • ufw status verboseiptables -L -nはどちらも表示コマンドで、システムの設定を一切変更しません。sudoは必要ですが、何度実行しても安全です
  • ルールを削除・変更する場合は、必ず今の状態を保存してから行います:sudo iptables-save > ~/iptables_backup_$(date +%Y%m%d).rulesで保存し、戻したいときはsudo iptables-restore < ~/iptables_backup_日付.rulesで復元できます
  • UFW側の変更で不安な場合はsudo ufw disableでいったん無効化してから作業し、sudo ufw enableで戻す、という切り戻し手順を用意しておくと安心です。ただし無効化中は無防備な状態になるため、作業は手短に済ませます
  • SSH接続で作業している場合、ルール変更でSSHポート自体を塞いでしまうと接続が切れて元に戻せなくなります。変更前に別ウィンドウでもう1つSSHセッションを開いておくか、コンソール(VNC等)からアクセスできる状態を確保してから作業してください

Debianや他ディストリでの違い

  • Debianには標準でUFWが入っていないため、sudo apt install ufwでインストールする必要があります(Ubuntuはデフォルトで導入済み)
  • iptablesがiptables-legacyとiptables-nftのどちらで動いているかは環境によって異なるため、sudo update-alternatives --list iptablesで確認できます。legacy側で動いている環境ではnft list rulesetには何も表示されない点に注意してください
  • firewalldを使っている場合(RHEL系に多い)は、UFWではなくsudo firewall-cmd --list-alliptables -L -n(またはnft list ruleset)の突き合わせに読み替えます

他の設定漏れが心配な場合は、sudo -lとNOPASSWDを点検2026年8月版もあわせて確認しておくと、権限まわりの見落としも一通りカバーできます。

まとめ

UFWの「active」表示は、あくまでUFW自身が把握しているルールが有効という意味であり、カーネルが実際に処理しているルールと一致している保証ではありません。sudo ufw status verboseで自分の設定意図を確認し、sudo iptables -L -n(Ubuntu 24.04以降は実体がnftablesの互換表示である点に注意)で実際の適用状況を確認して、両者のポリシーとポート一覧を突き合わせる習慣をつけることで、Docker連携や野良ルールによる「開けたつもりが開いていない/塞いだつもりが塞がっていない」を自分で発見できます。確認作業自体はシステムを変更しないため、まずは今の環境で両方のコマンドを実行し、表の対応関係を照らし合わせるところから始めてみてください。