SSD Nodes Learn Hosting plans →
मार्गदर्शक Matt Connorद्वारे Matt Connor · अपडेटेड 2026-08-29

Docker UFW ला वळसा का घालते आणि तो कसा थांबवायचा

Docker चे प्रकाशित ports iptables मधील DNAT rules ने UFW च्या आधी लागू होतात. त्यामुळे deny केलेला port 8080 internet ला उत्तर देतो. कारण आणि काम करणारे उपाय जाणून घ्या.

Docker UFW ला का वळसा घालते

Docker प्रकाशित केलेले container ports UFW व्यवस्थापित करत असलेल्या firewall rules मधून जात नसल्यामुळे UFW ला वळसा घालते. तुम्ही docker run -p 8080:80 चालवल्यावर Docker kernel च्या nat table मधील PREROUTING chain मध्ये DNAT (destination network address translation) rule लिहिते. हा rule kernel packet कुठे पाठवायचा हे ठरवण्यापूर्वी प्रत्येक packet चा destination container च्या private address वर बदलतो. त्यानंतर बदललेला packet FORWARD chain द्वारे container कडे forward केला जातो. या chain वर Docker चे नियंत्रण असते. UFW चे rules INPUT chain मध्ये असतात आणि packet त्या chain मध्ये कधीच प्रवेश करत नाही. त्यामुळे ufw status default deny दाखवते, sudo ufw deny 8080 यशस्वी असल्याचे सांगते आणि port 8080 संपूर्ण internet कडून requests स्वीकारत राहतो.

ही Docker मधील त्रुटी नाही आणि UFW देखील बिघडलेले नाही. दोन्ही tools त्याच kernel firewall मध्ये rules लागू करतात. Docker चे rules packet च्या मार्गावरील आधीच्या टप्प्यावर लागू होतात. त्यामुळे UFW कडून कोणतीही तपासणी केली जात नाही. हा मार्गदर्शक हा bypass दाखवतो, त्याची कार्यपद्धती स्पष्ट करतो आणि त्यानंतर काम करणारे दोन उपाय समजावतो: ports 127.0.0.1 वर publish करणे आणि DOCKER-USER chain मध्ये filtering करणे. UFW तुमच्यासाठी नवीन असल्यास, प्रथम UFW firewall च्या मूलभूत गोष्टींचा मार्गदर्शक वापरून ते configure करा. कारण server वरील इतर सर्व गोष्टींसाठी default-deny firewall हाच योग्य पाया आहे.

तुमच्या स्वतःच्या सर्व्हरवर bypass पाहा

Incoming traffic साठी default deny policy असलेल्या आणि UFW सक्रिय असलेल्या VPS पासून सुरुवात करा. Published port असलेला web container चालवा:

sudo ufw status verbose
docker run -d --name web -p 8080:80 nginx:1.29-alpine

ufw status verbose मध्ये Default: deny (incoming), allow (outgoing) दिसते आणि port 8080 साठी कोणताही rule दिसत नाही. Firewall च्या स्वतःच्या अहवालानुसार port बंद आहे. आता सर्व्हरवरून नव्हे, तर वेगळ्या मशीनवरून चाचणी करा:

curl -I http://your-vps-ip:8080/
HTTP/1.1 200 OK

Container प्रतिसाद देतो. स्पष्ट deny rule जोडा आणि पुन्हा चाचणी करा:

sudo ufw deny 8080/tcp

Port अजूनही प्रतिसाद देतो, कारण deny rule अशा chain मध्ये आहे जिथे packet कधीच पोहोचत नाही. UFW अयशस्वी झालेले नाही. त्याचा सल्लाच घेतला गेला नाही. त्यामुळे ही समस्या सहज लपून राहते: कुठेही error दिसत नाही, deployment यशस्वी होते आणि firewall status output पूर्णपणे सुरक्षितपणे बंदिस्त केलेल्या सर्व्हरसारखा दिसतो.

यंत्रणा: PREROUTING हे INPUT पूर्वी चालते

