SSD Nodes Learn Hosting plans →
নির্দেশিকা Matt Connorদ্বারা Matt Connor

UFW IPv6: VPS-এর খোলা port কীভাবে বন্ধ করবেন

UFW দোষী নয়: Ubuntu 24.04-এ IPv4 বন্ধ থাকলেও cloud firewall বা ভুল সেটিংয়ে IPv6 port খোলা থাকতে পারে। কী expose হচ্ছে দেখুন এবং gap বন্ধ করুন।

এক বাক্যে IPv6 firewall-এর ফাঁদ

আপনার firewall IPv4 সুরক্ষিত করে। আপনার VPS-এ প্রায় নিশ্চিতভাবেই একটি public IPv6 address আছে, এবং অনেক service ডিফল্টভাবে সেটিতে listening করে। আপনার firewall যদি শুধু IPv4 কভার করে, অথবা আপনি এমন cloud firewall-এর ওপর নির্ভর করেন যা শুধু IPv4 filter করে, তাহলে IPv4 অংশ locked down দেখালেও ওই সব service-এর প্রতিটিই IPv6-এর মাধ্যমে পুরো Internet থেকে reachable থাকে। আপনি curl দিয়ে একটি port test করে refused connection দেখতে পান এবং নিরাপদ বোধ করেন। একজন attacker একই port-এ IPv6-এর মাধ্যমে connect করে ভেতরে ঢুকে যায়।

এই guide-এ দেখানো হয়েছে, একটি সাধারণ Ubuntu 24.04 VPS-এ এই gap কোথা থেকে তৈরি হয়, আপনি ঠিক কী expose করছেন তা কীভাবে দেখবেন, এবং কীভাবে তা বন্ধ করবেন। এখানে UFW দোষী নয়। আধুনিক Ubuntu install-এ UFW ইতিমধ্যেই IPv6 পরিচালনা করে। Exposure তৈরি হয় এর চারপাশের layer-গুলো এবং আপনি যে service-গুলো listening করছে তা জানতেন না—সেগুলোর কারণে।

আপনার VPS-এ শুরু থেকেই IPv6 থাকার কারণ

বর্তমানে প্রায় প্রতিটি VPS-এই IPv4 address-এর পাশাপাশি একটি public IPv6 address থাকে। অনেক সময় একটি সম্পূর্ণ /64-ও বরাদ্দ থাকে। আপনারটি পরীক্ষা করুন:

ip -6 addr show scope global
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
    inet6 2001:db8:2a::1/64 scope global

এই নির্দেশিকায় ব্যবহৃত 2001:db8:2a::1 হলো 2001:db8::/32-এর একটি placeholder। এটি documentation-এর জন্য সংরক্ষিত এমন একটি prefix, যা Internet-এ কখনো route করা হয় না। ওই লাইনে আপনার server যে আসল address দেখায়, সেটি Internet-এর যেকোনো স্থান থেকে routable, ঠিক আপনার IPv4 address-এর মতো। এবার কোন কোন service listening করছে তা দেখুন:

sudo ss -tlnp
State   Recv-Q  Local Address:Port   Process
LISTEN  0       0.0.0.0:22           sshd
LISTEN  0       [::]:22              sshd
LISTEN  0       127.0.0.1:5432       postgres
LISTEN  0       [::]:8080            docker-proxy

Local Address column-টি ভালোভাবে দেখুন। 0.0.0.0:22 অর্থ হলো “প্রতিটি IPv4 address-এ listen করা।” [::]:22 অর্থ হলো “প্রতিটি IPv6 address-এ listen করা।” 127.0.0.1:5432 loopback-এর সঙ্গে bound এবং public নয়, তাই Postgres-এর লাইনটি নিরাপদ। দুটি [::] লাইন IPv6-এর মাধ্যমে পুরো Internet-এর অনুরোধ গ্রহণ করে, আর docker-proxy হলো সেই service, যেটি আপনি কখন চালু করেছিলেন তা ভুলে যেতে পারেন।

