کانفیگ nginx reverse proxy برای Node.js و Next.js

برنامه‌هایی مثل Node.js، Next.js، Django یا Go معمولاً روی یک پورت محلی (مثلاً ۳۰۰۰) اجرا می‌شوند. nginx جلوی آن‌ها قرار می‌گیرد، SSL را مدیریت می‌کند، فایل‌های استاتیک را سریع‌تر سرو می‌کند و درخواست‌ها را به برنامه می‌رساند.

وب‌سرور و SSLمتوسط12 دقیقه

۱اجرای برنامه فقط روی localhost

برنامه را روی 127.0.0.1 گوش بدهید تا مستقیماً از اینترنت در دسترس نباشد و همهٔ ترافیک از nginx بگذرد. نمونه با Docker:

bash
docker run -d --name app --restart unless-stopped -p 127.0.0.1:3000:3000 myapp:latest
curl -I http://127.0.0.1:3000

۲تعریف WebSocket در بخش http (یک بار)

این map را یک بار در فایل جداگانه‌ای داخل conf.d بگذارید تا همهٔ سایت‌ها از آن استفاده کنند.

nginx
sudo nano /etc/nginx/conf.d/websocket-map.conf

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

۳server block با reverse proxy

بلوک upstream چند ویژگی مفید دارد: نام‌گذاری برنامه، keepalive برای کاهش تعداد اتصال‌ها و امکان افزودن سرور دیگر در آینده. هدرهای X-Forwarded-* به برنامه می‌گویند کاربر واقعی کیست.

nginx
sudo nano /etc/nginx/sites-available/app.example.com

upstream app_backend {
    server 127.0.0.1:3000;
    keepalive 32;
}

server {
    listen 80;
    listen [::]:80;
    server_name app.example.com;

    client_max_body_size 20m;

    location / {
        proxy_pass http://app_backend;
        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;

        # WebSocket و HTTP/1.1 keepalive
        proxy_set_header Upgrade    $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_connect_timeout 5s;
        proxy_read_timeout    60s;
        proxy_send_timeout    60s;
    }
}

برای WebSocket طولانی‌مدت (مثل چت) proxy_read_timeout را بیشتر کنید، مثلاً 3600s.

۴فعال‌سازی و تست

لینک را بسازید، کانفیگ را تست و reload کنید.

bash
sudo ln -s /etc/nginx/sites-available/app.example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
curl -I -H "Host: app.example.com" http://127.0.0.1

۵سرو مستقیم فایل‌های استاتیک با nginx (اختیاری، سریع‌تر)

برای Next.js و SPA ها می‌توانید فایل‌های ثابت را بدون رسیدن به برنامه از دیسک سرو کنید. مسیر alias را با مسیر واقعی پروژه عوض کنید.

nginx
    location /_next/static/ {
        alias /opt/myapp/.next/static/;
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }

۶برنامه‌ای که زیر یک مسیر (subpath) قرار دارد

اگر می‌خواهید برنامه روی /dashboard/ باشد، به انتهای proxy_pass یک اسلش بدهید تا آن پیشوند حذف شود.

nginx
    location /dashboard/ {
        proxy_pass http://127.0.0.1:8080/;
        proxy_set_header Host $host;
    }

وجود یا نبود اسلش انتهای proxy_pass معنی متفاوتی دارد: با اسلش مسیر location جایگزین می‌شود و بدون آن مسیر کامل ارسال می‌شود.

۷عیب‌یابی خطای 502 Bad Gateway

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

bash
ss -tlnp | grep 3000
docker ps
sudo tail -n 30 /var/log/nginx/error.log

پرسش‌های پرتکرار دربارهٔ کانفیگ nginx reverse proxy برای Node.js و Next.js

چرا برنامه IP کاربر را نمی‌بیند و همه‌جا 127.0.0.1 است؟

چون درخواست از nginx می‌آید. باید هدر X-Forwarded-For را در برنامه (مثلاً trust proxy در Express) بخوانید یا در nginx ماژول real_ip را تنظیم کنید.

چرا WebSocket قطع می‌شود؟

احتمالاً هدرهای Upgrade و Connection ارسال نمی‌شوند یا proxy_read_timeout کوتاه است. تنظیمات map و هدرهای این راهنما را بررسی کنید.