چرا Nginx رو جلوی اپلیکیشنت میذاری
خلاصهٔ کاملتر
نویسنده با یه مثال ساده شروع میکنه: یه اپ Node که رو پورت 3000 گوش میده، رو لپتاپ هیچ دردسری نداره. اما همین که لایو میشه، همهچیز عوض میشه؛ حالا یه دامنه هست، HTTPS رو پورت 443 هست و همون پروسه از کل اینترنت قابلدسترسه. راهحل سریع اینه که خود اپ رو پورت 443 گوش بده، ولی این فقط یه روز جواب میده، چون بعدش باید TLS رو ترمینیت کنه، گواهی رو renew نگه داره، فایل استاتیک سرو کنه، restart رو بدون از دست دادن درخواستها رد کنه و جلوی کلاینتی که route لاگین رو میکوبه رو بگیره. به گفتهٔ نویسنده هیچکدوم اینا کار اپلیکیشن نیست و اپ جای اشتباهیه برای گذاشتنشون.
ایدهٔ بزرگ اینه که Nginx تبدیل میشه به تنها «در ورودی». عموم مردم با Nginx حرف میزنن و Nginx از یه اتصال خصوصی که هیچوقت از سرور بیرون نمیره با اپ حرف میزنه. اپ دیگه روبهاینترنت نیست و رو یه پورت local گوش میده که فقط Nginx بهش دسترسی داره، درحالیکه Nginx همهچیز بیرونی مثل گواهی و پورت عمومی و timeoutها و محدودیتها رو نگه میداره. نویسنده توضیح میده کلمهٔ «reverse» یعنی برعکس forward proxy: بهجای اینکه یه پروکسی جلوی کلاینتها باشه، یه پروکسی جلوی سرورهای توئه و درخواستهای کلی از طرف اونا رو میگیره.
بخش مهم مقاله معماری داخلی Nginxـه. این ابزار با یه پروسهٔ master و چندتا پروسهٔ worker اجرا میشه. مستر کانفیگ رو میخونه، پورتها رو bind میکنه و workerها رو مدیریت میکنه ولی خودش هیچ درخواستی رو سرو نمیکنه؛ موقع reload هم اونه که workerهای جدید رو بالا میاره و به قدیمیها اجازه میده درخواستهای در جریانشون رو تموم کنن. خود workerها کار سرو رو انجام میدن و هرکدوم یه پروسهٔ تک با یه event loopـه.
نویسنده این مدل رو با مدل قدیمی Apache مقایسه میکنه که بهازای هر اتصال یه thread یا پروسه میساخت؛ هزار کلاینت بیکار یعنی هزار thread که حافظه میگرفتن. اما یه worker تو Nginx هزاران اتصال رو همزمان باز نگه میداره و فقط وقتی سراغ یکی میره که واقعاً اتفاقی روش بیفته، اونم از طریق سیستم اطلاعرسانی رویداد کرنل یعنی epoll رو لینوکس. نتیجه اینه که یه کلاینت کند برای Nginx تقریباً هیچ هزینهای نداره، درحالیکه همون کلاینت تو یه سرور thread-per-connection یه worker کامل رو قفل میکرد.
برای بخش عملی، سادهترین server block اینطوریه که رو 443 با SSL گوش میده و درخواستها رو به اپ روی پورت local فوروارد میکنه:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
}
}نویسنده میگه server_name تعیین میکنه کدوم بلاک به درخواست جواب بده و هدر Host بلاک درست رو انتخاب میکنه؛ یه Nginx میتونه چندین بلاک برای چند دامنه رو یه پورت داشته باشه. یه نکتهٔ ظریف هم دربارهٔ proxy_pass و اسلش انتهایی هست: با اسلش انتهایی، درخواست به /api/users به اپ به شکل /users میرسه چون Nginx پیشوند /api/ رو حذف میکنه؛ بدون اسلش، کل مسیر دستنخورده رد میشه.
یه نکتهٔ عملی مهم دیگه پاسدادن اطلاعات واقعی کلاینتـه. چون اپ درخواست رو از طرف Nginx میبینه، بهطور پیشفرض فکر میکنه همهٔ کلاینتها 127.0.0.1 هستن که این logging و rate limiting رو خراب میکنه. راهحل اینه که Nginx این اطلاعات رو بهصورت هدر جلو بفرسته:
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;
}نویسنده توضیح میده که X-Forwarded-Proto به اپ میگه درخواست اصلی http بوده یا https، چون بعد از ترمینیتشدن TLS چیزی که به اپ میرسه HTTP سادست و بدون این هدر ممکنه اپ لینکهای https:// رو اشتباهی http:// بسازه. تو ادامهٔ مقاله سراغ موضوعاتی مثل نیاز WebSocket به Upgrade، بحث buffering و timeout، تفاوت HTTP/2 با HTTP/1.1، فشردهسازی با gzip و تنظیم تعداد workerها متناسب با CPU سرور هم میره.
نکات کلیدی:
- ایدهٔ اصلی: اپ فقط کد اجرا کنه و Nginx بهعنوان تنها در ورودی، کارهای روبهاینترنت (TLS، فایل استاتیک، timeout، محدودیتها) رو به عهده بگیره
- reverse proxy یعنی یه پروکسی جلوی سرورهای تو که درخواست کلاینتها رو از طرف اونا میگیره
- معماری master/worker با event loop مبتنی بر epoll باعث میشه کلاینت کند برای Nginx تقریباً بیهزینه باشه، برخلاف مدل thread-per-connection
- تو proxy_pass وجود یا نبود اسلش انتهایی مسیر رسیده به اپ رو عوض میکنه
- بدون proxy_set_header، اپ IP همهٔ کلاینتها رو 127.0.0.1 میبینه؛ این هدرها IP و پروتکل واقعی رو منتقل میکنن