বেশিরভাগ daemon শুরুতেই ::-এ bind করে, কারণ Linux-এ একটি :: socket সাধারণত IPv4 অনুরোধও গ্রহণ করে। তাই নতুন server-এর default অবস্থান হলো “উভয় stack-এ, সব address-এ অনুরোধ গ্রহণ করা।” এর সামনে থাকা একমাত্র নিয়ন্ত্রণ হলো আপনার firewall। তাই যে firewall শুধু একটি stack দেখতে পায়, সেটি বাস্তব সমস্যা তৈরি করে।

IPv6-এর ফাঁকটি আসলে কোথা থেকে আসে

এর 3টি সাধারণ উৎস আছে। একটি নির্দিষ্ট সার্ভারে এর মধ্যে একটি বা একাধিক কারণ একসঙ্গে থাকতে পারে।

1. এমন একটি cloud firewall, যা শুধু IPv4 ফিল্টার করে। অনেক provider firewall এবং security-group product IPv4-কেন্দ্রিকভাবে তৈরি হয়েছে। এগুলো IPv6 উপেক্ষা করতে পারে, অথবা আলাদা IPv6 rule প্রয়োজন হতে পারে, যা আপনাকে হাতে যোগ করতে হবে। আপনার একমাত্র firewall যদি provider dashboard-এর firewall হয় এবং সেটি IPv6 কভার না করে, তাহলে IPv4-এ port 22 সম্পর্কে যা-ই দেখানো হোক না কেন, আপনার [::] service-গুলো উন্মুক্ত থাকবে। আপনার provider-এর firewall documentation পড়ুন এবং বিশেষভাবে IPv6 শব্দটি খুঁজুন।

2. ip6tables ছাড়া হাতে তৈরি করা iptables configuration। iptables command শুধু IPv4 table-এ প্রয়োগ হয়। IPv6-এর জন্য আলাদা command, ip6tables, এবং আলাদা rule রয়েছে। আপনি যদি iptables -A INPUT ... line-এ পূর্ণ একটি firewall script লিখে থাকেন, কিন্তু তার সঙ্গে সামঞ্জস্যপূর্ণ ip6tables rule না লিখে থাকেন, তাহলে আপনার IPv6 firewall খালি থাকবে। Default ACCEPT policy-সহ একটি খালি INPUT chain সবকিছু অনুমোদন করে:

sudo ip6tables -L INPUT -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

একটি screen-এ পুরো সমস্যাটি এখানে দেখা যায়। IPv4 ফিল্টার করা হচ্ছে, কিন্তু IPv6 সবার জন্য অনুমোদিত।

3. Docker আপনার firewall পাশ কাটিয়ে সরাসরি port publish করছে। আপনি যখন docker run -p 8080:80 চালান, Docker UFW-এর rule-এর আগে নিজের rule যোগ করে। তাই ufw status কোনো port deny করলেও published port-এ পৌঁছানো যায়। বর্তমান Docker ডিফল্টভাবে ip6tables rule পরিচালনা করে। ফলে container-এর network-এ IPv6 সক্রিয় থাকলে IPv6-এর ক্ষেত্রেও একই ঘটনা ঘটে। Docker কেন UFW পাশ কাটায় এবং container port সঠিকভাবে কীভাবে ফিল্টার করবেন-এ প্রক্রিয়া এবং সমাধান ব্যাখ্যা করা হয়েছে। এই published port কীভাবে নির্ধারণ করা হয়, তা জানতে VPS-এ Docker Compose-এর প্রাথমিক বিষয়গুলো দেখুন।

UFW-এর IPv6 switch সম্পর্কে একটি কথা। UFW IPv6 পরিচালনা করতে পারে, এবং এই switch একটি file-এ থাকে। এটি পরীক্ষা করুন:

grep IPV6 /etc/default/ufw

