SSD Nodes Learn 🎉 VPS $5.50/월부터
가이드 Matt Connor작성자 Matt Connor

Ubuntu iptables와 nftables 차이점 및 확인 방법

Ubuntu에서 iptables 명령어가 실제로는 nftables 규칙을 생성한다는 사실을 확인하는 방법을 설명합니다. nftables 백엔드 동작 원리와 ufw 및 Docker 사용 시 발생하는 규칙 충돌 문제를 해결하기 위한 실무적인 가이드를 제공합니다.

Ubuntu에서 iptables와 nftables 비교: 현재 서버에서 무엇이 실행 중인가?

Ubuntu 20.04 이상 버전에서 iptables 명령어는 nftables 규칙을 작성하는 프런트엔드입니다. 커널에서는 하나의 패킷 필터인 nftables가 실행되며, 두 개의 사용자 공간 명령어가 이를 프로그래밍합니다. iptables -A INPUT 줄은 여전히 이전과 동일하게 작동하며, 생성된 규칙은 nft로 출력할 수 있는 nftables 규칙입니다.

이를 믿기 전에 본인의 서버에서 직접 확인하십시오.

iptables -V
sudo update-alternatives --display iptables
sudo nft list ruleset

Ubuntu 24.04(2026년 8월 기준, iptables 1.8.10)에서 iptables -Viptables v1.8.10 (nf_tables)를 출력합니다. 괄호 안의 이름은 백엔드를 의미합니다. (nf_tables)은 해당 명령어가 nftables와 통신함을 뜻합니다. (legacy)은 Ubuntu가 여전히 iptables-legacy으로 제공하고 커널이 완전히 별도의 규칙 집합으로 유지하는 기존 x_tables 백엔드를 의미합니다. update-alternatives는 해당 선택의 배후에 있는 심볼릭 링크인 link currently points to /usr/sbin/iptables-nft를 출력합니다.

방화벽이 설정되지 않은 새로운 VPS에서 sudo nft list ruleset은 아무것도 출력하지 않습니다. 이 빈 출력값이 기준점입니다. 이전 방식으로 규칙을 하나 추가한 뒤 다시 확인해 보십시오.

sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo nft list ruleset
# Warning: table ip filter is managed by iptables-nft, do not touch!
table ip filter {
  chain INPUT {
    type filter hook input priority filter; policy accept;
    tcp dport 22 counter packets 0 bytes 0 accept
  }
  chain FORWARD {
    type filter hook forward priority filter; policy accept;
  }
  chain OUTPUT {
    type filter hook output priority filter; policy accept;
  }
}

귀하의 iptables 규칙은 nftables 규칙입니다. iptables-nft은 생성된 테이블을 표시하며, nft은 해당 표시를 감지하면 경고를 출력합니다. 이는 nft로 그러한 테이블을 편집하면 두 도구가 동일한 규칙을 관리하게 되기 때문입니다. 하나의 명령어가 생성한 결과를 확인해 보십시오: 사용자가 명명하지 않은 테이블과 요청하지 않은 체인이 생성됩니다. 이것이 이전 모델이며, nftables를 직접 작성할 때 가장 먼저 바뀌는 부분입니다.

iptables -L가 숨기는 정보

iptables -Lfilter 테이블만 보여줍니다. NAT(network address translation) 규칙을 확인하려면 iptables -t nat -L이 필요하며, mangle 규칙은 -t mangle가 필요합니다. IPv6는 별도의 명령어인 ip6tables를 사용하며, 모든 규칙을 독자적으로 관리합니다. 따라서 특정 테이블만 확인하면 서버가 깨끗해 보일 수 있지만, 실제로는 확인하지 않은 다른 테이블에서 패킷이 드롭되거나 재작성되고 있을 수 있습니다.

