راه اندازی ریورس پروکسی در nginx

 

فرض کنید می‌خواهیم چندین سرویس مختلف را روی یک سرور واحد و از روی پورت عادی 80 سرو کنیم. مشکلی که به آن برمی‌خوریم این است که نمی‌شود چندین سرویس روی یک پورت یکسان پاسخگو باشند و قطعاً به ارور مشغول بودن آن پورت (port already in use) برمی‌خوریم.

برای حل این مشکل می‌توانیم از راه‌حلی که وب‌سرور nginx ارائه داده استفاده کنیم.

معرفی nginx

وب‌سرور Nginx یک وب‌سرور سبک و سریع است که برای سرو کردن فایل‌های وب، مدیریت ترافیک و به‌عنوان reverse proxy استفاده می‌شود. به زبان ساده، Nginx کمک می‌کند درخواست‌های کاربران بهتر و سریع‌تر به برنامه یا سایت شما برسند و برای سایت‌های کوچک تا بزرگ کاربرد زیادی دارد.

معرفی ریورس پروکسی

ریورس پروکسی درخواست‌های کاربران را به جای اینکه مستقیم به برنامه اصلی برسد، ابتدا خودش دریافت می‌کند و بعد آن را به سرویس داخلی مناسب فوروارد می‌کند.

قرار دادن این لایه‌ی میانی چند مزیت مهم هم دارد:

  • load balancing: می‌توان ترافیک یک دامنه را بین چند نمونه از یک سرویس پخش کرد تا فشار روی یک نمونه جمع نشود
  • مدیریت متمرکز دامنه‌ها: همه‌ی دامنه‌ها و ساب‌دامنه‌ها در فایل‌های کانفیگ nginx تعریف می‌شوند؛ افزودن، تغییر یا حذف هر سرویس فقط یک بلاک server است و بدون دست زدن به خود سرویس‌ها انجام می‌شود
  • افزایش سرعت لود شدن سابت:caching می‌تواند پاسخ‌های پرمصرف (فایل‌های استاتیک، صفحات پرتکرار) را کش کند و برای درخواست‌های بعدی به جای رفتن به بکند، مستقیم و سریع‌تر از خودش تحویل دهد
  • مخفی ماندن سرویس‌های داخلی: سرویس‌های اصلی روی پورت‌های داخلی بالا می‌آیند و فقط nginx در معرض اینترنت قرار می‌گیرد

آماده‌سازی سرور برای کانفیگ nginx

برای اینکه بتوانیم ریورس پروکسی خود را تنظیم کنیم لازم است به جای اینکه سرویس‌ها روی پورت 80 بالا بیایند، هرکدام را روی یک پورت داخلی و مخصوص به خودش بالا بیاوریم.
الان دو سرویس روی پورت‌های 3000 و 3001 سرور در حال اجرا هستند. ماهیت این دو سرویس مهم نیست؛ هر برنامه‌ای می‌تواند جای آن‌ها بنشیند، چون از این به بعد فقط nginx است که با آن‌ها حرف می‌زند.

ساختار فایل‌های کانفیگ nginx

برای تنظیم کردن nginx به شکلی که مطلوب ما است باید فایل‌های کانفیگ آن را که در مسیر /etc/nginx/ قرار دارند تغییر دهیم. در این مسیر چند فایل مختلف وجود دارد:

ls /etc/nginx
conf.d
fastcgi.conf
fastcgi_params
koi-utf
koi-win
mime.types
modules-available
modules-enabled
nginx.conf
proxy_params
scgi_params
sites-available ### دایرکتوری‌ای که تغییرات را در آن می‌نویسیم
sites-enabled ### فایل‌ها فقط با سیم‌لینک به اینجا منتقل می‌شوند
snippets
uwsgi_params
win-utf

بین فایل‌های نسبتاً زیاد nginx ما فقط با دو دایرکتوری مشخص‌شده کار می‌کنیم. کانفیگ‌های مربوط به سایت‌ها را ابتدا در دایرکتوری sites-available می‌نویسیم و بعد با دستور زیر به فهرست سایت‌های فعال اضافه‌شان می‌کنیم:

sudo ln -s /etc/nginx/sites-available/dornadevops.com /etc/nginx/sites-enabled/