আধুনিক Ubuntu-তে IPV6=yes থাকে। তাই UFW প্রতিটি rule উভয় stack-এ প্রয়োগ করে। পুরোনো image বা পুরোনো guide থেকে IPV6=no দেখা গেলে IPv6 উন্মুক্ত থাকে না। এই setting-এ সক্রিয় UFW loopback interface ছাড়া সব IPv6 traffic drop করে। ফলে সমস্যা উল্টো দিকে যায়: IPv6-এর মাধ্যমে যেসব service চালানোর কথা ছিল, সেগুলো আর response দেয় না। UFW-কে সরাসরি IPv6 block না করে আপনার rule অনুযায়ী IPv6 filter করাতে চাইলে এটি yes সেট করুন।

আপনি ঠিক কী উন্মুক্ত করছেন তা দেখুন

অনুমান করবেন না। বাইরে থেকে পরিমাপ করুন। প্রথমে আপনার listener-গুলোর তালিকা তৈরি করুন এবং ::-এর সঙ্গে bound থাকা প্রতিটি listener নোট করুন:

sudo ss -tlnp | grep '::'

এরপর অন্য একটি মেশিন থেকে সার্ভারের public IPv6 address-এ সংযোগ করুন এবং যে port-টি বন্ধ বলে মনে করছেন সেটিতে চেষ্টা করুন:

curl -6 -v http://[2001:db8:2a::1]:8080/

এতে যদি কোনো page বা banner দেখা যায়, তাহলে IPv6-এ port-টি open। বন্ধ port-এর ক্ষেত্রে Connection refused অথবা timeout দেখা যায়। এই দুটি failure একই সংকেত নয়। refused এবং timed out-এর পার্থক্য থেকে বোঝা যায় host উত্তর দিয়ে সংযোগ প্রত্যাখ্যান করেছে, নাকি firewall নীরবে আপনার packet drop করেছে। সম্পূর্ণ চিত্র পেতে সার্ভারের বাইরে থেকে nmap দিয়ে IPv6 address scan করুন:

nmap -6 2001:db8:2a::1

IPv6-এ nmap যে port-গুলোকে open হিসেবে দেখায়, সেগুলোতে IPv4 scan-এ যা-ই দেখা যাক, পুরো Internet থেকে পৌঁছানো যায়। IPv4 এবং IPv6 scan পাশাপাশি তুলনা করলে gap দ্রুত শনাক্ত করা যায়: -6-এ open কিন্তু IPv4-এ closed থাকা যেকোনো port এমন একটি service নির্দেশ করে, যেটি আপনার firewall সুরক্ষিত করছে না।

ফাঁক বন্ধ করুন

UFW-কে উভয় stack কভার করতে দিন এবং ডিফল্টভাবে deny করুন। পরিবর্তনটি নিশ্চিত করুন। এরপর inbound-এর জন্য default-deny policy সেট করুন এবং শুধু প্রয়োজনীয় জিনিস অনুমোদন করুন:

sudo sed -i 's/^IPV6=no/IPV6=yes/' /etc/default/ufw
sudo ufw default deny incoming
sudo ufw allow 22/tcp
sudo ufw enable
sudo ufw status verbose

IPV6=yes পরিবর্তন করার সময় UFW সক্রিয় থাকলে, sudo ufw reload চালানো পর্যন্ত পরিবর্তনটি কার্যকর হয় না।

ufw status প্রতিটি rule দুবার দেখায়: একবার সাধারণভাবে এবং একবার (v6) suffix-সহ। (v6) line দেখা গেলে বুঝবেন, UFW IPv6 filter করছে:

22/tcp                     ALLOW IN    Anywhere
22/tcp (v6)                ALLOW IN    Anywhere (v6)

