
فرض کنید میخواهیم چندین سرویس مختلف را روی یک سرور واحد و از روی پورت عادی 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 کانفیگ فایل را بررسی میکنیم
| Term | Meaning |
|---|---|
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 را بخوانید.