sudo nft list ruleset은 모든 패밀리, 테이블, 체인, 규칙을 한 번에 출력합니다. 직접 구축하지 않은 서버에서는 이 명령어가 현재 로드된 설정을 가장 빠르게 파악하는 방법입니다. -a을 추가하면 규칙 핸들을 함께 출력하는데, 이는 전체 체인을 삭제하지 않고 특정 규칙만 삭제할 때 필요합니다.

이곳을 확인하는 김에 두 가지 습관을 고치는 것이 좋습니다. iptables -L은 주소와 포트를 이름으로 변환하려 시도하므로, 리졸버가 고장 난 서버에서는 명령어가 멈춘 것처럼 보일 수 있습니다. 대신 iptables -nvL를 사용하십시오. 또한 sudo iptables-legacy -nvL을 실행하여 레거시 백엔드가 비어 있는지 확인하십시오. 두 백엔드 모두에 규칙이 존재하면 커널이 둘 다 평가하게 되며, 어느 한쪽의 목록만으로는 전체 상황을 파악할 수 없기 때문입니다.

직접 생성하고 상속받지 않는 테이블과 체인

nftables는 아무것도 없는 상태에서 시작합니다. 사용자가 생성하기 전까지는 filter 테이블이 존재하지 않으며, filter라는 단어는 사용자가 선택한 이름일 뿐입니다. 체인은 타입, 훅, 우선순위를 지정해야 패킷을 처리할 수 있으며, 이를 베이스 체인(base chain)이라고 합니다. 이러한 설정이 없는 체인은 명시적인 jump 또는 goto를 통해서만 도달할 수 있으므로, 다른 체인에서 점프(jump)하지 않는 한 시스템 자원을 소모하지 않습니다.

또 다른 큰 변화는 inet 패밀리입니다. 하나의 inet 테이블에서 IPv4와 IPv6 규칙을 동시에 처리하므로, iptables에서는 포트가 닫혀 있고 ip6tables에서는 열려 있는 식의 오류 유형이 완전히 사라집니다. 이러한 불일치는 매우 흔하게 발생하며, ufw 환경에서 고유한 장애 모드를 가질 정도입니다.

다음은 완전한 서버 규칙셋입니다. 이 내용은 /etc/nftables.conf에 저장합니다.

#!/usr/sbin/nft -f
flush ruleset

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

  chain input {
    type filter hook input priority filter; 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 ip saddr @admin_ips counter accept
    tcp dport { 80, 443 } counter accept
  }

  chain forward {
    type filter hook forward priority filter; policy drop;
  }

  chain output {
    type filter hook output priority filter; policy accept;
  }
}

2번째 줄을 두 번 읽어보십시오. flush ruleset은 ufw와 Docker가 스스로 생성한 테이블을 포함하여 서버의 모든 테이블을 삭제합니다. 운영 중인 서버에서 이 명령을 실행하기 전에 내용을 끝까지 읽으십시오.

input 체인의 첫 번째 규칙이 대부분의 작업을 수행합니다. ct state established,related accept은 사용자가 시작한 연결에 대한 응답 패킷을 허용하므로, 체인의 나머지 부분은 새로운 연결에 대해서만 판단하면 됩니다. ct state invalid drop는 알려진 연결과 일치하지 않거나 유효한 시작 패킷이 아닌 경우를 모두 폐기합니다. 그 이후의 모든 규칙은 명시적으로 허용하는 구멍이며, policy drop이 나머지를 처리합니다.

파일을 로드하기 전에 내용을 확인하고, 작업 중에는 두 번째 SSH 세션을 항상 열어두십시오. policy drop를 실행할 때 SSH 규칙에 오타가 하나라도 있으면 서버 접속이 차단됩니다.

sudo nft -c -f /etc/nftables.conf
sudo nft -f /etc/nftables.conf
sudo nft list ruleset

nft -c -f는 파일을 구문 분석하여 아무것도 로드하지 않은 상태에서 오류를 보고합니다. 구문 분석이 성공하면 아무런 출력도 표시되지 않습니다.

