آموزش سرور

آموزش کانفیگ Nginx؛ server block، location و میزبانی چند سایت روی یک سرور

تهیه: کلودیفای (نگارش با کمک هوش مصنوعی) · انتشار: · زمان مطالعه: ۷ دقیقه

https://example.comNginxserverblockآموزش سرورآموزش کانفیگ Nginx؛ serverblock، location و میزبانی چندسایت روی یک سرورمجلهٔ کلودیفایclodify.net/blog
پاسخ کوتاه

پیکربندی Nginx از بلوک‌های تودرتو ساخته شده است: بلوک http تنظیمات سراسری را دارد، هر سایت یک server block با listen و server_name دارد و داخل آن بلوک‌های location تعیین می‌کنند هر مسیر چطور پاسخ داده شود. در اوبونتو هر سایت را در فایلی جداگانه در sites-available بنویسید، با لینک در sites-enabled فعال کنید، همیشه با nginx -t تست کنید و با systemctl reload nginx بدون قطعی اعمال کنید.

چرا یادگیری کانفیگ Nginx ارزش دارد؟

Nginx یکی از پرکاربردترین وب‌سرورهای جهان است و روی سرورهای امروزی نقش‌های مختلفی دارد: میزبانی فایل‌های ثابت، اجرای سایت‌های PHP با PHP-FPM، Reverse Proxy جلوی برنامه‌های Node.js و پایتون و کانتینرهای داکر، و پایان دادن به HTTPS. همهٔ این کارها با چند مفهوم ساده در فایل پیکربندی انجام می‌شود. کسی که این مفاهیم را بفهمد، به‌جای کپی کردن تکه‌کدهای ناشناخته، می‌تواند هر پیکربندی را بخواند و خطاهایش را پیدا کند.

برای نصب Nginx روی اوبونتو یا دبیان:

sudo apt update && sudo apt install -y nginx
sudo systemctl enable --now nginx
ساختار تودرتوی پیکربندی Nginx
httpتنظیمات سراسری: لاگ، فشرده‌سازی، بافرها
serverیک سایت: listen و server_name
locationرفتار هر مسیر: فایل، PHP یا proxy
دستورهاroot، try_files، proxy_pass و…؛ با نقطه‌ویرگول
شکل ۱ دستورهای بلوک بیرونی به بلوک‌های داخلی به ارث می‌رسند، مگر اینکه بازتعریف شوند.

ساختار فایل‌ها در اوبونتو و دبیان

مسیر کاربرد
/etc/nginx/nginx.conf فایل اصلی و تنظیمات سراسری
/etc/nginx/sites-available/ پیکربندی هر سایت در یک فایل
/etc/nginx/sites-enabled/ لینک به سایت‌های فعال
/etc/nginx/conf.d/ فایل‌های پیکربندی اضافی (همیشه بارگذاری می‌شوند)
/etc/nginx/snippets/ تکه‌های قابل استفادهٔ مجدد
/var/log/nginx/ لاگ دسترسی و خطا

فایل اصلی با دستور include محتوای sites-enabled و conf.d را بارگذاری می‌کند. روش رایج این است که هر سایت را در یک فایل جداگانه در sites-available بنویسید و با ساختن لینک در sites-enabled فعالش کنید. با حذف لینک، سایت غیرفعال می‌شود بی‌آنکه پیکربندی‌اش از بین برود. در توزیع‌های خانوادهٔ Red Hat این دو پوشه وجود ندارد و همهٔ فایل‌ها در conf.d قرار می‌گیرند.

ساختار بلوک‌ها: http، server و location

پیکربندی Nginx از «دستورها» (Directive) تشکیل شده که هرکدام با نقطه‌ویرگول تمام می‌شوند، و «بلوک‌ها» که دستورها را در آکولاد گروه‌بندی می‌کنند:

  • بلوک http: تنظیمات کلی وب مثل فشرده‌سازی، اندازهٔ بافرها و قالب لاگ. همهٔ سایت‌ها داخل آن هستند.
  • بلوک server: یک سایت یا یک «میزبان مجازی». با listen (پورت) و server_name (نام دامنه) مشخص می‌شود.
  • بلوک location: داخل server؛ تعیین می‌کند درخواست‌های یک مسیر خاص چطور پاسخ داده شوند.

قاعدهٔ مهم ارث‌بری: دستوری که در بلوک بیرونی تعریف شود، در بلوک‌های داخلی هم اعمال می‌شود، مگر اینکه بلوک داخلی آن را بازتعریف کند.

اولین server block

یک سایت ساده با فایل‌های ثابت:

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

    root /var/www/example.com;
    index index.html;

    access_log /var/log/nginx/example.access.log;
    error_log  /var/log/nginx/example.error.log;

    location / {
        try_files $uri $uri/ =404;
    }
}