कर्नल येणाऱ्या पॅकेटवर निश्चित क्रमाने प्रक्रिया करतो. संपूर्ण समस्या या क्रमामुळे निर्माण होते.

  1. PREROUTING सर्वप्रथम चालते. येथील नियम पॅकेटचे destination बदलू शकतात. प्रकाशित port साठी Docker चा नियम नेमके हेच करतो.
  2. त्यानंतर routing decision घेतला जातो. स्वतः host साठी असलेले पॅकेट INPUT chain कडे जाते. इतर कोणत्याही machine साठी असलेले पॅकेट FORWARD chain कडे जाते.
  3. UFW चे नियम INPUT मध्ये असतात. Docker चे नियम FORWARD मध्ये असतात.

तुम्ही नुकतेच सुरू केलेल्या container साठी Docker चा नियम पहा:

sudo iptables -t nat -L DOCKER -n
Chain DOCKER (2 references)
target   prot opt source       destination
RETURN   0    --  0.0.0.0/0    0.0.0.0/0
DNAT     6    --  0.0.0.0/0    0.0.0.0/0    tcp dpt:8080 to:172.17.0.2:80

DNAT ही line संपूर्ण बाब स्पष्ट करते. port 8080 साठी येणाऱ्या कोणत्याही पॅकेटचे destination 172.17.0.2:80 असे बदलले जाते. हा Docker च्या private bridge network वरील container चा address आहे. बदल केल्यानंतर पॅकेटचे destination host राहात नाही. त्यामुळे routing decision ते FORWARD मार्गाने पाठवतो. त्या ठिकाणी Docker ने स्वतःच्या network मध्ये traffic स्वीकारणारे नियम आधीच जोडलेले असतात. तुमचा deny 8080/tcp नियम INPUT मध्ये अशा पॅकेटची वाट पाहत राहतो, पण ते पॅकेट तेथे कधीच येत नाही.

Ubuntu 24.04 वर iptables command ही nftables वरील front end आहे. मात्र chain चा क्रम आणि परिणाम समान राहतात. UFW आणि Docker दोन्ही एकाच kernel packet pipeline मध्ये नियम लिहितात, आणि Docker चा entry point आधी येतो. हे केवळ UFW पुरते मर्यादित नाही: Rocky किंवा AlmaLinux VPS वरील firewalld त्याच pipeline मधील त्याच ठिकाणी filtering करते आणि त्याच DNAT नियमामुळे त्याला वळसा घातला जातो. त्यामुळे खालील उपाय तेथेही वापरता येतात.

दैनंदिन उपाय: पोर्ट्स 127.0.0.1 वर publish करा

बहुतेक कंटेनर सुरुवातीपासूनच सार्वजनिक असण्याची गरज नव्हती. Database, reverse proxy मागे असलेला app server, admin panel किंवा metrics endpoint यापैकी कोणत्याही सेवेला थेट इंटरनेटला उत्तर देऊ नये. त्या loopback address वर publish करा:

docker run -d --name web -p 127.0.0.1:8080:80 nginx:1.29-alpine

किंवा Compose file मध्ये:

services:
  web:
    image: nginx:1.29-alpine
    ports:
      - "127.0.0.1:8080:80"

हे यासाठी कार्य करते की Docker चा DNAT rule आता फक्त 127.0.0.1 ला उद्देशून असलेल्या packets शी जुळतो. इंटरनेटवरून आलेल्या packet मध्ये हे destination वैधरीत्या असू शकत नाही. त्यामुळे कोणताही firewall rule लागू होण्यापूर्वी kernel तो packet drop करतो. हा port host वरून reachable असतो; इतर कोणत्याही ठिकाणाहून नाही. Binding पडताळा:

sudo ss -tlnp | grep 8080

Output मध्ये 127.0.0.1:8080 असणे अपेक्षित आहे; 0.0.0.0:8080 किंवा [::]:8080 नसावे. त्यानंतर दुसऱ्या machine वरून curl http://your-vps-ip:8080/ refused होत असल्याची खात्री करा.