Sets는 긴 규칙 목록을 대체합니다

tcp dport { 80, 443 }은 익명 세트입니다. 포트마다 규칙을 하나씩 만드는 대신, 규칙 하나와 조회 하나로 처리합니다. admin_ips과 같은 명명된 세트를 사용하면 더 유연합니다. 방화벽이 실행 중일 때도 내용을 변경할 수 있기 때문입니다.

sudo nft add element inet filter admin_ips { 203.0.113.9 }
sudo nft list set inet filter admin_ips
sudo nft delete element inet filter admin_ips { 203.0.113.9 }

설정을 다시 불러오거나 규칙 번호를 매길 필요가 없습니다. 세트에 주소가 5개 들어 있든 5만 개 들어 있든 일치 여부 확인은 단 한 번의 조회로 끝납니다. flags interval 플래그를 사용하면 세트에 범위나 198.51.100.0/24와 같은 CIDR(Classless Inter-Domain Routing) 접두사를 담을 수 있습니다. 이 플래그가 없으면 세트는 단일 주소만 허용하며, 접두사를 불러오려 할 때 실패합니다.

세트는 스스로 요소를 만료시킬 수도 있습니다.

set banned {
  type ipv4_addr
  flags timeout
  timeout 1h
}

ip saddr @banned drop 규칙을 사용하면 각 요소는 추가된 지 1시간 뒤에 스스로 삭제됩니다. Ubuntu 24.04의 fail2ban에서 nftables가 주소를 차단하는 방식이 바로 이것입니다. 규칙을 추가하는 것이 아니라 세트에 요소를 추가하는 방식입니다. 포트 개념이 생소하다면 Linux에서 포트의 실제 의미부터 확인하십시오.

마이그레이션 과정에서 흔히 겪는 차이점이 하나 있습니다. nftables는 요청하지 않으면 패킷을 세지 않습니다. iptables -nvL은 항상 모든 규칙의 카운터를 보여줍니다. 반면 nftables에서는 counter 키워드가 포함된 규칙에만 숫자가 표시되므로, 나중에 디버깅할 가능성이 있는 모든 규칙에는 counter을 추가해 두어야 합니다.

훅과 우선순위가 순서를 결정하는 방식

베이스 체인은 훅을 지정하며, 이는 패킷 경로상에서 규칙이 실행되는 지점입니다. prerouting는 라우팅 결정 이전에 실행됩니다. input는 이 장비로 향하는 패킷에 대해 실행됩니다. forward은 이 장비를 거쳐 라우팅되는 패킷에 대해 실행됩니다. output은 로컬 프로세스에서 생성된 패킷에 대해 실행됩니다. postrouting은 패킷이 나가기 직전인 마지막 단계에서 실행됩니다.

우선순위는 동일한 훅 내의 체인 순서를 결정하며, 숫자가 낮을수록 먼저 실행됩니다. nftables는 관례적인 값에 이름을 부여합니다. raw는 -300, mangle은 -150, dstnat은 -100, filter는 0, srcnat은 100입니다. priority filter;라고 쓰는 것은 priority 0;라고 쓰는 것과 동일합니다.

이제 여러 도구를 혼용할 수 있는지 결정하는 부분입니다. 훅에 등록된 모든 베이스 체인은 우선순위 순서대로 실행됩니다. 체인에서 패킷이 허용(accept)되었다고 해서 처리가 끝난 것은 아닙니다. accept은 해당 체인만 종료할 뿐이며, 패킷은 동일한 훅에 있는 다음 베이스 체인으로 계속 전달됩니다. drop은 어디서든 최종적인 결정이며 패킷을 즉시 차단합니다. 따라서 사용자의 테이블에 있는 허용 규칙은 ufw 테이블의 차단 규칙을 무효화할 수 없으며, 어느 쪽이 먼저 실행되든 상관없습니다. 또한 사용자의 accept은 나중에 실행되는 체인으로부터 어떠한 보호도 제공하지 않습니다.