نکته‌ی مهم این است که این سیم‌لینک به تنهایی هیچ خاصیتی ندارد؛ دلیل جواب دادن این روش آن است که فایل اصلی nginx.conf با دستور include محتوای همه‌ی فایل‌های داخل sites-enabled را لود می‌کند. پس هر فایلی که به آنجا لینک شود عملاً بخشی از کانفیگ اصلی nginx می‌شود.

بعد از هر تغییر هم همیشه اول صحت کانفیگ را تست می‌کنیم و بعد nginx را reload می‌کنیم این ترتیب را از همین‌جا عادت کنید تا در صورت وجود یک اشتباه تایپی، سرویس با یک کانفیگ خراب ری‌استارت نشود:

sudo nginx -t
sudo systemctl reload nginx

محتویات فایل‌های کانفیگ و سینتکس آن‌ها

حالا فایل /etc/nginx/sites-available/dornadevops.com را می‌سازیم. برای هر دو سرویسمان یک بلاک server جداگانه می‌نویسیم:

# سرویس اول: سایت اصلی
server {
        listen 80;
        server_name dornadevops.com www.dornadevops.com;

        location / {
                proxy_pass http://127.0.0.1:3000;
                proxy_http_version 1.1;
                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;
        }
}

# سرویس دوم: دامنه و پورت متفاوت، اما همان listen 80
server {
        listen 80;
        server_name api.dornadevops.com;

        location / {
                proxy_pass http://127.0.0.1:3001;
                proxy_http_version 1.1;
                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;
        }
}

نکته‌ی کلیدی اینجاست: هر دو بلاک روی همان یک پورت 80 گوش می‌دهند و nginx بر اساس هدر Host درخواست (همان مقدار server_name) تشخیص می‌دهد هر درخواست باید به کدام سرویس فوروارد شود.

کانفیگ nginx دستور زبان و ساختار خاص خود را دارد. در جدول پایین بخش های مهم syntax کانفیگ فایل را بررسی میکنیم

TermMeaning
serverبلاک سرور؛ همه چیز از اینجا شروع می‌شود
listen 80;پورتی که این بلاک روی آن گوش می‌دهد؛ هر دو بلاک ما روی 80 هستند
server_nameدامنه‌هایی که این بلاک برای آن‌ها پاسخ می‌دهد؛ برای چند دامنه (مثل www.dornadevops.com) کافی است کنار هم نوشته شوند
location /مشخص‌کننده‌ی مسیر ریشه‌ی دامنه و هر چیزی که پایین‌تر از آن قرار می‌گیرد
proxy_pass http://127.0.0.1:3000;مشخص‌کننده‌ی مقصد پروکسی برای این دامنه که درخواست‌ها را به پورت 3000 سرور ارسال می‌کند
proxy_http_version 1.1;نسخه‌ی پروتکل مورد استفاده برای حرف زدن با بکند؛ فعال کردن آن برای keep-alive و پشتیبانی از WebSocket لازم است
proxy_set_header Host $host;هدر اصلیِ هاست را به بک‌اند ارسال می‌کند
proxy_set_header X-Real-IP $remote_addr;آدرس IP واقعیِ کاربر را به بک‌اند ارسال می‌کند
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;آدرس IP کاربر را به زنجیرهٔ فوروارد اضافه می‌کند
proxy_set_header X-Forwarded-Proto $scheme;به بکند می‌گوید که درخواست https است یا http

بعد از نوشتن فایل کانفیگ، مثل همیشه اول تست و بعد reload:

sudo nginx -t
sudo systemctl reload nginx

جمع‌بندی

و به این صورت با ارسال درخواست به دامنه‌ی مدنظرمان روی پورت 80 می‌توانیم محتویات وب‌سایتِ در حال اجرا روی پورت 3000 را دریافت کنیم و به همین شکل با اضافه کردن بلاک‌های server جدید، هر سرویس دیگری را هم که روی سرور در حال اجرا است با دامنه‌ی خودش روی همان پورت واحد سرو کنیم.

قدم بعدی: ترافیک این دامنه‌ها هنوز HTTP ساده است. برای گذاشتن HTTPS رایگان روی آن‌ها می‌توانید مقاله‌ی  HTTPS رایگان برای دامنه‌های Nginx را بخوانید.