Nginx 403 error और SELinux permissions को कैसे ठीक करें
Nginx पर 403 error आने का मुख्य कारण गलत SELinux labels हैं। इस गाइड में जानें कि कैसे audit logs की जांच करें और semanage व restorecon का उपयोग करके फाइलों को सुरक्षित रूप से ठीक करें।
nginx किसी फाइल पर 403 error क्यों देता है जबकि उसकी permissions सही हैं
यदि किसी फाइल की permission bits सही होने के बावजूद nginx 403 error दे रहा है, तो इसका कारण लगभग हमेशा SELinux (security-enhanced Linux) द्वारा read access को रोकना होता है। सामान्य permissions के सफल होने के बाद SELinux नियमों का एक दूसरा सेट जाँचता है, और web server को केवल उन्हीं फाइलों को पढ़ने की अनुमति होती है जिन पर web content label लगा हो। आपकी फाइल पर एक अलग label लगा है, इसलिए open operation विफल हो जाता है और nginx के पास भेजने के लिए कुछ नहीं होता।
केवल mode ही नहीं, बल्कि label को भी देखें:
ls -ldZ /data/www /data/www/index.htmldrwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /data/www
-rw-r--r--. root root unconfined_u:object_r:default_t:s0 /data/www/index.htmldrwxr-xr-x के बाद छपा हुआ बिंदु (dot) यह दर्शाता है कि फाइल पर SELinux label लगा है। default_t वह label है जो किसी path को तब मिलता है जब policy उसके बारे में नहीं जानती, और web server के नियमों में ऐसा कुछ नहीं है जो उस प्रकार की फाइल को पढ़ने की अनुमति दे। error log में एक सामान्य Unix error दिखाई देती है, इसीलिए यह permissions की समस्या जैसा प्रतीत होता है:
2026/08/11 09:14:02 [error] 1183#1183: *1 open() "/data/www/index.html" failed (13: Permission denied), client: 203.0.113.9, server: _, request: "GET / HTTP/1.1"kernel दोनों प्रकार के इनकार के लिए 13: Permission denied लौटाता है, सामान्य permissions और SELinux दोनों के लिए। इसलिए पहला काम यह पता लगाना है कि किस layer ने मना किया है। setenforce 0 से शुरुआत न करें।
मॉडल का वह हिस्सा जिसकी आपको आवश्यकता है
SELinux एक अनिवार्य एक्सेस कंट्रोल है, जिसे आमतौर पर MAC लिखा जाता है। प्रत्येक process एक domain में चलती है, जैसे कि वेब सर्वर के लिए httpd_t। प्रत्येक file और प्रत्येक network port पर एक type होता है, जैसे कि httpd_sys_content_t। policy domain, type और action के स्वीकृत संयोजनों की एक सूची है, और जो कुछ भी उस सूची में नहीं है उसे अस्वीकार कर दिया जाता है। यह क्लासिक Unix जांच के बाद चलता है, इसलिए drwxr-xr-x में permission bits को पहले एक्सेस की अनुमति देनी होगी। दोनों परतों का 'हाँ' कहना आवश्यक है।
एक पूर्ण context में कोलन द्वारा अलग किए गए चार field होते हैं, जैसे system_u:system_r:httpd_t:s0: SELinux user, role, type, और level। सर्वर पर आप अपना लगभग सारा समय तीसरे field, यानी type पर बिताएंगे। दो commands लाइव मान दिखाती हैं:
ps -eZ | grep nginx
id -Znginx workers एक context दिखाते हैं जो httpd_t पर समाप्त होता है। आपका login shell unconfined_u:unconfined_r:unconfined_t:s0 दिखाता है, क्योंकि डिफ़ॉल्ट targeted policy सेवाओं को सीमित करती है और interactive users को छोड़ देती है। यह जानना महत्वपूर्ण है, क्योंकि SELinux least-privilege users के अंतर्गत चल रही सेवाओं का स्थान नहीं लेता है। यह सीमित करता है कि किसी के द्वारा सेंध लगाने के बाद कोई service कहाँ तक पहुँच सकती है।
तीन मोड, और किन images में SELinux होता है
sestatus
getenforceEnforcing मोड क्रियाओं को रोकता है और उन्हें log करता है। Permissive मोड सब कुछ करने की अनुमति देता है और केवल यह log करता है कि उसने क्या रोका होता। Disabled मोड कोई भी policy load नहीं करता है। getenforce वर्तमान मोड को print करता है। sestatus उस मोड को भी print करता है जो /etc/selinux/config से आता है, और यही वह मोड है जो reboot के बाद लागू होता है।
Rocky Linux, AlmaLinux, Fedora और RHEL में SELinux डिफ़ॉल्ट रूप से targeted policy के साथ enforcing मोड में होता है। Ubuntu और Debian में इसके बजाय AppArmor होता है, जो एक अलग mechanism के साथ वही काम करता है (अंतिम section में इसे कवर किया गया है)। इसलिए, एक ही application आपके एक सर्वर पर ठीक से install हो सकती है और दूसरे पर 403 error दे सकती है।
जरूरत पड़ने से पहले टूल्स इंस्टॉल करें
sudo dnf install -y policycoreutils-python-utils setroubleshoot-serversemanage: command not found का minimal image पर होने का अर्थ है कि policycoreutils-python-utils गायब है: उस पैकेज में semanage और audit2allow शामिल होते हैं। setroubleshoot-server, sealert को जोड़ता है और प्रत्येक denial का सरल अंग्रेजी में सारांश journal में लिखता है। इन्हें एक नए सर्वर पर तुरंत इंस्टॉल करें, क्योंकि जिस क्षण आपको इनकी आवश्यकता होगी, उसी क्षण कुछ न कुछ पहले से ही खराब हो चुका होगा।
audit log में SELinux denial को कैसे पढ़ें
हर इनकार (refusal) को audit daemon द्वारा एक AVC (access vector cache) संदेश के रूप में रिकॉर्ड किया जाता है:
sudo ausearch -m AVC,USER_AVC,SELINUX_ERR -ts recenttype=AVC msg=audit(1754896442.881:412): avc: denied { read } for pid=1183 comm="nginx" name="index.html" dev="vda1" ino=17203 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0चार fields पूरी कहानी बताती हैं। comm वह प्रोग्राम है जिसे ब्लॉक किया गया था। scontext source context है, वह domain जिसमें process चल रही थी। tcontext target context है, उस वस्तु पर लगा label जिसे वह छूने की कोशिश कर रही थी। tclass object का प्रकार है, यहाँ एक file। इन्हें एक साथ पढ़ें: httpd_t में मौजूद process ने default_t लेबल वाली file को पढ़ने की कोशिश की, और permissive=0 बताता है कि अनुरोध को केवल log करने के बजाय वास्तव में ब्लॉक किया गया था।
यदि ausearch कुछ भी print नहीं करता है, तो हो सकता है कि audit daemon चल न रहा हो। ऐसी स्थिति में denials kernel ring buffer में चले जाते हैं:
sudo journalctl -k | grep -i avcअब इस रिकॉर्ड को एक वाक्य में बदलें:
sudo ausearch -m AVC -ts recent | audit2why
sudo journalctl -t setroubleshoot --since today
sudo sealert -a /var/log/audit/audit.logaudit2why उन्हीं रिकॉर्ड्स को पढ़ता है और पहचाने गए कारण का नाम बताता है: एक boolean जो बंद है, एक label जो policy से मेल नहीं खाता, या कोई नियम ही न होना। sealert पूरे log को scan करता है और हर denial के लिए एक सुझाया गया command print करता है। सुझाव को केवल एक संकेत मानें। अलग-अलग releases के बीच शब्दों का चयन बदलता रहता है, और sealert कभी-कभी एक custom policy module का प्रस्ताव देता है, जबकि सही समाधान केवल एक-लाइन का label fix हो सकता है।
एक और बात ध्यान रखें। Policy में dontaudit नियम होते हैं जो उन denials को छिपा देते हैं जिन्हें हानिकारक नहीं माना जाता, इसलिए कोई प्रोग्राम गलत व्यवहार कर सकता है जबकि log खाली रहता है। एक test की अवधि के लिए उन्हें unhide करें:
sudo semodule -DB
# reproduce the problem, then read the log again
sudo semodule -Bsemanage fcontext और restorecon के साथ गलत लेबल वाले पाथ को ठीक करना
दो commands का उपयोग करें, और इनका क्रम महत्वपूर्ण है। semanage fcontext -a यह रिकॉर्ड करता है कि किसी पाथ का लेबल क्या होना चाहिए। restorecon उस रिकॉर्ड किए गए डिफ़ॉल्ट लेबल को डिस्क पर मौजूद फाइलों पर लागू करता है।
sudo semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"
sudo restorecon -Rv /data/www
ls -ldZ /data/www/index.htmlपाथ एक regular expression होता है। (/.*)? डायरेक्टरी और उसके अंदर की हर चीज़ को कवर करता है, जो कि एक document root के लिए आवश्यक है। बदलाव करने से पहले देखें कि क्या बदलेगा: sudo restorecon -Rvn /data/www नियोजित relabels को प्रिंट करता है, क्योंकि -n का अर्थ है कि कोई कार्रवाई नहीं की जाएगी। एक वास्तविक restorecon के बाद लेबल httpd_sys_content_t हो जाता है और 403 error बिना किसी service restart के ठीक हो जाता है।
chcon का उपयोग केवल परीक्षण के लिए करें। chcon -t httpd_sys_content_t index.html लेबल को सीधे सेट करता है, और अगला restorecon, package update या full relabel इसे रीसेट कर देता है, क्योंकि policy अभी भी यही कहती है कि पाथ कुछ और होना चाहिए। semanage fcontext वह वर्ज़न है जो बना रहता है। आपने जो रिकॉर्ड किया है उसे sudo semanage fcontext -l | grep '^/data' के साथ लिस्ट करें।
जिस कंटेंट को service को लिखना है, उसके लिए एक अलग type की आवश्यकता होती है। upload डायरेक्टरी या cache के लिए httpd_sys_rw_content_t का उपयोग करें, और इसे केवल उन्हीं पाथ तक सीमित रखें: एक writable type के तहत read-only साइट रखने से एप्लिकेशन की आवश्यकता से अधिक access मिल जाता है।
लेबल गलत क्यों था? लगभग हमेशा फाइलों के आने के तरीके के कारण। mv फाइल के मौजूदा लेबल को बनाए रखता है, इसलिए /root से बाहर ले जाई गई साइट admin_home_t लेबल के साथ आती है और वैसी ही बनी रहती है। एक साधारण cp नई फाइल को डेस्टिनेशन डायरेक्टरी का डिफ़ॉल्ट लेबल देता है, जो आमतौर पर आप चाहते हैं, जबकि cp -a और rsync -X फाइल के साथ सोर्स लेबल को भी कॉपी करते हैं। एक नई टॉप-लेवल डायरेक्टरी में git clone करने पर default_t प्राप्त होता है। जब कोई पेज /usr/share/nginx/html से ठीक लोड होता है और आपकी अपनी डायरेक्टरी से विफल हो जाता है, तो यही इसका कारण होता है।
बूलियन के साथ व्यवहार की एक श्रेणी को ठीक करना
कुछ विफलताएं लेबल की समस्या नहीं होती हैं। एक नए Rocky या AlmaLinux बॉक्स पर reverse proxy 502 error देता है, और error log में यह दिखता है:
2026/08/11 10:02:55 [crit] 1183#1183: *3 connect() to 127.0.0.1:3000 failed (13: Permission denied) while connecting to upstreamआपका upstream ठीक है। httpd_t domain को डिफ़ॉल्ट रूप से outbound network connections खोलने की अनुमति नहीं है, इसलिए connect() कॉल को loopback interface तक पहुँचने से पहले ही अस्वीकार कर दिया जाता है। एक स्विच इस पूरे व्यवहार को नियंत्रित करता है:
getsebool -a | grep httpd_can_network
sudo setsebool -P httpd_can_network_connect on-P वह flag है जो मायने रखता है: यह मान को disk पर लिखता है। -P के बिना, अगले reboot पर बदलाव खो जाता है, जिससे आपको एक ऐसी service मिलती है जो मशीन के restart होने तक काम करती है। semanage boolean -l | grep httpd_can_network_connect के साथ पुष्टि करें, जो संग्रहीत मान के बगल में चल रहे मान को प्रिंट करता है।
जब भी कोई बूलियन उपलब्ध हो, तो उसे हाथ से लिखे गए नियम (hand-written rule) पर प्राथमिकता दें। बूलियन distribution policy के साथ आते हैं, इसलिए उन्हें maintain किया जाता है, document किया जाता है, और अगले व्यक्ति के लिए ढूंढना आसान होता है। getsebool -a सिस्टम पर मौजूद हर एक बूलियन को सूचीबद्ध करता है।
किसी सर्विस को non-standard port पर listen करने दें
Ports पर भी labels लगे होते हैं। Nginx को 8081 पर ले जाने पर वह start होने से मना कर देता है:
nginx: [emerg] bind() to 0.0.0.0:8081 failed (13: Permission denied)httpd_t केवल उन्हीं ports को bind कर सकता है जिन पर http_port_t label लगा हो, और 8081 उनमें से नहीं है। इसे जोड़ें:
sudo semanage port -l | grep -w http_port_t
sudo semanage port -a -t http_port_t -p tcp 8081पहले सूची की जाँच करें। कई high ports पहले से ही allowed हैं, जिनमें 8008 और 8443 शामिल हैं, और किसी एक को दो बार जोड़ने पर ValueError: Port tcp/8081 already defined के साथ error आता है। यदि port पहले से ही किसी अन्य type से संबंधित है, तो उसे जोड़ने के बजाय semanage port -m -t http_port_t -p tcp 8081 का उपयोग करके बदलें।
यही command बदले हुए SSH port को काम करने योग्य बनाती है। journalctl -u sshd में Bind to port 2222 on 0.0.0.0 failed: Permission denied का मतलब है कि 2222, ssh_port_t में मौजूद नहीं है, इसलिए daemon को restart करने और अपना session बंद करने से पहले sudo semanage port -a -t ssh_port_t -p tcp 2222 चलाएं। यह वह कदम है जिसे लोग तब भूल जाते हैं जब वे VPS पर SSH को सुरक्षित करने के लिए किसी सामान्य guide का पालन करते हैं, विशेषकर Red Hat family की image पर। SELinux कोई firewall नहीं है, इसलिए port को अभी भी open रखना होगा: यहाँ sudo firewall-cmd --permanent --add-port=8081/tcp && sudo firewall-cmd --reload का उपयोग करें, या Debian या Ubuntu image पर ufw का उपयोग करें।
जब बदलने के लिए कोई boolean या label न हो
एक सामान्य सर्वर पर यह स्थिति दुर्लभ है, और यहीं पर लोग नुकसान पहुँचाते हैं। audit2allow लॉग में मौजूद denials से एक policy module बना सकता है:
sudo ausearch -m AVC -ts recent -c nginx | audit2allow -M nginx_local
cat nginx_local.te
sudo semodule -i nginx_local.ppइसे install करने से पहले nginx_local.te को पढ़ें। दो आदतें इसे सुरक्षित रखती हैं। इनपुट को केवल उस एक प्रोग्राम तक सीमित करें जिसे आप -c के साथ ठीक कर रहे हैं, क्योंकि एक सप्ताह के असंबंधित denials को audit2allow में पाइप करने से वे सभी एक साथ स्वीकृत हो जाते हैं। और कभी भी ऐसे denial से बना module install न करें जिसे आप समझा न सकें: एक ऐसा नियम जो httpd_t को बॉक्स पर मौजूद हर फाइल को पढ़ने की अनुमति देता है, उसे बनाना आसान है लेकिन महीनों बाद उसे पहचानना कठिन होता है। sudo semodule -r nginx_local के साथ एक module को हटाएँ।
Permissive एक डायग्नोस्टिक मोड है, समाधान नहीं
sudo setenforce 0
# reproduce the problem once, all the way through
sudo ausearch -m AVC -ts recent
sudo setenforce 1Permissive मोड access की अनुमति देता है और उसे log करता है। इसका वास्तविक मूल्य पूर्णता (completeness) में है। Enforcing मोड में, service पहले denial पर ही रुक जाती है, इसलिए आप उसे ठीक करते हैं, restart करते हैं, और फिर अगली समस्या सामने आती है। Permissive मोड में, execution जारी रहता है और log एक ही बार में सभी denials को collect कर लेता है, जिसके बाद आप वापस switch करके उन्हें एक साथ ठीक कर सकते हैं।
setenforce, /etc/selinux/config को प्रभावित नहीं करता है, इसलिए reboot करने पर सिस्टम वापस enforcing मोड में आ जाता है। यह एक सुरक्षा कवच है, और यही कारण है कि setenforce 0 से किया गया "समाधान" सबसे खराब समय पर फिर से समस्या पैदा कर सकता है। यदि किसी service पर काम करते समय उसे अधिक छूट की आवश्यकता हो, तो पूरी मशीन के बजाय केवल उस domain को mark करें: sudo semanage permissive -a httpd_t बाकी सब कुछ enforcing रखता है, और sudo semanage permissive -d httpd_t इसे वापस सामान्य कर देता है।
SELinux को disable करना label ठीक करने से अधिक महंगा क्यों है
/etc/selinux/config में SELINUX=disabled सेट करना एक लाइन के label फिक्स को हमेशा के लिए कमजोर सर्वर से बदलने जैसा है। इसका अंतर उस दिन पता चलता है जब कोई web application breach हो जाती है। Enforcing मोड में, attacker का कोड httpd_t में चलता है, इसलिए वह web content तो पढ़ सकता है, लेकिन Unix user की अनुमति के बावजूद policy उसे /etc/shadow पढ़ने या systemd unit लिखने से रोक देती है। यदि कोई policy loaded न हो, तो वही कोड service account के पास मौजूद हर चीज़ का उपयोग कर सकता है।
इसे disable करने की कीमत आपको बाद में चुकानी पड़ती है। जब कोई policy loaded नहीं होती, तो नई फाइलें बिना label के बनती हैं, जिससे filesystem policy के साथ तालमेल खो देता है। SELinux को वापस चालू करने पर पूरे filesystem को relabel करना पड़ता है, अन्यथा कई services एक साथ fail हो जाती हैं:
sudo fixfiles -F onboot
sudo rebootयह /.autorelabel लिखता है और अगले boot के दौरान हर filesystem को relabel करता है। बड़ी disk पर इसमें काफी समय लगता है और console रुका हुआ लग सकता है, इसलिए इसे तब चलाएं जब आप प्रतीक्षा कर सकें। Rocky Linux और AlmaLinux 9 पर, config फाइल अब kernel के हिस्से को अपने आप बंद नहीं करती है, और SELinux को पूरी तरह से disable करने का आधिकारिक तरीका kernel argument (sudo grubby --update-kernel ALL --args selinux=0) है। जब आप किसी और का सर्वर संभालते हैं, तो उस command की जानकारी होना उपयोगी होता है। यह 403 error का समाधान नहीं है।
Containers में एक और label जोड़ना
Red Hat परिवार के host पर, container processes container_t में चलते हैं और केवल उन फाइलों को पढ़ सकते हैं जिन्हें container_file_t लेबल किया गया है। host से bind mount करने पर container के अंदर Permission denied त्रुटि आती है, जबकि host पर ls -l बिल्कुल सामान्य दिखता है। :Z प्रत्यय (suffix) runtime को mount को फिर से लेबल (relabel) करने का निर्देश देता है:
docker run -d -v /data/appdata:/var/lib/app:Z myimage:Z इस container के लिए निर्देशिका (directory) को विशेष रूप से लेबल करता है। :z इसे containers के बीच साझा करने के लिए लेबल करता है। यदि आप :Z को ऐसी निर्देशिका पर पॉइंट करते हैं जिसका उपयोग अन्य सेवाएं करती हैं, तो यह उस निर्देशिका को पुनरावर्ती (recursively) रूप से फिर से लेबल कर देगा, जिससे वे सेवाएं बाधित हो जाएंगी। इसलिए containers को उनके अपने पथ (paths) दें। सेटअप के बारे में बाकी सब कुछ किसी भी अन्य image से मेल खाता है, जिसे VPS पर Docker चलाना में कवर किया गया है।
Ubuntu और Debian में AppArmor मिलता है
काम वही है, लेकिन डिज़ाइन अलग है। AppArmor किसी प्रोग्राम को उसकी executable के पाथ के आधार पर सीमित करता है, जिसके लिए /etc/apparmor.d/ के अंतर्गत एक प्रोफाइल का उपयोग किया जाता है, न कि डिस्क पर फाइलों को लेबल करने का। इसमें relabel करने जैसा कुछ नहीं है और न ही कोई restorecon है। यहाँ से शुरुआत करें:
sudo aa-status
sudo journalctl -k | grep -i apparmorएक इनकार (refusal) apparmor="DENIED" operation="open" profile="/usr/sbin/nginx" name="/data/www/index.html" requested_mask="r" के रूप में दिखाई देता है। कार्यप्रवाह का स्वरूप वही है: इनकार को पढ़ें, प्रोफाइल खोजें, नियम बदलें। sudo apt install apparmor-utils आपको aa-complain (एक प्रोफाइल के लिए permissive) और इसे वापस लाने के लिए aa-enforce की सुविधा देता है। Ubuntu पैकेज्ड सेवाओं के एक चयनित सेट को ही सीमित करता है और बाकी को unconfined छोड़ देता है, इसलिए यह मानने के बजाय कि क्या सक्रिय है, वास्तव में क्या चल रहा है यह देखने के लिए aa-status पढ़ें।
दोनों सिस्टम में एक आदत समान रहती है। जब कोई सेवा किसी ऐसी चीज़ पर Permission denied रिपोर्ट करती है जो सही दिखती है, तो अनुमतियों (permissions) को बदलने से पहले सुरक्षा लॉग पढ़ें। समस्या शायद ही कभी दो बार समान bits के कारण होती है।
FAQ
फाइल अनुमतियाँ (permissions) सही होने पर भी nginx 403 error क्यों देता है?
ऐसा इसलिए होता है क्योंकि SELinux ने फाइल को पढ़ने से मना कर दिया है, न कि permission bits की समस्या के कारण। वेब सर्वर httpd_t डोमेन में चलता है और केवल वेब सामग्री के लिए लेबल की गई फाइलों को ही पढ़ सकता है, इसलिए default_t या admin_home_t लेबल वाली फाइल को अस्वीकार कर दिया जाता है और nginx के पास सर्व करने के लिए कुछ नहीं होता। इसकी पुष्टि sudo ausearch -m AVC -ts recent से करें, जो यह दिखाएगा कि scontext का अंत httpd_t पर हो रहा है और tcontext में गलत प्रकार (type) मौजूद है। इसके बाद सही लेबल रिकॉर्ड करें और उसे लागू करें: sudo semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?" और उसके बाद sudo restorecon -Rv /data/www का उपयोग करें।
क्या किसी सर्विस को चलाने के लिए setenforce 0 का उपयोग करना सुरक्षित है?
setenforce 0 केवल एक नैदानिक (diagnostic) चरण है, समाधान नहीं। इसका उपयोग समस्या को एक बार पुनरुत्पादित (reproduce) करने के लिए करें ताकि लॉग में सभी denials एक साथ आ जाएं, फिर उन्हें sudo ausearch -m AVC -ts recent के साथ पढ़ें, और अंत में sudo setenforce 1 चलाकर कारणों को ठीक करें। यदि सर्वर को permissive मोड पर छोड़ दिया जाता है, तो वह हर denial को लॉग तो करेगा लेकिन किसी को ब्लॉक नहीं करेगा, जिससे आप सुरक्षा खो देंगे और लॉग में अनावश्यक जानकारी भर जाएगी। यदि काम करते समय किसी एक सर्विस को छूट की आवश्यकता है, तो sudo semanage permissive -a httpd_t चलाएं ताकि बाकी मशीन enforcing मोड में बनी रहे।
SELinux enforcing मोड में रहते हुए किसी सर्विस को non-standard पोर्ट पर कैसे चलाएं?
उस पोर्ट को उस प्रकार (type) में जोड़ें जिसे सर्विस bind करने की अनुमति रखती है। 8081 पोर्ट पर वेब सर्वर के लिए: sudo semanage port -a -t http_port_t -p tcp 8081। 2222 पोर्ट पर SSH के लिए: sudo semanage port -a -t ssh_port_t -p tcp 2222। पहले sudo semanage port -l | grep -w http_port_t के साथ वर्तमान सूची की जाँच करें, क्योंकि जो पोर्ट पहले से ही सूची में है, उसे जोड़ने पर ValueError: Port tcp/8081 already defined त्रुटि आएगी। इस चरण के बिना, daemon स्टार्टअप पर bind() ... Permission denied के साथ बंद हो जाएगा, भले ही कोई अन्य प्रक्रिया उस पोर्ट का उपयोग न कर रही हो।
क्या Ubuntu में SELinux होता है?
नहीं। Ubuntu और Debian में AppArmor होता है, जो फाइलों पर लेबल के बजाय निष्पादन योग्य (executable) फाइल के पथ (path) से जुड़े प्रोफाइल को लागू करता है। इसे sudo aa-status के साथ जाँचें और sudo journalctl -k में apparmor="DENIED" लाइनों को देखें। Ubuntu केवल चुनिंदा पैकेज्ड सर्विसेज को ही सीमित (confine) करता है, इसलिए डिफ़ॉल्ट रूप से कई प्रोग्राम unconfined चलते हैं। Rocky Linux और AlmaLinux में आपको SELinux डिफ़ॉल्ट रूप से enforcing मिलता है, साथ ही Fedora और RHEL में भी।