동일한 훅에서 우선순위가 같은 베이스 체인 두 개는 등록된 순서대로 실행되며, 이는 어떤 서비스가 먼저 시작되었는지에 따라 달라집니다. 이 순서는 재부팅 시마다 바뀔 수 있습니다. ufw와 함께 사용자만의 테이블을 운영해야 한다면, 실행 순서가 경쟁 상태에 놓이지 않도록 고유한 우선순위를 부여하십시오.

왜 역방향 NAT 규칙을 작성할 필요가 없습니까?

이 질문은 사람들이 가장 자주 오해하는 부분이므로, 이에 대한 명확한 답변을 드립니다. 커널의 연결 추적(connection tracking) 기능이 사용자를 대신하여 역방향 변환을 기록하기 때문입니다. 따라서 추가할 두 번째 규칙은 존재하지 않습니다.

일반적인 VPS 작업의 양방향을 모두 처리하는 nat 테이블은 다음과 같습니다.

table inet nat {
  chain prerouting {
    type nat hook prerouting priority dstnat; policy accept;
    iifname "enp1s0" tcp dport 8080 dnat ip to 10.0.0.5:80
  }

  chain postrouting {
    type nat hook postrouting priority srcnat; policy accept;
    ip saddr 10.0.0.0/24 oifname "enp1s0" masquerade
  }
}

연결의 첫 번째 패킷만이 nat 체인에서 평가됩니다. 규칙이 일치하면 커널은 해당 변환 정보를 연결 추적 테이블의 연결 항목과 함께 저장합니다. 이후 양방향으로 오가는 모든 패킷은 저장된 항목을 바탕으로 재작성되며, 규칙을 다시 읽지 않습니다. conntrack 도구를 설치하여 실시간 항목을 확인해 보십시오.

sudo apt install -y conntrack
sudo conntrack -L -p tcp
tcp 6 431999 ESTABLISHED src=198.51.100.20 dst=203.0.113.10 sport=54321 dport=8080 src=10.0.0.5 dst=198.51.100.20 sport=80 dport=54321 [ASSURED] mark=0 use=1

이 내용을 두 개의 튜플로 읽으십시오. 처음 네 개의 필드는 클라이언트가 보낸 연결 정보이며, 목적지는 사용자의 공인 IP인 203.0.113.10:8080입니다. 뒤의 네 개는 커널이 예상하는 응답 정보로, 이미 역방향으로 변환되었으며 실제 백엔드인 10.0.0.5:80에서 오는 패킷입니다. 이 두 번째 튜플이 바로 역방향 규칙입니다. 첫 번째 패킷이 일치했을 때 커널이 직접 작성한 것입니다.

그러므로 반환 방향에 대한 규칙을 작성하지 마십시오. 반환 패킷은 이미 확립된 연결에 속하므로 nat 체인에 도달하지 않으며, 설령 규칙이 일치하더라도 커널이 이미 수정한 패킷을 다시 변환하게 되어 문제가 발생합니다.

재작성 규칙이 어디에 위치해야 하는지는 동일한 메커니즘에서 결정됩니다. 목적지 변환(destination translation)은 라우팅 결정 이전에 prerouting에서 수행되어야 합니다. 라우팅 과정에서 새로운 목적지를 확인하지 못하면 패킷이 잘못된 경로로 전달되기 때문입니다. 서버가 직접 생성하는 트래픽도 같은 이유로 output 훅에서 처리됩니다. 출발지 변환(source translation)은 출발지 포트 재작성을 포함하여 라우팅이 나가는 인터페이스를 결정한 후인 postrouting에서 수행되어야 합니다. masquerade는 해당 인터페이스에서 주소를 가져오는데, 라우팅이 실행되기 전까지는 인터페이스를 알 수 없기 때문입니다.