این فایل را در /etc/nginx/sites-available/example.com ذخیره کنید و سپس:

sudo mkdir -p /var/www/example.com
echo "Hello" | sudo tee /var/www/example.com/index.html
sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

try_files می‌گوید: ابتدا فایلی با همین مسیر را پیدا کن، اگر نبود پوشه‌ای با این نام، و اگر هیچ‌کدام نبود خطای ۴۰۴ بده. برای برنامه‌های تک‌صفحه‌ای (React، Vue) آخرین گزینه را /index.html قرار دهید تا همهٔ مسیرها به برنامه برسند.

Nginx چطور درخواست را مسیریابی می‌کند
پورت ۸۰/۴۴۳مسیر URLپردازشدرخواستHost: shop.example.comانتخاب serverتطبیق server_nameانتخاب location/api/ یا فایل ثابتپاسخفایل، PHP-FPM یا proxyپورت ۸۰/۴۴۳مسیر URLپردازشدرخواستHost: shop.example.comانتخاب serverتطبیق server_nameانتخاب location/api/ یا فایل ثابتپاسخفایل، PHP-FPM یا proxy
شکل ۲ ابتدا سایت با نام دامنه و سپس رفتار با مسیر درخواست انتخاب می‌شود.

Nginx چطور سایت درست را انتخاب می‌کند؟

وقتی چند server block روی یک پورت دارید، Nginx هدر Host درخواست را با server_name هر بلوک مقایسه می‌کند. اگر هیچ‌کدام تطبیق نکند، درخواست به server پیش‌فرض آن پورت می‌رود؛ یعنی اولین بلوک یا بلوکی که default_server دارد. این موضوع دلیل یک اتفاق رایج است: دامنه‌ای را به سرور وصل می‌کنید و سایت دیگری نمایش داده می‌شود.

توصیه می‌شود یک server پیش‌فرض بسازید که درخواست‌های ناشناس (مثلاً با آی‌پی مستقیم یا دامنه‌های ثبت‌نشده) را رد کند:

server {
    listen 80 default_server;
    listen [::]:80 default_server;
    server_name _;
    return 444;
}

کد ۴۴۴ مخصوص Nginx است و اتصال را بدون پاسخ می‌بندد.

قواعد تطبیق location

ترتیب نوشتن locationها مهم نیست؛ Nginx بر اساس نوع تطبیق اولویت می‌دهد:

  1. location = /path تطبیق دقیق؛ بالاترین اولویت.
  2. location ^~ /path پیشوند که جلوی بررسی عبارت‌های منظم را می‌گیرد.
  3. location ~ regex و location ~* regex عبارت منظم (دومی بدون حساسیت به حروف)؛ به ترتیب نوشتن بررسی می‌شوند و اولین تطبیق برنده است.
  4. location /path پیشوند معمولی؛ طولانی‌ترین تطبیق انتخاب می‌شود.

مثال‌های کاربردی:

# کش طولانی برای فایل‌های ثابت
location ~* \.(css|js|png|jpg|webp|svg|woff2)$ {
    expires 30d;
    access_log off;
}

# جلوگیری از دسترسی به فایل‌های مخفی مثل .git و .env
location ~ /\. {
    deny all;
}

# ارسال یک مسیر به برنامهٔ پشتی
location /api/ {
    proxy_pass http://127.0.0.1:3000;
}

چند سایت روی یک سرور

برای هر دامنه یک فایل جداگانه در sites-available بسازید که server_name و root خودش را دارد، و هرکدام را با لینک فعال کنید. Nginx هر درخواست را با توجه به نام دامنه به سایت درست می‌فرستد. همه می‌توانند روی پورت‌های ۸۰ و ۴۴۳ یک آی‌پی باشند. پس از ساخت رکوردهای DNS هر دامنه (آموزش در تنظیم رکوردهای DNS)، برای هر کدام گواهی SSL بگیرید؛ مراحل در آموزش Nginx و Let's Encrypt آمده است.

سایت PHP با PHP-FPM

برای وردپرس یا لاراول، فایل‌های PHP باید به PHP-FPM فرستاده شوند:

location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}

نسخهٔ PHP را با نسخهٔ نصب‌شده روی سرور یکی کنید؛ مسیر سوکت را با ls /run/php/ ببینید. اشتباه در این مسیر یکی از علت‌های رایج خطای 502 Bad Gateway است.

root@server: ~
$ ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/$ nginx -tnginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful$ systemctl reload nginx$ curl -sI -H 'Host: example.com' http://127.0.0.1 | head -n 1HTTP/1.1 200 OK$ 
شکل ۳ فعال‌سازی سایت، تست پیکربندی، بارگذاری دوباره و بررسی پاسخ با هدر Host.