আপনি যদি হাতে iptables পরিচালনা করেন, প্রতিটি rule ip6tables-এও অনুরূপভাবে যোগ করুন, অথবা nftables ব্যবহার করুন। nftables-এর inet table একই জায়গা থেকে IPv4 ও IPv6 কভার করে এবং এই ধরনের ভুলের সুযোগ দূর করে। নিজে rule লিখলে একটি nftables inet filter table ব্যবহার করাই সবচেয়ে পরিষ্কার সমাধান। আপনার VPS যদি Ubuntu-এর বদলে Rocky বা AlmaLinux চালায়, তাহলে configure করার মতো UFW নেই। সেক্ষেত্রে আপনি firewalld-কে front end হিসেবে পরিচালনা করবেন, যা একসঙ্গে উভয় stack-এ zone rule প্রয়োগ করে।

যেসব service public করতে চান না, সেগুলোকে loopback-এ bind করুন। Database, admin panel বা metrics endpoint-এর সাধারণত public address-এর প্রয়োজন হয় না। এগুলোকে 127.0.0.1 এবং ::1-এ bind করুন, যাতে শুরু থেকেই কোনো routable address-এ listen না করে। Postgres-এর জন্য listen_addresses = 'localhost' সেট করুন। App server-এর ক্ষেত্রে 127.0.0.1-এ bind করে সামনে একটি reverse proxy রাখুন। Listener বন্ধ করা firewall দিয়ে block করার চেয়ে কার্যকর, কারণ তখন পৌঁছানোর মতো কোনো listener থাকে না।

Docker-এর published port সুরক্ষার জন্য UFW-এর ওপর নির্ভর করবেন না। Container port প্রতিটি interface-এ publish না করে নির্দিষ্ট address-এ publish করুন, যেমন -p 127.0.0.1:8080:80। তাহলে port-এ শুধু host এবং আপনি ইচ্ছাকৃতভাবে যেসব proxy-তে traffic পাঠান, সেখান থেকেই পৌঁছানো যাবে। কোনো container সত্যিই public করতে হলে একটি Traefik reverse proxy-এর পেছনে রাখুন এবং প্রতিটি app নয়, শুধু proxy publish করুন।

আপনার provider firewall-এ IPv6 rule যোগ করুন, অথবা মেনে নিন যে IPv6-এর ক্ষেত্রে সেটি আপনার firewall নয়। সে ক্ষেত্রে host-এর UFW বা nftables-কে এই কাজ করতে দিন।

আপনি সত্যিই বন্ধ করেছেন কি না যাচাই করুন

পরিবর্তন করার পরে একই external test আবার চালান:

curl -6 -v http://[2001:db8:2a::1]:8080/
nmap -6 2001:db8:2a::1

আগে যে port উত্তর দিয়েছিল, এখন সেটির connection প্রত্যাখ্যাত হওয়া বা timeout হওয়া উচিত। nmap-এর সেটিকে filtered অথবা closed দেখানো উচিত। কোনো port এখনও open থাকলে উপরের তিনটি উৎস আবার পরীক্ষা করুন: কোনো service এখনও ::-এ bind করা আছে কি না এবং তার সামনে কোনো rule নেই কি না; UFW-এর আগে কোনো Docker rule কার্যকর হচ্ছে কি না; অথবা provider firewall আদৌ IPv6 traffic পরীক্ষা করেনি কি না।

সংবেদনশীল service-কে সম্পূর্ণভাবে public Internet-এর বাইরে রাখা আরও নিরাপদ। SSH এবং admin panel-কে WireGuard VPN-এর আড়ালে রাখুন এবং তাদের port এমনভাবে firewall করুন, যাতে সেগুলো শুধু tunnel-এর মাধ্যমে উত্তর দেয়। তাহলে তাদের ক্ষেত্রে IPv6 exposure-এর প্রশ্ন আর প্রযোজ্য হবে না। public রাখা service-গুলোতে আসা brute-force scan ধীর করতে default-deny firewall-এর উপর SSH-এর সামনে Fail2ban যুক্ত করুন।

port সম্পর্কে ধারণা নতুন হলে আগে port কী এবং service কীভাবে listen করে পড়ুন।

FAQ

UFW কি ডিফল্টভাবে IPv6 ব্লক করে?