이러한 이유로 다음과 같은 규칙은 경로의 마지막 단계에만 위치해야 합니다.

ip saddr 10.0.0.0/24 oifname "enp1s0" snat ip to 203.0.113.10:20000-30000

포트 범위는 출발지 주소와 함께 출발지 포트를 재작성합니다. 이는 다수의 내부 클라이언트가 하나의 공인 IP를 공유할 때 출발지 포트가 충돌하는 경우에 필요한 작업입니다. 해당 범위 내의 포트로 응답이 도착하면 conntrack이 이를 기존 항목과 일치시키고, 패킷이 전달되기 전에 원래의 출발지 포트로 복원합니다. 이 경우에도 두 번째 규칙은 필요하지 않습니다.

실무적인 결과로, NAT 규칙을 변경해도 이미 존재하는 연결에는 영향을 주지 않습니다. 변환 정보가 이미 저장되어 있기 때문입니다. 연결 항목이 만료될 때까지 기존 동작이 유지됩니다. sudo conntrack -D -p tcp --dport 8080은 일치하는 항목을 삭제하며, sudo conntrack -F은 모든 항목을 삭제합니다. NAT 서버에서 후자를 사용할 때는 주의해야 합니다. 저장된 변환 정보가 현재 연결을 유지하는 핵심이기 때문에, 이를 삭제하면 서버를 통과하는 모든 연결이 즉시 끊어집니다.

ufw와 Docker는 각자 고유한 규칙을 작성합니다

ufw는 iptables의 프런트엔드이며, Ubuntu에서는 nftables의 프런트엔드 역할을 합니다. 따라서 ufw를 사용하는 서버에는 ufw-before-input, ufw-user-input 등의 체인으로 가득 찬 ip filter 테이블이 존재하며, 동일한 구조의 ip6 filter 복사본도 함께 존재합니다. sudo nft list ruleset | grep ufw 명령으로 이를 확인할 수 있습니다. 해당 체인들은 /etc/ufw 내의 파일들을 기반으로 생성되며, ufw reload는 이를 처음부터 다시 작성합니다. 이것이 수동으로 추가한 iptables 규칙이 다음 리로드 시 사라지는 이유입니다. VPS를 위한 ufw 기초에서 해당 파일 구조를 다룹니다.

Docker는 방화벽을 직접 프로그래밍하며 ufw를 참조하지 않습니다. -p 80:80로 포트를 게시하면 nat 테이블에 DNAT 규칙이 작성되고 포워딩 경로에 accept 규칙이 추가되는데, 이 둘은 ufw의 사용자 정의 체인보다 먼저 실행됩니다. 그 결과 모두가 한 번씩 당황하게 됩니다. ufw deny 80가 로드되어도 컨테이너는 여전히 인터넷에서 접근 가능한 상태이기 때문입니다. 해결책은 Docker가 사용자의 규칙을 위해 남겨둔 DOCKER-USER 체인에 있으며, Docker 컨테이너가 ufw를 무시하는 이유에서 이를 자세히 설명합니다. sudo nft list ruleset | grep -i docker 명령으로 현재 서버의 상태를 확인하십시오.

이제 위 설정에서 flush ruleset 줄을 다시 읽어보십시오. 이 명령은 두 도구가 관리하는 테이블을 포함하여 모든 테이블을 삭제합니다. Docker 호스트에서 이 명령을 실행하면 sudo systemctl restart docker이 체인을 재구축하기 전까지 게시된 포트들은 작동을 멈춥니다. 이 한 줄은 방화벽을 정리하려다 스스로 서비스 접속을 차단하게 되는 가장 흔한 원인입니다.

재부팅 후에도 유지되는 규칙

두 규칙 집합 모두 자체적으로는 영구적으로 유지되지 않습니다. 시스템이 종료되면 커널은 모든 설정을 잊어버리므로, 각 진영은 별도의 패키지를 통해 이 문제를 해결합니다.