ریدایرکت‌های رایج: HTTPS و www

تقریباً هر سایتی به دو ریدایرکت نیاز دارد: هدایت همهٔ درخواست‌های HTTP به HTTPS، و یکی کردن نسخهٔ با www و بدون www تا موتورهای جست‌وجو دو نسخه از سایت نبینند. روش درست در Nginx استفاده از دستور return در یک server block جداگانه است، نه rewrite یا شرط if:

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

کد ۳۰۱ یعنی انتقال دائمی و به مرورگرها و موتورهای جست‌وجو می‌گوید آدرس اصلی کدام است. متغیر $request_uri مسیر و پارامترهای درخواست را حفظ می‌کند تا کاربر دقیقاً به همان صفحه برسد. اگر Certbot را برای گرفتن گواهی اجرا کنید، معمولاً ریدایرکت HTTP به HTTPS را خودش اضافه می‌کند.

در کار با Nginx چند متغیر را زیاد می‌بینید: $host نام دامنهٔ درخواست، $uri مسیر بدون پارامترها، $remote_addr آی‌پی کلاینت و $scheme پروتکل (http یا https). وقتی سایت پشت CDN یا پروکسی دیگری است، $remote_addr آی‌پی همان پروکسی است، نه کاربر واقعی؛ برای دریافت آی‌پی واقعی باید ماژول real_ip را پیکربندی کنید.

تست، بارگذاری دوباره و عیب‌یابی

پیش از هر بارگذاری دوباره، پیکربندی را تست کنید. اگر خطای نگارشی وجود داشته باشد، nginx -t شمارهٔ خط را نشان می‌دهد و سایت فعلی دست‌نخورده می‌ماند:

sudo nginx -t
sudo systemctl reload nginx     # اعمال بدون قطع اتصال‌های فعلی
sudo nginx -T | less            # دیدن کل پیکربندی نهایی بارگذاری‌شده

تفاوت reload و restart: reload پیکربندی جدید را بدون قطع اتصال‌های جاری اعمال می‌کند و اگر پیکربندی خطا داشته باشد، Nginx با پیکربندی قبلی به کار ادامه می‌دهد؛ restart سرویس را کامل متوقف و اجرا می‌کند. در کار روزمره همیشه reload را ترجیح دهید.

خطاهای پرتکرار: فراموش کردن نقطه‌ویرگول در انتهای دستور، آکولاد باز یا بسته‌نشده، دو server block با یک server_name روی یک پورت (هشدار conflicting server name) و مجوز نادرست پوشهٔ root که به خطای ۴۰۳ می‌انجامد. لاگ خطای هر سایت دقیق‌ترین منبع عیب‌یابی است. مستندات کامل دستورها در nginx.org موجود است.

یک عادت خوب دیگر این است که پیش از هر تغییر بزرگ، از پوشهٔ /etc/nginx نسخهٔ پشتیبان بگیرید یا آن را در گیت نگه دارید. به این ترتیب اگر تغییری رفتار سایت را خراب کرد، در چند ثانیه به پیکربندی سالم قبلی برمی‌گردید و لازم نیست زیر فشار قطعی سایت، خط‌به‌خط دنبال اشتباه بگردید.

اگر برای میزبانی چند سایت به سرور نیاز دارید، سرور مجازی ایران کلودیفای با دسترسی root و صورتحساب ساعتی در دسترس است.

سؤالات متداول

تفاوت sites-available و sites-enabled چیست؟

در sites-available پیکربندی همهٔ سایت‌ها نگهداری می‌شود و در sites-enabled فقط لینک به سایت‌های فعال قرار دارد. Nginx فقط sites-enabled را می‌خواند؛ پس با حذف لینک، سایت غیرفعال می‌شود بدون اینکه فایل پیکربندی از بین برود.

چرا دامنهٔ جدید سایت دیگری را نشان می‌دهد؟

چون هیچ server blockی با server_name آن دامنه تطبیق ندارد و درخواست به server پیش‌فرض رفته است. server_name را درست بنویسید و یک server پیش‌فرض برای رد درخواست‌های ناشناس بسازید.

reload بهتر است یا restart؟

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

خطای 403 Forbidden در Nginx از کجاست؟

معمولاً یا فایل index در پوشهٔ root وجود ندارد و فهرست پوشه غیرفعال است، یا کاربر www-data اجازهٔ خواندن پوشه یا یکی از پوشه‌های والد را ندارد. مجوزها و وجود فایل index را بررسی کنید.

آماده‌اید؟ سرورتان را بسازید.

از ۱٬۲۰۰ تومان در ساعت · پرداخت ریالی

سرورتان را همین حالا بسازید.

ساعتی بپردازید. هر وقت خواستید حذف کنید.