nginx به عنوان reverse proxy: از صفر تا یک پیکربندی قابل اتکا

· ۷ دقیقه مطالعه

شبکهلینوکس

تقریباً هر برنامه‌ی وبی که روی سرور می‌گذارم پشت nginx می‌نشیند. خود برنامه روی یک درگاه محلی مثل 127.0.0.1:3000 گوش می‌دهد و nginx تنها چیزی است که از بیرون دیده می‌شود. این جداسازی سه فایده دارد: گواهی TLS فقط یک جا مدیریت می‌شود، فایل‌های ایستا بدون درگیر کردن برنامه تحویل داده می‌شوند، و اگر برنامه از کار بیفتد دست‌کم یک صفحه‌ی خطای آبرومند نشان می‌دهیم.

ساده‌ترین پیکربندی

روی اوبونتو فایل‌های داخل /etc/nginx/conf.d/ خودکار بارگذاری می‌شوند. یک فایل تازه بسازید:

server {
    listen 443 ssl http2;
    server_name example.ir;

    ssl_certificate     /etc/ssl/example.ir/fullchain.pem;
    ssl_certificate_key /etc/ssl/example.ir/privkey.pem;

    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;
    }
}

چهار سرآیند proxy_set_header تزیینی نیستند. بدون Host برنامه نمی‌داند با چه دامنه‌ای صدا زده شده و لینک‌هایی که می‌سازد به 127.0.0.1 اشاره می‌کنند. بدون X-Forwarded-Proto برنامه فکر می‌کند درخواست با HTTP آمده و ممکن است در یک حلقه‌ی تغییر مسیر بی‌پایان به HTTPS بیفتد.

اسلش آخر proxy_pass مهم است

این همان جایی است که بیشترین وقت را از من گرفته. اگر بعد از نشانی در proxy_pass مسیری بنویسید (حتی فقط یک /)، nginx بخشی از نشانی را که با location جور شده حذف و مسیر شما را جایگزین می‌کند. اگر ننویسید، نشانی دست‌نخورده رد می‌شود.

location /api/ {
    proxy_pass http://127.0.0.1:3000;     # /api/users -> /api/users
}

location /api/ {
    proxy_pass http://127.0.0.1:3000/;    # /api/users -> /users
}

WebSocket

اتصال WebSocket با یک درخواست HTTP معمولی شروع می‌شود که سرآیند Upgrade دارد. nginx به طور پیش‌فرض این سرآیند را رد نمی‌کند، پس باید صریح بگویید:

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

location /socket/ {
    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 300s;
}

مقدار proxy_read_timeout را هم بالا ببرید. پیش‌فرض آن ۶۰ ثانیه است و اتصالی که یک دقیقه ساکت بماند بسته می‌شود.

قبل از هر بارگذاری مجدد

nginx -t && systemctl reload nginx

nginx -t پیکربندی را بدون اعمال کردن بررسی می‌کند. reload هم برخلاف restart اتصال‌های باز را قطع نمی‌کند. این دو را همیشه با هم اجرا کنید تا یک غلط تایپی کل سایت را پایین نیاورد.