nftables의 경우, /etc/nftables.confnftables.service에 의해 읽힙니다. Ubuntu는 해당 서비스를 비활성화된 상태로 제공하므로, 신뢰하기 전에 반드시 상태를 확인하십시오.

systemctl is-enabled nftables
sudo nft -c -f /etc/nftables.conf
sudo systemctl enable --now nftables

iptables의 경우, iptables-persistent 패키지를 사용합니다. 이 패키지는 netfilter-persistent을 설치하며, 규칙을 /etc/iptables/rules.v4/etc/iptables/rules.v6에 저장합니다.

sudo apt install -y iptables-persistent
sudo netfilter-persistent save

두 방식을 동시에 사용하지 마십시오. 방화벽 설정을 담고 있다고 주장하는 두 파일이 서로 어긋나게 되며, 마지막에 로드되는 설정이 우선권을 갖게 되는데 이는 어느 파일을 읽더라도 예측할 수 없는 결과를 초래합니다.

실시간 규칙 집합을 덤프할 때 주의해야 할 함정이 있습니다. sudo nft -s list ruleset > /etc/nftables.conf은 ufw 테이블과 Docker 테이블을 포함하여 현재 로드된 모든 항목을 캡처합니다. 이를 부팅 시점에 복원하면 해당 도구들이 스스로 생성해야 할 규칙의 고정된 복사본이 먼저 로드되고, 이후 도구가 시작되면서 두 번째 복사본이 생성되는 문제가 발생합니다. sudo nft -s list table inet filter을 사용하여 본인이 작성한 테이블만 덤프하십시오. -s 플래그를 사용하면 설정 파일에 포함할 필요가 없는 카운터 값을 제외할 수 있습니다.

VPS에서 방화벽을 직접 설정해야 합니까?

ufw가 처리할 수 없는 기능이 필요한 경우가 아니라면 ufw를 그대로 두십시오. ufw는 일반적인 VPS의 요구 사항인 기본 거부(default deny) 정책과 몇 개의 포트 개방을 충분히 수행합니다. 단순히 직접 작성한 규칙 세트로 교체하는 것은 동일한 방화벽 기능을 유지하면서 관리해야 할 항목만 늘리는 결과를 초래합니다.

NAT, 포트 포워딩, 런타임에 업데이트되는 세트, 두 주소 체계(IPv4/IPv6)를 모두 포함하는 단일 규칙, 또는 직접 정의한 체인 우선순위가 필요하다면 네이티브 방화벽을 사용하십시오. ufw로는 이러한 설정을 구현할 수 없으므로, 이때가 바로 네이티브 방화벽을 사용해야 할 타당한 이유가 됩니다.

네이티브 방화벽을 선택했다면 완전히 전환하십시오. sudo ufw disablesudo systemctl disable --now ufw를 실행하고, sudo nft list ruleset를 통해 기존 테이블이 제거되었는지 확인한 뒤 직접 작성한 파일을 로드하십시오. ufw와 직접 작성한 테이블을 동시에 운영하면 트래픽은 통과하지만, 실제 정책은 서비스 시작 순서에 따라 결정되는 두 규칙 세트의 합집합이 됩니다. 이 경우 어떤 파일을 읽더라도 서버의 실제 방화벽 동작을 정확히 파악할 수 없습니다.

기존 iptables 규칙 세트 마이그레이션

iptables-translate은 규칙 하나를 변환하여 nftables 형식으로 출력합니다. 서버의 설정은 아무것도 변경하지 않습니다.

iptables-translate -A INPUT -p tcp --dport 22 -j ACCEPT
nft add rule ip filter INPUT tcp dport 22 counter accept