इंटरनेटला उपलब्ध असलेल्या services साठी ports 80 आणि 443 स्वतःकडे ठेवणारा एक reverse proxy चालवा आणि hostname नुसार routing करा. इतर कोणतेही ports publish करू नका. Traefik reverse proxy मार्गदर्शक हीच रचना तयार करते. VPS वरील Nextcloud सारखे self-hosted app फक्त त्याच्या proxy द्वारे reachable कसे राहते, हेही याच पद्धतीने स्पष्ट होते. ports: entries कशा घोषित करायच्या आणि उर्वरित Compose workflow यासाठी Docker Compose मूलभूत गोष्टींचे मार्गदर्शक पहा.

प्रत्येक internal container loopback वर असल्यामुळे UFW पुन्हा त्याचे नेहमीचे काम करू शकते: host स्वतः serve करत असलेल्या ports चे संरक्षण करणे. येथे तो rule set तयार करा आणि commands क्रमाने चालवा:

ToolUFW rule generator

वास्तविक filtering: DOCKER-USER chain

कधीकधी एखादा container port network वर प्रकाशित ठेवणे आवश्यक असते, परंतु त्यावर मर्यादा घालावी लागते. उदाहरणार्थ, database replica port वर केवळ एका कार्यालयाच्या address ला प्रवेश द्यायचा असू शकतो. यासाठी Docker DOCKER-USER chain उपलब्ध करून देतो. कोणत्याही container कडे जाणारे प्रत्येक packet Docker च्या स्वतःच्या accept rules आधी DOCKER-USER मधून जाते. Docker या chain मध्ये कधीही rules लिहित नाही. ही chain तुमच्यासाठी असते आणि daemon restart झाल्यानंतरही Docker तिची सामग्री बदलत नाही.

Command वापरण्यापूर्वी एक महत्त्वाचा मुद्दा लक्षात ठेवा: packet DOCKER-USER पर्यंत पोहोचेपर्यंत DNAT rewrite आधीच झालेले असते. Packet चा destination port प्रकाशित port (8080) नसून container port (आपल्या उदाहरणात 80) असतो. त्यामुळे --dport 8080 शी जुळणारा rule काहीही match करणार नाही. Client ने मूळतः ज्या port वर connection केले तो port match करणे हा विश्वासार्ह मार्ग आहे. Kernel चा connection tracker ही माहिती जतन करतो:

sudo iptables -I DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8080 --ctdir ORIGINAL ! -s 10.0.0.10 -j DROP

याचा अर्थ असा: eth0 वरून आलेल्या आणि ज्यांच्या connection चा original destination port 8080 आहे अशा packets पैकी 10.0.0.10 वरून न पाठवलेले सर्व packets drop करा. --ctdir ORIGINAL match मुळे हा rule फक्त client-to-container दिशेपुरता मर्यादित राहतो. त्यामुळे reply packets चुकून पकडले जात नाहीत. eth0 ऐवजी तुमचा public interface द्या; ip route | grep default त्याचे नाव दाखवते. मागीलप्रमाणेच चाचणी करा: परवानगी असलेल्या address वरून curl यशस्वी होते, तर इतर कोणत्याही ठिकाणाहून connection timeout होते. हा hang म्हणजे DROP rule योग्य प्रकारे काम करत असल्याचे लक्षण आहे. त्यामागे कोणतीही सेवा नसलेला port असल्याचे ते लक्षण नाही. Filter केलेला port आणि प्रत्यक्षात listening नसलेली सेवा यांतील फरक समजून घेण्याचा सर्वात जलद मार्ग म्हणजे connection refused होते की timeout.

iptables command ने जोडलेले rules reboot झाल्यावर नाहीसे होतात. UFW हे firewall आधीच व्यवस्थापित करत असल्यामुळे ते कायम ठेवण्यासाठी योग्य ठिकाण /etc/ufw/after.rules आहे. File च्या शेवटी एक block जोडा:

