2026年10月9日
2026年10月9日
nftables でポート開放する手順:ルールの追加・永続化・締め出し防止まで
nftables でポートを開放するには、inet filter テーブルの input チェーンに tcp dport 番号 accept のルールを、遮断ルールより前に入れ、設定ファイルに書いて再起動後も残るようにします。この記事では、現在のルールの読み方、一時的な追加と設定ファイルでの恒久設定、送信元を絞った開放、SSH で締め出されないための手順、開いたかどうかの確認方法までを順に説明します。
作業前に確認すること
誰がファイアウォールを管理しているか
最近の Linux ディストリビューションでは、firewalld や ufw、Docker なども内部で nftables(または iptables の nftables 互換層)を使っています。これらが動いている状態で手書きのルールを足すと、管理ツールの再読み込みで消えたり、別のテーブルのルールに先に止められたりします。
systemctl status nftables firewalld ufw
sudo nft list tables
firewalld や ufw を使っているサーバーでは、そのツールの操作(firewall-cmd や ufw allow)でポートを開けるのが原則です。この記事は、nftables を直接管理するサーバーを前提にしています。
締め出し対策を先に用意する
リモートから SSH で作業している場合、ルールを誤るとその場で接続できなくなります。作業前に、VPS のコンソール機能などネットワーク以外の入り口が使えるかを確認し、現在のルールを保存しておきます。
sudo sh -c 'nft list ruleset > /root/nftables-good.nft'
現在のルールを読む
sudo nft -a list ruleset
-a を付けると各ルールにハンドル番号(# handle 12 のような表示)が付き、削除や位置指定に使えます。確認するのは次の点です。
- input チェーンの
policyがdropかacceptか。policy dropなら、許可していない通信はすべて落ちる - チェーンの途中や末尾に、明示的な
dropやrejectのルールがあるか ct state established,related acceptがあるか。これがないと、サーバーから外へ出た通信の戻りまで落ちる
nftables はルールを上から順に評価し、accept や drop に当たった時点でそのチェーンでの評価を終えます。開放ルールを遮断ルールより後ろに置いても効かないことが、もっとも多いつまずきです。
一時的にポートを開ける(すぐ試したいとき)
inet ファミリーのテーブルは IPv4 と IPv6 の両方に効きます。テーブル名とチェーン名は、list ruleset で見た実際の名前に合わせてください。
# 末尾に追加(policy drop で、末尾に明示的な drop ルールがない場合)
sudo nft add rule inet filter input tcp dport 8080 accept
# チェーンの先頭に追加(末尾に drop ルールがある場合)
sudo nft insert rule inet filter input tcp dport 8080 accept
# 不要になったら、ハンドル番号を確認して削除
sudo nft -a list chain inet filter input
sudo nft delete rule inet filter input handle 15
コマンドで追加したルールは再起動や nftables サービスの再読み込みで消えます。動作確認には便利ですが、残したい設定は次の設定ファイルに書きます。
設定ファイルで恒久的に開放する
設定ファイルの場所は、Debian や Ubuntu では /etc/nftables.conf、RHEL 系では /etc/sysconfig/nftables.conf が一般的です(2026年10月現在、パッケージやバージョンによって異なる場合があります)。Web サーバーで SSH と HTTP/HTTPS を開ける最小構成の例です。
#!/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
# ICMP と ICMPv6(IPv6 の近隣探索に必要)
meta l4proto { icmp, ipv6-icmp } accept
# SSH は管理元のアドレスだけに限定する例
ip saddr 203.0.113.10 tcp dport 22 accept
# Web サーバー
tcp dport { 80, 443 } accept
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
先頭の flush ruleset は、読み込み時に既存のルールをすべて消してからこの内容で置き換えます。Docker などほかのソフトが作ったテーブルも消えるため、同じサーバーで動かしている場合は flush ruleset を使わず、自分のテーブルだけを定義・削除する書き方に変えてください。
ICMPv6 を落とすと IPv6 の通信が成り立たなくなります。IPv6 を使っていないつもりでも、ICMP の許可は残しておくのが無難です。
書いたら、反映前に文法を確認してから読み込みます。
sudo nft -c -f /etc/nftables.conf # 文法チェックのみ(反映しない)
sudo nft -f /etc/nftables.conf # 反映
sudo systemctl enable --now nftables # 起動時に読み込む
自動で元に戻す保険をかける
遠隔作業では、新しいルールを入れる前に「一定時間後にバックアップへ戻す」予約をしておくと安心です。
# 5分後にバックアップのルールへ戻す予約
sudo systemd-run --on-active=5min /bin/sh -c 'nft flush ruleset && nft -f /root/nftables-good.nft'
systemd-run は作成したユニット名(run-...timer のような名前)を表示します。新しいルールで SSH が維持できることを確認できたら、systemctl list-timers で該当のタイマーを探し、sudo systemctl stop ユニット名.timer で止めます。締め出されてしまった場合も、5分待てば保存しておいたルールに戻ります。保存したファイルには flush が含まれないため、戻すときは先に nft flush ruleset を実行する形にしています。
送信元を絞って開放する
データベースや管理画面用のポートは、誰にでも開けるのではなく、接続元を限定します。
# 単一アドレスとネットワーク
ip saddr 203.0.113.10 tcp dport 3306 accept
ip saddr 192.0.2.0/24 tcp dport 3306 accept
許可するアドレスが複数ある場合は、名前付きセットにまとめると管理しやすくなります。
table inet filter {
set admin_v4 {
type ipv4_addr
flags interval
elements = { 203.0.113.10, 192.0.2.0/24 }
}
chain input {
# ...(前述のルール)
ip saddr @admin_v4 tcp dport 22 accept
}
}
セットの中身は、sudo nft add element inet filter admin_v4 '{ 198.51.100.20 }' のように、チェーンを書き換えずに追加できます。
開いたかどうかを確認する
ポートが使えない原因は、ファイアウォール以外にもあります。次の順に確認すると切り分けがしやすくなります。
- サービスが待ち受けているか:
ss -tlnpで、そのポートに LISTEN があるか。127.0.0.1:8080のようにループバックだけで待ち受けている場合、ファイアウォールを開けても外からはつながらない - ルールに当たっているか:ルールに
counterを付けて(例:tcp dport 8080 counter accept)、外から接続を試したあとnft list chain inet filter inputでカウンタが増えるか見る - 外部から接続できるか:別のマシンから
nc -vz サーバーのIP 8080やcurlで試す - サーバーの外側:クラウドのセキュリティグループや VPS 事業者のパケットフィルターは、サーバー内の nftables とは別に設定が必要
カウンタが増えないのに接続できない場合は、サーバーに届く前に止まっています。4 の外側の設定を確認してください。
Docker を使っている場合の注意
Docker のコンテナで公開したポートは、ホストの input チェーンではなく転送の経路を通るため、input チェーンで遮断しても外から見えることがあります。逆に、flush ruleset で Docker のルールを消すとコンテナの通信が止まります。Docker を使うホストでは、Docker のドキュメントにあるファイアウォール連携の方法を確認してから設計してください。
まとめ
- 開放ルールは遮断ルールより前に置く。
nft -a list rulesetで順序とハンドルを確認する - コマンドでの追加は一時的。恒久設定は設定ファイルに書き、
nft -c -fで確認してから反映する flush rulesetはほかのソフトのルールも消す。Docker などと同居するときは使い方に注意する- 管理用ポートは送信元を限定し、複数アドレスはセットで管理する
- 遠隔作業ではバックアップと自動切り戻しの予約を用意してから作業する
- つながらないときは、待ち受け、カウンタ、外部からの接続、クラウド側の設定の順に切り分ける