iptables-restore-translate -f /etc/iptables/rules.v4은 저장된 전체 규칙 세트에 대해 동일한 작업을 수행합니다. 이 출력 결과는 초안으로 간주하십시오. 변환은 규칙 단위로 기계적으로 이루어지므로, 기존의 테이블 및 체인 이름이 그대로 유지되며 IPv4와 IPv6용 규칙 세트가 분리된 상태로 반환됩니다. 또한 nftables로 전환하는 이점을 누릴 수 있는 세트(set) 기능은 포함되지 않습니다. 수동으로 하나의 inet 테이블로 다시 작성한 뒤, 운영 서버에 적용하기 전에 nft -c -f로 검증하십시오.

이 예제에 사용된 주소는 문서화용 범위인 203.0.113.0/24198.51.100.0/24에서 가져왔으며, enp1s0는 인터페이스 이름입니다. 최신 Ubuntu 이미지에서는 eth0라는 이름을 거의 사용하지 않으므로, 예제를 그대로 복사하지 말고 ip route show defaultip -br addr에서 본인의 환경에 맞는 값을 사용하십시오.

FAQ

Ubuntu에서 iptables는 더 이상 사용되지 않습니까?

해당 명령어는 사라지지 않으며 Ubuntu 24.04에서도 여전히 정상적으로 작동합니다. 변경된 점은 내부 동작 방식입니다. iptablesiptables-nft 백엔드를 통해 nftables 규칙을 작성하는 프런트엔드 역할을 합니다. iptables -V 명령어로 확인하면 24.04 버전에서는 iptables v1.8.10 (nf_tables)가 출력됩니다. 기존 x_tables 백엔드는 여전히 iptables-legacy로 제공되며, 이는 완전히 별도의 규칙 집합을 유지하므로 규칙은 두 백엔드 중 한 곳에만 작성해야 합니다.

돌아오는 패킷에 대해 NAT를 해제하는 두 번째 규칙이 필요합니까?

아니요, 필요하지 않습니다. 연결 추적(connection tracking) 기능은 연결의 첫 번째 패킷이 nat 규칙과 일치할 때 변환 정보를 저장하며, 이후 양방향의 모든 패킷은 해당 저장된 항목에 따라 재작성됩니다. sudo conntrack -L는 이를 연결당 두 개의 튜플로 보여줍니다. 첫 번째는 원래 방향이고, 두 번째는 이미 역방향으로 처리된 응답입니다. 반환 방향을 위해 작성된 규칙은 아무런 도움이 되지 않는데, 이는 반환 패킷이 nat 체인에 도달하지 않기 때문입니다.

ufw와 직접 작성한 nftables 규칙을 동시에 사용할 수 있습니까?

작동은 하지만 문제를 자초하는 일입니다. 모든 후크(hook)의 기본 체인이 실행되므로, 실제 정책은 두 규칙 집합이 결합된 형태가 됩니다. 이때 우선순위에 따라 순서가 결정되며, 우선순위가 같다면 먼저 시작된 서비스의 규칙이 적용됩니다. 어느 한쪽의 drop은 최종 결정권을 가지며, 사용자가 작성한 accept가 다른 쪽의 패킷 차단을 막을 수는 없습니다. 하나의 도구만 선택하십시오. nftables를 사용한다면 먼저 ufw를 비활성화하고 sudo nft list ruleset에서 ufw의 테이블이 제거되었는지 확인하십시오.

Ubuntu에서 재부팅 후에도 nftables 규칙이 유지되게 하려면 어떻게 해야 합니까?

규칙 집합을 /etc/nftables.conf에 저장하고 sudo nft -c -f /etc/nftables.conf로 확인한 뒤, sudo systemctl enable --now nftables을 실행하십시오. 해당 서비스는 기본적으로 활성화되어 있지 않으므로 systemctl is-enabled nftables를 한 번 실행하는 것이 좋습니다. 해당 파일을 생성할 때는 sudo nft -s list table inet filter을 사용하여 본인이 작성한 테이블만 덤프하십시오. 전체 list ruleset 덤프를 수행하면 ufw와 Docker가 스스로 관리하는 테이블까지 모두 포함되기 때문입니다.