ufwの設定方法:Linuxのサーバーファイアウォールとnftablesの基礎
ufwの設定は3つの手順で済みます。デフォルトのポリシーを設定し(sudo ufw default deny incoming と sudo ufw default allow outgoing)、SSHと必要なポートを許可し(sudo ufw allow 22/tcp、sudo ufw allow 443/tcp)、最後に sudo ufw enable でファイアウォールを有効にします。ルールは sudo ufw status numbered で確認します。内部ではufwがiptablesまたはnftablesでnetfilterを制御しています。
Linuxのファイアウォールは、サーバーに届くネットワークパケットのうち、どれを通し、どれを破棄するかを決めます。実際の処理はカーネルのnetfilterというサブシステムが行い、それを操作するのが低レベルの iptables や nftables、そしてその上位ツールの ufw(Uncomplicated Firewall)です。UbuntuやDebianのほとんどのサーバーでは、ufwの設定は5分程度で終わります。受信をすべて閉じ、SSHとサービスのポートを開けて、有効にするだけです。以下では、その手順、よくある間違い、そして内部の仕組みを理解するための最低限のnftablesを紹介します。
Linuxのファイアウォールの仕組み
パケットのフィルタリングはカーネル内で行われます。これがnetfilterです。netfilterは、ホスト自身へ向かう受信トラフィック、送信トラフィック、転送トラフィック(forward)のための処理ポイント(フック)を提供します。ユーザー空間のツールは、それらのフックに対するルールをカーネルに書き込むだけです。
| ツール | レベル | 使う場面 |
|---|---|---|
ufw | 上位ツール。シンプルな構文 | UbuntuやDebianの単体サーバー、基本的なルール |
firewalld | ゾーンを持つ上位ツール | RHEL、Rocky、Fedora |
nftables(nft) | 低レベル。最新 | 複雑なルール、NAT、アドレスのセット |
iptables | 低レベル。非推奨へ移行中 | 古いシステムやスクリプト |
重要なのは、管理ツールを1つだけ使うことです。ufwと手動のiptablesで同時にルールを変更すると、互いに上書きし合い、動作が予測できなくなります。
ufwのインストールと確認
Ubuntuではufwが通常すでにインストールされていますが、無効になっています。Debianでは別途インストールします。
$ sudo apt update
$ sudo apt install ufw
$ sudo ufw status
Status: inactive
inactive は、ufwのルールが適用されていないことを意味します。まだ有効にしないでください。先にSSHを許可しておかないと、リモートのサーバーで自分自身の接続を遮断してしまいます。
サーバーでのufw設定の手順
手順1:デフォルトポリシー
デフォルトポリシーは、どのルールにも一致しなかったパケットをどう扱うかを決めます。サーバーにとって安全な方法は、受信を拒否し、送信を許可することです。
$ sudo ufw default deny incoming
Default incoming policy changed to 'deny'
$ sudo ufw default allow outgoing
Default outgoing policy changed to 'allow'
自分から始めた送信接続への応答は自動的に通過します。ufwが接続の状態を追跡している(connection tracking)ためです。応答のためにポートを開ける必要はありません。
手順2:SSHを許可する
$ sudo ufw allow OpenSSH
Rules updated
Rules updated (v6)
OpenSSH はアプリケーションプロファイルです。SSHが標準以外のポートで待ち受けている場合は、ポートを明示的に許可してください(例:sudo ufw allow 2222/tcp)。sshdが実際にどのポートで待ち受けているかは、sudo ss -tlnp | grep sshd で確認できます。
手順3:サービスのポートを開ける
$ sudo ufw allow 80/tcp
$ sudo ufw allow 443/tcp
プロトコルを指定してください。/tcp を省略すると、ufwはTCPとUDPの両方でポートを開けます。使わないUDPのポートを開けておく必要はありません。
手順4:ファイアウォールを有効にする
$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup
ufwはすぐに起動し、以降は再起動のたびに自動で有効になります。現在のSSHセッションは閉じないでください。別のセッションを開いて、接続できることを確認してください。
手順5:ルールを確認する
$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp (OpenSSH) ALLOW IN Anywhere
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (OpenSSH (v6)) ALLOW IN Anywhere (v6)
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
IPv6のルールは、/etc/default/ufw に IPV6=yes が設定されている場合(既定の値)、ufwが自動で作成します。
ufwでポートを開ける:構文のすべてのパターン
ufw allow は短い形式と完全な形式の両方に対応しています。短い形式は一般的なケースに便利で、完全な形式は送信元、インターフェース、宛先アドレスを指定する必要があるときに使います。
| 目的 | コマンド |
|---|---|
| TCPポート | sudo ufw allow 443/tcp |
| UDPポート | sudo ufw allow 51820/udp |
| ポートの範囲 | sudo ufw allow 6000:6007/tcp |
| サービス名で指定 | sudo ufw allow https |
| 特定のIPから | sudo ufw allow from 203.0.113.10 |
| サブネットからポートへ | sudo ufw allow from 10.0.0.0/24 to any port 5432 proto tcp |
| 特定のインターフェースで | sudo ufw allow in on eth1 to any port 3306 proto tcp |
| 拒否する | sudo ufw deny 23/tcp |
| 応答を返して拒否する | sudo ufw reject 25/tcp |
deny と reject の違いは次のとおりです。deny はパケットを黙って破棄するので、接続しようとした側はタイムアウトまで待つことになります。reject は「ポートは閉じています」という応答を返します。外部からのアクセスには通常 deny を、内部ネットワークでは reject を使うと、クライアントはすぐにエラーを確認できます。
データベースへのアクセスを1台のサーバーに限定する
よくあるケースとして、PostgreSQLやMySQLをインターネットから見えないようにしたいが、隣のサーバーのアプリケーションからは接続できるようにしたい場合があります。
$ sudo ufw allow from 10.0.0.5 to any port 5432 proto tcp
Rule added
deny incoming のポリシーにより、ポート5432は他のすべての送信元に対して閉じたままになります。さらに、DBサービス自体を内部アドレスだけで待ち受けさせることもお勧めします。ファイアウォールとサービスの設定が互いを補強します。
アプリケーションプロファイル
パッケージは、自分が使うポートの説明を /etc/ufw/applications.d/ に置くことがあります。プロファイルの一覧と内容は次のように確認します。
$ sudo ufw app list
Available applications:
Nginx Full
Nginx HTTP
Nginx HTTPS
OpenSSH
$ sudo ufw app info "Nginx Full"
Profile: Nginx Full
Title: Web Server (Nginx, HTTP + HTTPS)
Description: Small, but very powerful and efficient web server
Ports:
80,443/tcp
プロファイルを許可するには sudo ufw allow "Nginx Full" を実行します。空白を含む名前は引用符で囲んでください。独自のプロファイルは同じディレクトリにINI形式で記述し、sudo ufw app update 名前 で反映できます。
ufwのルールを削除する
最も確実な方法は番号を指定することです。
$ sudo ufw status numbered
Status: active
To Action From
-- ------ ----
[ 1] OpenSSH ALLOW IN Anywhere
[ 2] 80/tcp ALLOW IN Anywhere
[ 3] 443/tcp ALLOW IN Anywhere
[ 4] OpenSSH (v6) ALLOW IN Anywhere (v6)
[ 5] 80/tcp (v6) ALLOW IN Anywhere (v6)
[ 6] 443/tcp (v6) ALLOW IN Anywhere (v6)
$ sudo ufw delete 2
Deleting:
allow 80/tcp
Proceed with operation (y|n)? y
Rule deleted
ルールを削除すると番号が詰められるため、次の削除の前に必ず status numbered を再度実行してください。もう一つの方法は、同じルールを delete を付けて指定することです(例:sudo ufw delete allow 80/tcp)。この場合、IPv4とIPv6の両方のルールが一度に削除されます。
ルールの順序と先頭への挿入
ufwはルールを上から順に確認し、最初に一致したものを適用します。そのため、特定のアドレスを拒否するルールは、一般的な許可ルールより上にある必要があります。
$ sudo ufw insert 1 deny from 198.51.100.23
Rule inserted
通常のコマンドで deny を追加すると、allow 443/tcp の後ろに入ってしまい、そのポートに対しては効果がありません。
SSHを総当たりから守る:ufw limit
limit ルールは接続を許可しますが、30秒以内に6回以上の接続を試みたアドレスをブロックします。
$ sudo ufw limit OpenSSH
Rule updated
これは大量のパスワード総当たりに対する簡単な防御です。より強固にするには、鍵認証だけでのログインを有効にし、必要に応じてfail2banを併用してください。fail2banはufwを通じてアドレスをブロックできます。
ufwのログ
ログは sudo ufw logging on で有効になります。レベルは low、medium、high、full から選べます。記録は /var/log/ufw.log(rsyslog経由)とカーネルのログに書き込まれます。
$ sudo journalctl -k | grep 'UFW BLOCK' | tail -2
Oct 14 10:12:03 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=45.155.205.1 DST=192.0.2.10 PROTO=TCP SPT=51544 DPT=3389
Oct 14 10:12:09 web kernel: [UFW BLOCK] IN=eth0 OUT= SRC=89.248.165.7 DST=192.0.2.10 PROTO=TCP SPT=40312 DPT=23
SRC と DPT のフィールドは、誰がどのポートにアクセスしようとしたかを示します。サービスが応答せず、ログにそのポートの UFW BLOCK が記録されている場合は、ルールが追加されていないことを意味します。
ufwとDocker:ルールを無視してポートが開く理由
これは非常に有名な落とし穴です。Dockerはポートを公開する(-p 8080:80)と、NATのルールと DOCKER チェーンを自動で追加します。コンテナへのトラフィックはforwardを通るため、ufwの受信ルールをバイパスします。その結果、ufw status にはポート8080が表示されないのに、外部からはアクセスできてしまいます。
解決方法は次のとおりです。
- ポートをlocalhostだけに公開する(
-p 127.0.0.1:8080:80)、そして外部へはリバースプロキシ(nginx)経由で公開する。 DOCKER-USERチェーンに独自のルールを追加する。Dockerはこのチェーンを上書きしません。- 内部用のコンテナのポートは公開せず、Dockerのネットワークを介して接続する。
リセットと無効化
$ sudo ufw disable # 無効にする。ルールは保持される
$ sudo ufw reset # すべてのルールを削除して無効にする
$ sudo ufw reload # 設定を読み直す
reset を実行する前に、ufwは /etc/ufw/ にルールファイルのバックアップを日付付きのサフィックスで保存します。実際のルールは /etc/ufw/user.rules と user6.rules に保存されています。これらのファイルは手で編集せず、必ずコマンドで変更してください。
nftablesの基礎
nftablesは、カーネル内でiptablesを置き換える現代的な仕組みです。Debian 10以降やUbuntu 20.10以降では、iptables コマンドは既定で互換レイヤー iptables-nft を通して動作します。そのため、ufwのルールもnftablesに格納されています。カーネルに読み込まれているすべてのルールを表示するには次のとおりです。
$ sudo nft list ruleset
nftablesの構造は次のとおりです。テーブル(ファミリーは ip、ip6、または両方に対応する inet)がチェーンを持ち、チェーンはnetfilterの処理ポイントに結び付けられています。チェーンにはルールが含まれます。サーバー向けの最小限のファイアウォールを /etc/nftables.conf に書くと次のようになります。
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
ct state invalid drop
iif "lo" accept
ip protocol icmp accept
meta l4proto ipv6-icmp accept
tcp dport { 22, 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
適用して起動時に有効にするには次のとおりです。
$ sudo nft -c -f /etc/nftables.conf # 構文チェックのみ
$ sudo systemctl enable --now nftables
ルールは稼働中に追加することもできますが、ファイルに保存しなければ再起動後に消えます。
$ sudo nft add rule inet filter input tcp dport 5432 ip saddr 10.0.0.5 accept
$ sudo nft -a list chain inet filter input # -a でルールのhandleを表示
$ sudo nft delete rule inet filter input handle 9
nftablesの大きな利点は、セット({ 22, 80, 443 })が使えることと、IPv4とIPv6を1つの inet テーブルで扱えることです。ufwと同時に独自の nftables.service を動かさないでください。flush ruleset によってufwのルールが消えてしまいます。
よくある間違い
- SSHのルールがないままufwを有効にした:サーバーへの接続が失われます。プロバイダーのコンソール(VNCやシリアル)が頼りになります。
sudo ufw allow OpenSSHを実行するか、sudo ufw disableで無効にしてください。 - ポートを開けたのにサービスに接続できない:サービスが外部アドレスではなく
127.0.0.1で待ち受けています。ss -tlnpで確認してください。 - クラウドのファイアウォールがある:多くのプロバイダーにはセキュリティグループがあります。ポートはそちらでも開ける必要があります。
- denyが効かない:ルールが許可ルールより下にあります。
insert 1を使ってください。
まとめ
基本的なufwの設定は、default deny incoming の指定、SSHとサービスのポートの許可、ufw enable での有効化、そして status numbered での確認から成ります。特定の相手だけに許可するには from と port を使ったルールを、SSHには limit を使います。Dockerを使うときは、Dockerがufwをバイパスすることを忘れないでください。NATや複雑なルールセットが必要になったら、nftablesへ移行します。サーバーのファイアウォールは、Linuxコースで実践的に解説しています。
よくある質問
ufwとiptablesの違いは何ですか?
ufwは、シンプルな構文を持つ上位ツールです。iptablesやnftablesのルールを自動で生成します。iptablesとnftablesは低レベルのツールで、完全な制御ができますが、より多くの知識が必要です。
ufwのルールは再起動後も保持されますか?
はい。sudo ufw enable を実行すると、ファイアウォールは起動時に自動で有効になります。ルールは /etc/ufw/user.rules と user6.rules に保存されています。
送信接続のためにポートを開ける必要はありますか?
送信ポリシーが allow outgoing であれば必要ありません。ufwは接続の状態を追跡しているため、送信接続への応答を自動的に通します。
ufwが有効なままpingを許可するにはどうすればよいですか?
ufwは既定で、受信のICMP echo要求(ping)を通します。このルールは /etc/ufw/before.rules に定義されています。pingを禁止するには、そのファイル内のルールを ACCEPT から DROP に変更し、sudo ufw reload を実行します。
CentOSやRocky Linuxでもufwを使えますか?
これらの標準的なツールはfirewalldで、コマンドは firewall-cmd です。ufwはEPELからインストールできますが、firewalldと併用しないことをお勧めします。