*filter
:DOCKER-USER - [0:0]
-A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8080 --ctdir ORIGINAL ! -s 10.0.0.10 -j DROP
COMMIT

त्यानंतर sudo ufw reload चालवा. प्रत्येक reload आणि प्रत्येक boot वेळी UFW त्या file मधील rules पुन्हा लागू करते. त्यामुळे container filtering आता firewall च्या इतर rules प्रमाणेच त्याच ठिकाणी व्यवस्थापित होते आणि reboot तसेच Docker upgrade नंतरही कायम राहते.

Docker चे iptables integration का disable करू नये

या समस्येसाठी दिलेल्या जुन्या उत्तरांमध्ये { "iptables": false } हे /etc/docker/daemon.json मध्ये set करण्याचा सल्ला दिला जातो. तसे करू नका. Docker चे firewall rules फक्त ports publish करण्यापुरते मर्यादित नसतात. masquerade rule मुळे containers ना host च्या address मार्फत outbound internet access मिळतो. त्यामुळे integration बंद केल्यास containers images pull करू शकत नाहीत, package mirrors पर्यंत पोहोचू शकत नाहीत किंवा कोणत्याही external API (application programming interface) ला call करू शकत नाहीत. DNAT rules मुळेच -p कार्य करते. त्यामुळे published ports पूर्णपणे बंद पडतात. स्वतंत्र Compose networks एकमेकांपासून वेगळे ठेवणारे isolation rules देखील काढले जातात. bypass दुरुस्त करण्याच्या प्रयत्नात container networking मोडेल आणि त्या सर्व rules स्वतः लिहून manually maintain कराव्या लागतील. Docker च्या स्वतःच्या documentation मध्ये ही setting नेमके तसे करण्याचा हेतू असलेल्या वापरकर्त्यांसाठी असल्याचे नमूद केले आहे. DOCKER-USER chain याच कारणासाठी अस्तित्वात आहे, त्यामुळे कोणालाही हा switch वापरण्याची गरज पडत नाही.

याच समस्येची IPv6 बाजू

प्रकाशित पोर्ट IPv6 वर कसा दिसतो ते प्रथम तपासा:

sudo ss -tlnp | grep 8080

Docker Engine 27 पासून Docker, default पद्धतीने ip6tables व्यवस्थापित करते. IPv6 सक्षम असलेल्या Docker network वर प्रकाशित पोर्टला IPv6 tables मध्येही तेच DNAT लागू होते. त्यामुळे तेथेही तोच bypass उपलब्ध असतो आणि तोच उपाय लागू होतो: DOCKER-USER chain ip6tables मध्येही असते. त्यामुळे sudo ip6tables -I DOCKER-USER ... वापरून तीच rule तयार करा आणि तुमच्या server च्या public IPv6 address वर curl चालवून बाहेरून तपासा, उदाहरणार्थ curl -6 http://[2001:db8:2a::1]:8080/.

IPv6 नसलेल्या network वर IPv6 clients साठी docker-proxy वापरले जाते. ही user-space प्रक्रिया [::]:8080 वर listening करते आणि IPv4 द्वारे traffic container मध्ये forward करते. Host process कडे जाणारा traffic INPUT मधून जातो. त्यामुळे UFW त्या मार्गावर filtering करू शकते; परंतु UFW IPv6 व्यवस्थापित करत असेल तरच. ते तसे आहे का आणि VPS वर IPv6 मधील त्रुटी निर्माण होण्याचे इतर मार्ग कोणते, याची माहिती UFW आणि IPv6 मार्गदर्शकात दिली आहे.

Loopback वर publishing केल्यास हा संपूर्ण प्रश्न टाळता येतो: -p 127.0.0.1:8080:80 केवळ IPv4 loopback वर bind होते. त्यामुळे IPv6 listener नसतो आणि कोणत्याही stack वरून बाहेरून पोहोचण्यास काहीही उपलब्ध राहत नाही.

