Nginx reverse proxy configuration कैसे सेट करें
Ubuntu 24.04 पर Nginx reverse proxy सेटअप करने का तरीका जानें। इस गाइड में proxy_pass, आवश्यक headers, websockets और trailing slashes को कॉन्फ़िगर करने की पूरी प्रक्रिया दी गई है।
Nginx reverse proxy configuration क्या करती है
एक Nginx reverse proxy पोर्ट 80 और पोर्ट 443 पर आने वाले requests को लेती है और प्रत्येक को स्थानीय पोर्ट पर चल रहे application को सौंप देती है, फिर उस application का उत्तर browser को वापस भेज देती है। इसका configuration एक एकल server ब्लॉक है, और यह ब्लॉक संक्षिप्त होता है। अधिकांश कठिनाई उन पांच या छह लाइनों में होती है जो आपके app को यह बताती हैं कि वास्तविक client कौन था और उस client ने किस protocol का उपयोग किया था।
नीचे दी गई हर चीज़ Ubuntu 24.04 पर शून्य से तैयार की गई है, जिसमें distribution के Nginx package का उपयोग किया गया है। शुरुआती बिंदु एक ऐसा app है जो पहले से ही 127.0.0.1:3000 पर उत्तर देता है। यदि आपने अभी तक किसी proxy का चयन नहीं किया है, तो Nginx की Caddy और Traefik के साथ तुलना वह तुलना है जिसे आपको सबसे पहले पढ़ना चाहिए। आगे जो दिया गया है, वह Nginx का उत्तर है, पंक्ति दर पंक्ति।
इन configurations को अपने सर्वर पर चलाएं। reload करने से पहले sudo nginx -t के साथ हर बदलाव का परीक्षण करें, और जो यह print करता है उसे पढ़ें।
Ubuntu पर Nginx अपनी config कहाँ रखता है
sudo apt update
sudo apt install -y nginx
ls -l /etc/nginx/sites-enabled/मुख्य फाइल /etc/nginx/nginx.conf है। यह http { } ब्लॉक के भीतर global options सेट करती है और फिर दो डायरेक्टरीज़ को शामिल करती है: /etc/nginx/conf.d/*.conf और /etc/nginx/sites-enabled/*। Ubuntu और Debian पर आप प्रत्येक साइट के लिए /etc/nginx/sites-available/ में एक फाइल लिखते हैं और /etc/nginx/sites-enabled/ में एक symlink बनाकर उसे चालू करते हैं। Symlink को हटाने से साइट disable हो जाती है और फाइल सुरक्षित रहती है।
बाद में उपयोग किए जाने वाले दो directives केवल http context में काम करते हैं, कभी भी server ब्लॉक के भीतर नहीं: map और upstream। इन्हें /etc/nginx/conf.d/ के अंतर्गत अपनी फाइल में रखें, क्योंकि वह डायरेक्टरी http स्तर पर शामिल की जाती है।
यह पैकेज default नामक एक enabled साइट के साथ आता है। इसे default_server चिह्नित किया गया है, जिसका अर्थ है कि यह किसी भी ऐसे अनुरोध का उत्तर देता है जिसका Host हेडर आपकी config में कहीं भी किसी server_name से मेल नहीं खाता है। जब तक यह enabled रहता है, आपके नाम से मेल न खाने वाला अनुरोध आपके ऐप के बजाय इस पर पहुँच जाता है। अपनी साइट के काम करने के बाद symlink को हटा दें।
sudo rm /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginxएक ऐप को प्रॉक्सी करने वाला सबसे छोटा सर्वर ब्लॉक
server {
listen 80;
listen [::]:80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}इसे /etc/nginx/sites-available/app.example.com के रूप में सेव करें, फिर इसे इनेबल करें और लोड करें।
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
curl -sI -H 'Host: app.example.com' http://127.0.0.1/listen 80; IPv4 को बाइंड करता है और listen [::]:80; IPv6 को बाइंड करता है। यदि आप दूसरी लाइन हटा देते हैं, तो जिस विजिटर का DNS (डोमेन नेम सिस्टम) लुकअप आपके सर्वर के लिए AAAA रिकॉर्ड देता है, उसे कनेक्शन रिफ्यूज्ड (connection refused) मिलेगा, जबकि IPv4 वाले सभी लोगों को साइट काम करती हुई दिखेगी। आपको मिलने वाली बग रिपोर्ट में लिखा होगा "it works for me"।
server_name का मिलान ब्राउज़र द्वारा भेजे गए Host हेडर से किया जाता है। स्पेस द्वारा अलग करके कई नाम सूचीबद्ध किए जा सकते हैं। यदि कोई ब्लॉक मैच नहीं होता है, तो nginx उस ब्लॉक का उपयोग करता है जो default_server है, यही कारण है कि पैकेज्ड साइट को हटाना पड़ा।
location / रिक्वेस्ट पाथ पर एक प्रीफिक्स मैच है, और / हर पाथ से मैच करता है। proxy_pass वह एड्रेस है जिससे nginx कनेक्शन खोलता है। ऐप को 127.0.0.1 पर बाइंड रखें ताकि अंदर आने का एकमात्र रास्ता nginx के माध्यम से ही हो। यदि ऐप किसी कंटेनर में चलता है, तो इसे 127.0.0.1:3000:3000 के रूप में पब्लिश करें न कि 3000:3000 के रूप में, क्योंकि Docker अपने स्वयं के नियम लिखता है और ufw को दरकिनार करके पोर्ट्स को सीधे पब्लिश कर देता है, इसलिए आपका फायरवॉल चाहे जो भी कहे, एक खुला पब्लिश पोर्ट इंटरनेट से एक्सेस किया जा सकता है।
curl लाइन सर्वर से ही सही Host हेडर भेजती है, ताकि आप DNS के कहीं भी पॉइंट करने से पहले ब्लॉक का परीक्षण कर सकें।
जब आप कुछ और नहीं लिखते तो nginx upstream को क्या भेजता है
proxy_pass अपने आप में आपके application से चार चीजें छिपा देता है।
nginx डिफ़ॉल्ट रूप से backend से HTTP/1.0 में बात करता है और Connection: close भेजता है, इसलिए हर request एक नया upstream connection खोलती है और कोई भी protocol upgrade संभव नहीं होता।
Host header को proxy_pass के मान में बदल दिया जाता है, जो कि 127.0.0.1:3000 है। जो app Host से absolute links बनाती है, वह अब ऐसे links तैयार करती है जिन्हें सर्वर के बाहर कोई नहीं खोल सकता।
app तक पहुँचने वाला connection nginx से आता है, इसलिए app को client का पता 127.0.0.1 दिखाई देता है। तब app के अंदर की हर log line और हर rate limit visitor के बजाय proxy को record करती है।
app यह नहीं बता सकती कि browser ने HTTPS का उपयोग किया है, क्योंकि उसे प्राप्त connection loopback address पर plain HTTP है।
चार lines इन सभी समस्याओं को ठीक कर देती हैं।
सेट किए जाने वाले चार हेडर, और प्रत्येक हेडर backend को क्या दिखाता है
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Host उस नाम को ले जाता है जिसे visitor ने टाइप किया है। $host अनुरोध (request) से प्राप्त नाम है, जिसमें से port हटा दिया गया है और अक्षरों को lowercase में बदल दिया गया है। इसे सेट करें ताकि आपका app सही absolute URLs बना सके: जैसे login के बाद का redirect, या password reset email के अंदर का लिंक। यदि आप इसे छोड़ देते हैं, तो वे URLs 127.0.0.1:3000 की ओर इशारा करेंगे, जिससे login करने पर browser एक ऐसे पते पर जाएगा जो connection को अस्वीकार कर देगा। यदि आपके app को port की भी आवश्यकता है, क्योंकि आप इसे 8080 पर serve करते हैं, तो $http_host का उपयोग करें, जो कि बिल्कुल वैसा ही हेडर है जैसा client ने भेजा था।
X-Real-IP एक मान (value) ले जाता है: $remote_addr, वह पता जहाँ से nginx ने connection स्वीकार किया है। Apps इसे अपने access logs और rate limiting के लिए पढ़ते हैं।
X-Forwarded-For एक सूची ले जाता है। $proxy_add_x_forwarded_for क्लाइंट द्वारा पहले से हेडर में डाले गए किसी भी मान में $remote_addr को जोड़ देता है, इसलिए मान comma से अलग होता है और आपके nginx द्वारा जोड़ी गई entry सबसे अंत में होती है। यह विवरण तय करता है कि हेडर पर भरोसा किया जा सकता है या नहीं: एक client अपनी पसंद का कोई भी X-Forwarded-For भेज सकता है, इसलिए जो app पहली entry को पढ़ता है, उसे कोई भी गलत पता बताया जा सकता है। जब nginx edge server हो, तो इसके बजाय $remote_addr लिखें और client के version को हटा दें। जब कोई CDN या अन्य proxy सामने हो, तो realip module से set_real_ip_from और real_ip_header का उपयोग करें, ताकि $remote_addr स्वयं वास्तविक client पता बन जाए।
X-Forwarded-Proto http या https ले जाता है। Frameworks इसे यह तय करने के लिए पढ़ते हैं कि cookies को Secure मार्क करना है या नहीं और HTTPS पर redirect को force करना है या नहीं। TLS साइट पर इसे न छोड़ने पर, HTTPS को force करने के लिए कॉन्फ़िगर किया गया app http देखता है, HTTPS पते पर redirect के साथ उत्तर देता है, nginx के माध्यम से अगला अनुरोध प्राप्त करता है, फिर भी http देखता है, और फिर से redirect करता है। Browser हार मान लेता है और ERR_TOO_MANY_REDIRECTS दिखाता है।
हर location में उन चार लाइनों को दोहराने से उनमें अंतर आ जाता है। उन्हें एक फाइल में रखें और include करें।
# /etc/nginx/snippets/proxy-headers.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;location / {
include snippets/proxy-headers.conf;
proxy_pass http://127.0.0.1:3000;
}यहाँ inheritance में एक खामी है। एक location अपने server block से proxy_set_header directives को केवल तभी inherit करता है जब वह location स्वयं कोई directive परिभाषित न करे। location के अंदर एक भी proxy_set_header जोड़ें और server स्तर पर परिभाषित सभी headers उस location के लिए हटा दिए जाएंगे। इसलिए उन सभी को एक ही स्तर पर रखें, या प्रत्येक proxy करने वाली location में snippet को include करें।
मेरा WebSocket app कनेक्ट होने के बाद डिस्कनेक्ट क्यों हो जाता है?
इसका कारण यह है कि डिफ़ॉल्ट सेटिंग्स अपग्रेड की अनुमति नहीं देती हैं और डिफ़ॉल्ट रीड टाइमआउट 60 सेकंड के बाद एक निष्क्रिय टनल को बंद कर देता है। एक WebSocket की शुरुआत HTTP रिक्वेस्ट से होती है जिसमें Upgrade: websocket और Connection: Upgrade शामिल होते हैं। ये hop-by-hop हेडर हैं, जिसका अर्थ है कि प्रॉक्सी से यह अपेक्षा की जाती है कि वह इन्हें आगे भेजने के बजाय स्वयं उपयोग करे, और HTTP/1.0 में अपग्रेड करने का कोई तंत्र नहीं होता है। इन दोनों को मैन्युअल रूप से वापस जोड़ना पड़ता है।
मैप को http कॉन्टेक्स्ट में, उसकी अपनी फाइल में रखा जाता है।
# /etc/nginx/conf.d/websocket.conf
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}इसके बाद लोकेशन का नंबर आता है।
location / {
include snippets/proxy-headers.conf;
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}मैप इसलिए मौजूद है ताकि एक ही लोकेशन दोनों प्रकार के ट्रैफिक को सर्व कर सके। सामान्य रिक्वेस्ट पर $http_upgrade खाली होता है, इसलिए $connection_upgrade का मान close हो जाता है। अपग्रेड रिक्वेस्ट पर इसमें websocket होता है, इसलिए अपस्ट्रीम भेजे जाने वाला हेडर Connection: upgrade होता है। proxy_set_header Connection "upgrade"; को हार्ड-कोड करने से वह हेडर हर सामान्य पेज रिक्वेस्ट पर भी चला जाता है, और कुछ बैकएंड ऐसी रिक्वेस्ट का जवाब 400 एरर के साथ देते हैं।
proxy_read_timeout ही वह सेटिंग है जो "यह लोड होता है, फिर अपडेट होना बंद हो जाता है" जैसी रिपोर्ट का कारण बनती है। इसका डिफ़ॉल्ट मान 60 सेकंड है, और यह कनेक्शन के कुल समय को नहीं, बल्कि बैकएंड से दो रीड के बीच के अंतराल को मापता है। एक WebSocket जो 60 सेकंड तक शांत रहता है, उसे nginx द्वारा बंद कर दिया जाता है, और ब्राउज़र कंसोल में सॉकेट 1006 कोड के साथ बंद होता दिखाई देता है। जो ऐप्स हर मिनट से अधिक बार अपना हार्टबीट भेजते हैं, उन्हें कभी समस्या नहीं होती। जो ऐसा नहीं करते, वे एक मिनट बाद बंद हो जाते हैं। लाइव एडिटर्स और डैशबोर्ड में यह समस्या सबसे पहले दिखाई देती है, जिसका एक सामान्य उदाहरण HTTPS के पीछे चल रहा एक self-hosted n8n instance है।
proxy_pass में trailing slash मेरे URLs को क्यों बदल देता है?
नियम एक वाक्य का है। यदि proxy_pass किसी URI (uniform resource identifier) पर समाप्त होता है, यहाँ तक कि एक साधारण / पर भी, तो nginx अनुरोध पथ (request path) के उस हिस्से को हटा देता है जो location prefix से मेल खाता है और उसकी जगह उस URI को रख देता है। यदि proxy_pass होस्ट और पोर्ट पर ही रुक जाता है, तो अनुरोध पथ बिना किसी बदलाव के आगे भेज दिया जाता है।
location /app/ {
proxy_pass http://127.0.0.1:3000/;
}/app/status के लिए किया गया अनुरोध backend तक /status के रूप में पहुँचता है।
location /app/ {
proxy_pass http://127.0.0.1:3000;
}/app/status के लिए किया गया अनुरोध backend तक /app/status के रूप में पहुँचता है।
आपको किस प्रारूप की आवश्यकता है, यह आपके app पर निर्भर करता है। जिस app में base-path या sub-folder की सेटिंग होती है, उसे दूसरे प्रारूप की आवश्यकता होती है, जिसमें सेटिंग को /app के बारे में बताया गया हो। जिस app को prefixes के बारे में कोई जानकारी नहीं होती, उसे पहले प्रारूप की आवश्यकता होती है। पहले प्रारूप की एक खामी आप तुरंत देख सकते हैं: app द्वारा लौटाए गए HTML में अभी भी /static/main.css जैसे absolute paths होते हैं, ब्राउज़र उनके लिए site root से पूछता है, कोई location मेल नहीं खाता, और पेज बिना styling के रेंडर होता है। ब्राउज़र का network tab उन asset requests को 404 के रूप में दिखाता है। इसका समाधान app की अपनी base-path सेटिंग है, या उसी backend की ओर इशारा करने वाला दूसरा location /static/ है।
एक regex location, proxy_pass में URI नहीं ले सकता। sudo nginx -t इस config को अस्वीकार कर देता है और कारण बताता है: "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block।
समस्याओं का यह पूरा वर्ग तब समाप्त हो जाता है जब प्रत्येक app को अपना नाम, app.example.com, मिल जाता है, जिसे location / से proxy किया जाता है। Sub-paths तभी परेशानी मोल लेने लायक होते हैं जब आप DNS records नहीं जोड़ सकते।
एक ही नाम के पीछे एक से अधिक backend कैसे लगाएँ?
एक upstream ब्लॉक के साथ। यह http context का हिस्सा है, इसलिए इसे उसी फाइल में server ब्लॉक के ऊपर लिखें, या /etc/nginx/conf.d/ में रखें।
upstream app_backend {
least_conn;
server 127.0.0.1:3000 max_fails=3 fail_timeout=30s;
server 127.0.0.1:3001 max_fails=3 fail_timeout=30s;
keepalive 32;
}इसके बाद location इसे इस प्रकार नाम देता है: proxy_pass http://app_backend;।
डिफ़ॉल्ट विधि round robin है। least_conn प्रत्येक request को उस backend पर भेजता है जिसमें सबसे कम active connections हों, जो असमान लंबाई वाली requests के लिए उपयुक्त है। ip_hash एक client address को एक ही backend से जोड़ देता है। आपको ip_hash की आवश्यकता तब होती है जब app sessions को अपनी memory में रखता है, क्योंकि ऐसे दो backends पर round robin का उपयोग करने से users random रूप से logout हो जाते हैं क्योंकि उनकी requests उस instance पर पहुँच जाती हैं जिसने उन्हें पहले नहीं देखा था। Sessions को shared storage में ले जाना बेहतर समाधान है।
max_fails=3 fail_timeout=30s का अर्थ है कि 30 सेकंड के भीतर तीन बार विफल होने पर उस सर्वर को 30 सेकंड के लिए हटा दिया जाता है। जब ब्लॉक का हर सर्वर इस स्थिति में होता है, तो clients को 502 error मिलता है और error log में no live upstreams while connecting to upstream दिखाई देता है।
keepalive 32 प्रति worker process backends के लिए 32 idle connections तक खुले रखता है, जो अधिकांश requests से TCP handshake को हटा देता है। यह केवल proxy_http_version 1.1 के साथ काम करता है और upstream में कोई Connection: close न होने पर ही प्रभावी है। यदि वही location WebSocket map का भी उपयोग करता है, तो empty case को close से बदलकर एक empty string कर दें, ताकि सामान्य requests में कोई Connection header न जाए और pooled connection का पुन: उपयोग हो सके।
map $http_upgrade $connection_upgrade {
default upgrade;
'' '';
}upstream ब्लॉक के अंदर के नाम nginx start होने पर resolve किए जाते हैं। यदि आपका backend एक container है जिसे restart होने पर नया address मिलता है, तो nginx पुराने address का ही उपयोग करता रहेगा जब तक कि आप उसे reload न करें। Docker network के अंदर आप embedded resolver के साथ lookup को request time पर ले जा सकते हैं।
resolver 127.0.0.11 valid=10s;
set $backend http://app:3000;
proxy_pass $backend;जब containers इतनी बार आने-जाने लगें कि आपको तालमेल बिठाने के लिए बार-बार nginx edit करना पड़े, तो container labels को पढ़ने वाला proxy बेहतर उपकरण है। कई Docker Compose apps के सामने Traefik अपने routes को सीधे containers से ही बनाता है।
अपलोड 413 Request Entity Too Large के साथ विफल क्यों होते हैं?
client_max_body_size डिफ़ॉल्ट रूप से 1 megabyte पर सेट होता है। यदि request body इससे बड़ी है, तो nginx उसे आपके app तक पहुँचने से पहले ही अस्वीकार कर देता है, और error log में client intended to send too large body दर्ज हो जाता है। इसे server block में, या उस location में बढ़ाएं जहाँ अपलोड होते हैं।
client_max_body_size 512m;0 का मान इस जाँच को पूरी तरह से बंद कर देता है। App की अपनी सीमा भी होती है, इसलिए यदि इस बदलाव के बाद भी 413 error आता है, तो यह backend से आ रहा है और आपको app की अपनी upload setting देखनी होगी।
डिफ़ॉल्ट रूप से nginx upstream connection खोलने से पहले पूरी request body को पढ़ता है, और किसी भी बड़ी फ़ाइल को पहले डिस्क पर एक temporary file में लिखता है। यह app को धीमे clients से बचाता है, क्योंकि backend को अपलोड पूरी local speed पर प्राप्त होता है। बहुत बड़े अपलोड के लिए आप इसके बजाय streaming का उपयोग कर सकते हैं।
proxy_request_buffering off;इसके बाद backend body को वैसे ही प्राप्त करता है जैसे वह आती है और उसे इसे संभालने में सक्षम होना चाहिए। nginx किसी अन्य upstream पर request को retry करने की क्षमता भी खो देता है, क्योंकि body पहले ही भेजी जा चुकी होती है।
client_body_timeout, जो डिफ़ॉल्ट रूप से 60 seconds का होता है, पूरी अपलोड प्रक्रिया के बजाय body के दो लगातार reads के बीच लागू होता है। एक धीमा लेकिन निरंतर अपलोड इसे पार कर लेता है। यदि अपलोड रुक जाता है, तो उसे हटा दिया जाता है।
रिस्पॉन्स बफरिंग और वह सेटिंग जो लाइव आउटपुट को बाधित करती है
proxy_buffering डिफ़ॉल्ट रूप से चालू रहता है और आमतौर पर यही वांछित होता है। Nginx आपके ऐप से रिस्पॉन्स को उतनी तेज़ी से पढ़ता है जितनी तेज़ी से ऐप उसे लिख सकता है, उसे होल्ड करता है, और फिर धीमे क्लाइंट को उसकी गति के अनुसार डेटा भेजता है। ऐप वर्कर पूरी धीमी डाउनलोड प्रक्रिया के दौरान व्यस्त रहने के बजाय जल्दी फ्री हो जाता है।
यह स्ट्रीमिंग रिस्पॉन्स को बाधित करता है। सर्वर-सेंट इवेंट्स (Server-sent events) और लाइव लॉग आउटपुट तब तक कुछ नहीं दिखाते जब तक कि बफर भर न जाए। केवल उस लोकेशन पर बफरिंग को बंद करें।
proxy_buffering off;यदि आप ऐप को नियंत्रित करते हैं, तो बेहतर तरीका यह है कि केवल स्ट्रीमिंग रिस्पॉन्स पर X-Accel-Buffering: no हेडर भेजें। Nginx प्रत्येक रिस्पॉन्स के लिए उस हेडर को पढ़ता है और केवल उसी के लिए बफरिंग को अक्षम कर देता है, ताकि सामान्य पेज बफरिंग के लाभ का उपयोग करते रहें।
जब एरर लॉग में upstream sent too big header while reading response header from upstream दिखाई दे, तो इसका मतलब है कि रिस्पॉन्स हेडर एक बफर में फिट नहीं हुए। proxy_buffer_size डिफ़ॉल्ट रूप से एक मेमोरी पेज के बराबर होता है, जो प्लेटफॉर्म के आधार पर 4 या 8 किलोबाइट हो सकता है, और लंबे कुकीज़ या बड़े ऑथेंटिकेशन हेडर इसे ओवरफ़्लो कर देते हैं। दोनों मानों को बढ़ाएं।
proxy_buffer_size 16k;
proxy_buffers 8 16k;इस कॉन्फ़िगरेशन में TLS कहाँ होना चाहिए?
Nginx पर, ऊपर दी गई हर चीज़ के सामने। TLS (transport layer security) प्रॉक्सी पर समाप्त (terminate) होता है, और Nginx से ऐप तक का कनेक्शन loopback एड्रेस पर plain HTTP रहता है, जहाँ नेटवर्क पर मौजूद कोई अन्य चीज़ इसे पढ़ नहीं सकती। ऐप को यह जानकारी X-Forwarded-Proto से मिलती है, जो चार हेडर में से चौथा है।
सर्टिफिकेट पाथ को मैन्युअल रूप से न लिखें। DNS रिकॉर्ड को सर्वर पर पॉइंट करें, फ़ायरवॉल खोलें, और Certbot को इसी सर्वर ब्लॉक को एडिट करने दें: यह listen 443 ssl लाइन को ssl_certificate पाथ के साथ जोड़ता है, साथ ही पोर्ट 80 से एक रीडायरेक्ट भी जोड़ता है। Certbot के साथ Nginx के लिए Let's Encrypt सर्टिफिकेट जारी करना में इसे जारी करने और रिन्यूअल टाइमर की जानकारी दी गई है।
sudo ufw allow 'Nginx Full'
sudo ufw statusNginx Full एक एप्लिकेशन प्रोफ़ाइल है जिसे Nginx पैकेज इंस्टॉल करता है, और यह पोर्ट 80 और पोर्ट 443 को एक साथ खोलता है। HTTP-01 रिन्यूअल चैलेंज के लिए पोर्ट 80 को खुला रखना आवश्यक है, भले ही सभी विज़िटर्स को HTTPS पर रीडायरेक्ट कर दिया गया हो।
कॉन्फ़िगरेशन का परीक्षण करें, फिर रिलोड करें
sudo nginx -t
sudo systemctl reload nginxnginx -t हर शामिल की गई फ़ाइल को पार्स करता है और या तो परीक्षण के सफल होने की रिपोर्ट देता है या उस फ़ाइल और लाइन को प्रिंट करता है जहाँ यह रुक गया। रिलोड करने से पहले उस आउटपुट को पढ़ें। खराब कॉन्फ़िगरेशन के साथ रिलोड करने पर वह लागू नहीं होता है: nginx पिछली कॉन्फ़िगरेशन के साथ ही सेवा देना जारी रखता है, इसलिए आपकी साइट चालू रहती है जबकि आपका बदलाव चुपचाप कुछ नहीं करता है। systemctl restart अलग और खराब तरीके से व्यवहार करता है, क्योंकि रीस्टार्ट पहले चल रहे सर्वर को बंद कर देता है, इसलिए कॉन्फ़िगरेशन त्रुटि होने पर nginx बिल्कुल भी नहीं चलता है। डिफ़ॉल्ट रूप से रिलोड करें, और रीस्टार्ट को केवल उन दुर्लभ बदलावों के लिए रखें जिनके लिए इसकी आवश्यकता होती है।
sudo tail -f /var/log/nginx/error.log
sudo ss -lntp | grep -E ':(80|443|3000)'ss लाइन दिखाती है कि कौन सी प्रक्रिया किस पोर्ट को होल्ड कर रही है, ताकि आप पुष्टि कर सकें कि ऐप वास्तव में वहीं लिसन कर रहा है जहाँ proxy_pass पॉइंट करता है।
वे विफलताएं जिनका आप वास्तव में सामना करेंगे
502 Bad Gateway, error log में connect() failed (111: Connection refused) while connecting to upstream के साथ। proxy_pass में दिए गए पते पर कोई भी service listening मोड में नहीं है। App बंद है, या किसी अन्य port पर bound है, या ऐसे container-internal पते पर bound है जिस तक host नहीं पहुँच सकता।
no live upstreams while connecting to upstream के साथ 502 error। upstream ब्लॉक में मौजूद हर सर्वर को max_fails द्वारा वर्तमान में failed चिह्नित किया गया है। Backends को ठीक करें। fail_timeout समाप्त होने के बाद nginx उन्हें फिर से प्रयास (retry) करता है।
504 Gateway Time-out, upstream timed out (110: Connection timed out) while reading response header from upstream के साथ। Backend ने connection स्वीकार किया लेकिन proxy_read_timeout सेकंड तक कोई डेटा नहीं भेजा। यदि रिपोर्ट वास्तव में धीमी है तो timeout बढ़ाना सही है, लेकिन यदि app अटक (stuck) गई है तो यह गलत समाधान है।
हर path app से 404 error देता है। Trailing slash नियम ने path को rewrite कर दिया है। App द्वारा log किए गए path की तुलना उस path से करें जिसे आपने request किया था।
कोई दूसरी साइट जवाब देती है। server_name, Host header से मेल नहीं खाता है, इसलिए request default_server ब्लॉक पर चली गई।
पेज लोड होता है, लेकिन लगभग एक मिनट बाद इंटरफेस फ्रीज हो जाता है। यह WebSocket का मामला है: Upgrade हैंडलिंग गायब है, या proxy_read_timeout अभी भी 60 सेकंड पर सेट है।
FAQ
proxy_pass जोड़ने के बाद nginx 502 Bad Gateway क्यों दिखाता है?
nginx proxy_pass में दिए गए पते पर connection नहीं बना पा रहा है। /var/log/nginx/error.log पर मौजूद error log में इसका कारण देखें: connect() failed (111: Connection refused) while connecting to upstream का अर्थ है कि उस पते पर कोई service listening नहीं है, और no live upstreams का अर्थ है कि upstream ब्लॉक के सभी servers को failed मार्क कर दिया गया है। यह जाँचने के लिए कि कौन सी process उस port का उपयोग कर रही है और वह किस पते पर bound है, sudo ss -lntp | grep 3000 चलाएँ। यदि कोई app container-internal address पर bound है, या आपके द्वारा लिखे गए port के अलावा किसी अन्य port पर चल रही है, तो यह error बार-बार आएगी।
nginx के पीछे मेरा app लगभग एक मिनट बाद disconnect क्यों हो जाता है?
यह connection एक WebSocket है और proxy_read_timeout अभी भी अपने default 60 seconds पर है, जो backend से दो reads के बीच के अंतराल को मापता है। एक शांत socket को nginx द्वारा बंद कर दिया जाता है और browser console में close code 1006 दिखाई देता है। proxy_http_version 1.1 सेट करें, map के साथ $http_upgrade पर Upgrade और Connection को pass करें, और proxy_read_timeout को बढ़ाकर 3600s जैसा कुछ कर दें। Upgrade header के बिना upgrade कभी नहीं हो पाता, जिससे app polling पर वापस चला जाता है या live updates नहीं दिखाता।
क्या proxy_pass में trailing slash का कोई महत्व है?
हाँ, और यह उस path को बदल देता है जो आपका backend प्राप्त करता है। location /app/ और proxy_pass http://127.0.0.1:3000/ के साथ, /app/status के लिए आने वाली request backend पर /status के रूप में पहुँचती है, क्योंकि host और port के बाद का कोई भी URI matched location prefix की जगह ले लेता है। उस अंतिम slash को हटा दें और वही request /app/status के रूप में पहुँचेगी। Prefix को हटाने से अक्सर app के अपने asset links टूट जाते हैं, जो absolute बने रहते हैं और फिर site root पर 404 error देते हैं, इसलिए base-path setting वाले app के लिए वह तरीका बेहतर है जो path को वैसा ही आगे बढ़ा दे।
मेरा application हर visitor का IP address 127.0.0.1 क्यों log करता है?
क्योंकि app को मिलने वाला connection वास्तव में loopback address पर nginx से आता है। visitor का address app तक केवल आपके द्वारा सेट किए गए header में पहुँचता है: एक single value के लिए proxy_set_header X-Real-IP $remote_addr;, और appended chain के लिए proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;। इसके बाद app को उन headers पर भरोसा करने के लिए configure करना पड़ता है। याद रखें कि एक client अपना खुद का X-Forwarded-For भेज सकता है, इसलिए जब nginx edge server हो, तो उसे append करने के बजाय $remote_addr से overwrite करें।
क्या मुझे nginx और मेरे app के बीच connection पर TLS की आवश्यकता है?
नहीं, जब app उसी server पर चलता है और 127.0.0.1 पर bound होता है, क्योंकि वह traffic कभी भी machine से बाहर नहीं जाता। TLS को nginx पर terminate करें, proxy_pass को loopback पर plain HTTP रखें, और X-Forwarded-Proto $scheme भेजें ताकि app को पता चल सके कि visitor ने HTTPS का उपयोग किया है। यदि backend किसी ऐसे network पर अलग host पर स्थित है जिसे आप control नहीं करते, तो उस hop को अपनी सुरक्षा की आवश्यकता होती है, या तो backend के लिए HTTPS का उपयोग करें या दोनों machines के बीच एक private tunnel बनाएँ।