আধুনিক Ubuntu 24.04 ইনস্টলে, হ্যাঁ। UFW /etc/default/ufw থেকে IPV6=yes পড়ে এবং প্রতিটি rule IPv4 ও IPv6—উভয়ের ক্ষেত্রেই প্রয়োগ করে। ufw status IPv6 rule-গুলোতে (v6) suffix দেখায়। সমস্যা দেখা দেয় যখন আপনি এমন provider firewall-এর ওপর নির্ভর করেন যা শুধু IPv4 filter করে, হাতে লেখা iptables rule-এর কোনো ip6tables সমতুল্য rule থাকে না, অথবা Docker UFW-এর পাশ কাটিয়ে কোনো port publish করে। পুরোনো image বা পুরোনো tutorial থেকে আসা IPV6=no IPv6 খুলে দেয় না। এটি ব্যবহার করলে active UFW loopback ছাড়া সব IPv6 traffic drop করে। grep IPV6 /etc/default/ufw দিয়ে switch-এর অবস্থা পরীক্ষা করুন।

আমার VPS IPv6-এ কী expose করছে তা কীভাবে পরীক্ষা করব?

sudo ss -tlnp চালান এবং এমন প্রতিটি listener চিহ্নিত করুন যার local address [::] দিয়ে শুরু হয়। এর অর্থ listener-টি প্রতিটি IPv6 interface-এ response দেয়। এরপর অন্য একটি machine থেকে curl -6 -v http://[YOUR:IPV6::ADDR]:PORT/ ব্যবহার করে server-এর public IPv6 address সরাসরি পরীক্ষা করুন, অথবা nmap -6 YOUR:IPV6::ADDR দিয়ে scan করুন। IPv6 scan-এ open কিন্তু IPv4-এ closed থাকা যেকোনো port-ই আপনার security gap।

UFW port-টি blocked দেখালেও আমি Docker container-এর port-এ পৌঁছাতে পারি কেন?

-p দিয়ে কোনো port publish করলে Docker UFW-এর আগে নিজের firewall rule বসায়। তাই ufw status সেটিকে denied দেখালেও published port-এ পৌঁছানো যায়। এটি IPv4-এ ঘটে। Docker-এর IPv6 support চালু থাকলে IPv6-এও ঘটে। -p 127.0.0.1:8080:80-এর মতো নির্দিষ্ট address-এ publish করুন, অথবা container-কে reverse proxy-এর পেছনে রাখুন এবং শুধু proxy publish করুন।

আমার IPv4 firewall শক্তিশালী হলে কি এখনও IPv6 firewall দরকার?

হ্যাঁ। IPv4 ও IPv6 আলাদা network stack এবং তাদের firewall rule-ও আলাদা। IPv4-এর নিখুঁত rule সেট IPv6 traffic-এর ক্ষেত্রে কোনো কাজ করে না। আপনার VPS-এ public IPv6 address থাকলে—এবং প্রায় সব VPS-এই থাকে—::-এ listening করা যেকোনো service IPv6-এর মাধ্যমে reachable থাকবে, যতক্ষণ না কোনো IPv6 firewall rule বা loopback binding সেটিকে থামায়।

কোনো service-কে কীভাবে শুধু IPv4-এ, অথবা শুধু localhost-এ listen করাব?

Service-এর নিজস্ব config-এ bind address নির্ধারণ করুন। শুধু IPv4 loopback-এর জন্য 127.0.0.1-এ bind করুন। IPv6 listener ছাড়া সব IPv4 address-এর জন্য 0.0.0.0-এ bind করুন। Postgres listen_addresses ব্যবহার করে, SSH ListenAddress ব্যবহার করে, এবং অধিকাংশ app server-এ host বা bind flag থাকে। sudo ss -tlnp দিয়ে ফলাফল নিশ্চিত করুন এবং পরীক্ষা করুন যে Local Address আর [::] দেখাচ্ছে না।