तग धरणारी रचना

  • प्रत्येक अंतर्गत पोर्ट 127.0.0.1 वर publish करा, जेणेकरून ते सुरुवातीपासूनच कधीही उघडे राहणार नाही.
  • सार्वजनिक बाजू एका reverse proxy कडे द्या. हा proxy 80 आणि 443 पोर्टचे व्यवस्थापन करेल.
  • Host साठी UFW चे default deny कायम ठेवा आणि SSH तसेच proxy ports ला परवानगी द्या.
  • प्रत्यक्षात सार्वजनिक असलेल्या container ports वर DOCKER-USER मध्ये filter लावा. हा filter मूळ destination port शी जुळणारा असावा आणि /etc/ufw/after.rules मध्ये persist करा.
  • Docker चे iptables integration सुरू ठेवा.

एकदा ही रचना केल्यानंतर अनपेक्षित उघडपणा टळतो: ufw status मध्ये host चे वर्णन असते आणि DOCKER-USER मध्ये containers चे वर्णन असते. कोणतेही port चुकून publish होत नाही. पुढे तुम्ही टाइप केलेला प्रत्येक docker run -p नेमके तुम्हाला अपेक्षित तेच उघडतो.

FAQ

UFW पोर्ट अवरोधित करत असताना माझ्या Docker container पर्यंत पोहोचता का येते?

Docker PREROUTING chain मध्ये DNAT rule वापरून पोर्ट publish करते. कोणतेही filtering होण्यापूर्वी हे rule packet चे destination container च्या address वर बदलते. त्यानंतर packet FORWARD path मधून पुढे जाते. UFW चे rules INPUT मध्ये असतात आणि packet त्या chain मध्ये कधीच प्रवेश करत नाही. त्यामुळे firewall चा सल्ला घेतलाच जात नाही आणि published container ports वर त्याच्या deny rules चा परिणाम होत नाही.

Docker चे published ports UFW कडून अवरोधित कसे करायचे?

UFW स्वतःहून हे करू शकत नाही, कारण त्याचे rules चुकीच्या chain मध्ये आहेत. एकतर पोर्ट expose करणे थांबवा. त्यासाठी तो 127.0.0.1:8080:80 म्हणून publish करा, म्हणजे फक्त host त्याच्यापर्यंत पोहोचू शकेल. किंवा मूळ destination port शी conntrack द्वारे जुळणारा iptables rule DOCKER-USER chain मध्ये लागू करा. हा rule /etc/ufw/after.rules मध्ये persist करा, म्हणजे reboot आणि ufw reload नंतरही तो लागू राहील.

Docker च्या daemon.json मध्ये "iptables": false सेट करावे का?

नाही. ही setting Docker चे सर्व firewall आणि NAT rules काढून टाकते. त्यामुळे bypass पेक्षा अधिक गोष्टी बिघडतात. masquerade rule नसल्यामुळे containers चा outbound internet access बंद होतो. DNAT rules नसल्यामुळे published ports काम करणे थांबवतात. त्याऐवजी loopback publishing आणि DOCKER-USER chain वापरा. यामुळे container networking न बिघडवता exposure दूर करता येते.

IPv6 वरही Docker UFW ला bypass करते का?

Docker Engine 27 आणि त्यानंतरच्या आवृत्त्यांमध्ये ip6tables management पूर्वनिर्धारितपणे सुरू असते. त्यामुळे IPv6-enabled Docker network वर publish केलेला पोर्ट IPv4 प्रमाणेच UFW च्या बाहेरील मार्गाने rewrite केला जातो. त्यासाठी DOCKER-USER rule ची ip6tables सह समान प्रतिकृती लागू करावी लागते. IPv6 नसलेल्या networks वर docker-proxy process [::] वर listen करते. हा traffic INPUT मधून जातो. UFW IPv6 व्यवस्थापित करत असल्यास तेथे UFW हा traffic filter करू शकते. 127.0.0.1 वर publishing केल्यास दोन्ही परिस्थिती टाळता येतात, कारण IPv6 वर काहीही listen करत नाही.