نصب و راه‌اندازی NGINX


مقدمه

نرم‌افزار Nginx (بخوانید اِنجین اِکس) در واقع یک نرم‌افزار Web server است که می‌تواند به عنوان Reverse proxy یا Load balancer یا Web cache نیز مورد استفاده قرار گیرد.

- تعریف Web server :Web server یا HTTP server نرم افزاری است که بر روی یک سرور سخت‌افزاری نصب شده، Request ها را در بستری مثل HTTP از Client ها دریافت کرده و به آنها پاسخ می‌دهد. این پاسخ ها یا به صورت Static از قبل در مسیری روی سرور ذخیره شده و یا به صورت Dynamic توسط یک Web Application ساخته شده و به سمت Client ها ارسال می‌شوند. مثلا تصاویر، ویدیو ها یا فایل های CSS و Javascript و ... می‌توانند به صورت Static روی سرور ذخیره شده و توسط Web server به Client ارسال شوند. اما اطلاعاتی مثل محصولات خریداری شده توسط کاربر، دانشجویان برتر ترم جاری، آگهی های منقضی شده و ... باید به صورت لحظه ای و Dynamic از دیتابیس ها و ... جمع آوری و تجمیع شده و در قالب یک پاسخ مناسب برای Client ها ارسال شوند.
- تعریف Reverse proxy: یک Proxy server در حالت عادی، یک سرور واسط میان یک Client و سایر سرور ها است. این سرور واسط، جلوی همه درخواست های یک Client قرار گرفته، آنها را دریافت کرده و به جای او به سرور های مقصد ارسال می‌کند. تحریم شکن ها و فیلترشکن های قدیمی تر در واقع یک Proxy server بودند که همه درخواست های کاربر را گرفته و آنها را به جای او به سرور های مورد نظرش ارسال کرده و پاسخ دریافتی را به کاربر بر می گرداندند. (فیلترشکن های امروزی به جای Proxy server از VPN استفاده می‌کنند). اما Reverse proxy برعکس Proxy server معمولی است. این نوع از پراکسی به جای دریافت همه درخواست های یک Client و ارسال آنها به سرور های مختلف (Forward proxy)، درخواست های همه Client ها را دریافت کرده و به یک سرور خاص ارسال می‌کند (Reverse Proxy).
- تعریف Load balancer: با افزایش تعداد Request های وارد شده به یک سرور، منابع بیشتری از آن سرور اشغال می‌شود (Load روی سرور افزایش می‌یابد). با افزایش Load روی سرور، عملکرد آن تحت تاثیر قرار گرفته و پاسخ‌دهی به درخواست ها با کندی روبرو می‌شود. در این صورت، سرور های فعلی جوابگوی نیاز ما نیستند و باید سرور ها را Scale کنیم. ممکن است اولین ایده ای که برای Scale کردن سرور ها به ذهن برسد افزایش قدرت پردازنده و حافظه RAM باشد. به این روش Vertical Scaling می‌گوییم. اما معمولا ایده بهتر استفاده از Server Farm (چند سرور متوسط به جای یک سرور قوی) است که به روش Horizontal Scaling معروف است. در این صورت Load balancer با قرار گرفتن در جلوی ورودی Server Farm، درخواست های وارد شده را دریافت و آنها را بین چند سرور مختلف با عملکرد یکسان توزیع می‌کند.
- تعریف Web cache: معمولا سرو کردن محتوای Static توسط Web server ها بسیار ساده تر و سریعتر از محتوای Dynamic صورت می‌گیرد. برای ساختن محتوای Dynamic معمولا کوئری های نسبتا زمان‌بری به Database ها زده می‌شود و یا الگوریتم های نسبتا پیچیده ای اجرا می‌شوند. بنابراین واضح است که آماده شدن چنین محتوایی نه تنها کندتر از محتوای Static صورت می‌گیرد، بلکه منابع سخت افزاری (RAM و CPU) بیشتری را از سرور اشغال می‌کند. Web cache یا HTTP cache محتوای Dynamic تولید شده برای Request های پرتکرار را به صورت Static در سرور Cache کرده و برای درخواست های بعدی در صورت امکان از آنها استفاده می‌کند. بنابراین پاسخ درخواست های پرتکرار، بسیار سریعتر از حالت عادی داده می‌شود و همچنین بار (Load) وارد شده به سرور نیز بطور چشمگیری کاهش می‌یابد.


با اینکه بیشترین سهم از بازار Web server ها در حال حاضر (۲۰۱۹) در دست Apache HTTP Server است، با این حال Nginx به علت عملکرد بهتر در مواجهه با منابع محدود و همینطور scale پذیری بیشتر، در حال ربودن گوی سبقت از Apache است. البته Web server های دیگری مثل Microsoft IIS و LiteSpeed هم در رده های سوم و چهارم قراردارند که وقت شما را با پرداختن به آنها نمیگیریم ;)


یکی از تفاوت های Nginx با Apache HTTP Server در این است که Apache ماژول هایی دارد که به کمک آنها قادر است محتوای Dynamic (از طریق اسکریپت های PHP یا Python یا ...) را خودش پردازش و تولید کند، اما Nginx برای اینکه سبک تر و سریع تر باشد روی وظیفه اصلی خودش تمرکز کرده و ساختن محتوای Dynamic را به نرم‌افزار های مخصوص این کار مثل php-fpm برای PHP یا uWSGI برای Python می‌سپارد.

یگی دیگر از تفاوت های Apache HTTP Server و Nginx در این است که Apache هنگام سرو محتوای Static می‌تواند از هر Directory، یک فایل به نام htaccess. شامل تنظیمات Apache برای آن دایرکتوری را بخواند و تنظیمات خود را برای آن دایرکتوری Override کند. Override کردن تنظیمات به ازای هر دایرکتوری باعث پیچیدگی در مدیریت تنظیمات می‌شود و همینطور به علت در دسترس بودن، امنیت پایین تری دارد، به همین دلیل Nginx در کل چنین قابلیتی را ارایه نمی‌دهد.

اگر قصد مهاجرت از Apache HTTP Server به Nginx را دارید، می‌توانید از راهنمای این لینک استفاده کنید.

نصب Nginx روی Ubuntu

پکیج Nginx روی مخازن پیشفرض Ubuntu وجود دارد. بنابراین اجرای دستورات زیر آخرین نسخه از Nginx و پکیج های وابسته به آن را روی سیستم عامل Ubuntu نصب می‌کند.

$ sudo apt update 
$ sudo apt install nginx

سرویس Nginx پس از نصب در Ubuntu به صورت خودکار اجرا می‌شود. دستور زیر وضعیت این سرویس را نمایش می‌دهد.

$ sudo systemctl status nginx

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

چراغ سبز نشان دهنده فعال بودن سرویس است.
چراغ سبز نشان دهنده فعال بودن سرویس است.


در صورت نیاز به متوقف کردن سرویس Nginx می‌توانید از دستور زیر استفاده کنید:

$ sudo systemctl stop nginx

برای راه اندازی این سرویس وقتی که در حالت توقف است، از دستور زیر استفاده می‌شود:

$ sudo systemctl start nginx

زمانی که تنظیمات Nginx تغییر می‌کند، برای اعمال تغییرات می‌توانید این سرویس را Restart کنید. این کار معادل Stop و سپس Start کردن سرویس است:

$ sudo systemctl restart nginx

زمانی که Nginx را Restart می‌کنید، همه درخواست هایی که در حال پردازش بوده اند قطع (Drop) شده و تا زمان کامل شدن فرآیندِ اجرای مجددِ سرویس، هیچ درخواستی پاسخ داده نمی‌شود. برای اینکه بدون Down شدن سایت یا سرویس های آن بتوانیم تغییرات Nginx را اعمال کنیم، می‌توان به جای Restart از Reload استفاده کرد. در این صورت درخواست هایی که در حال اجرا هستند با تنظیمات قدیم و درخواست های جدید با تنظیمات جدید پاسخ داده می‌شوند.

$ sudo systemctl reload nginx

سرویس Nginx پس از نصب در Ubuntu به صورت پیش‌فرض Enable است. به این معنی که هر بار که سیستم عامل (کامپیوتری که Nginx روی آن نصب شده) Restart شود، این سرویس به صورت خودکار اجرا می‌شود. در صورت نیاز به Disable کردن این سرویس می‌توان از دستور زیر استفاده کرد:

$ sudo systemctl disable nginx

و همینطور برای Enable کردن آن در صورت Disable بودن، از دستور زیر استفاده می‌شود:

$ sudo systemctl enable nginx


بررسی صحت عملکرد Nginx

حال که Nginx را نصب کرده و وضعیت این سرویس را بررسی کردید می‌توانید عملکرد آن را تست کنید. Nginx به صورت پیش‌فرض محتوای Static موجود در آدرس var/www/html/ را که فعلا فقط یک فایل HTML است، سرو می‌کند. بنابراین با وارد کردن آدرس IP سرور خود در مرورگر وب باید این صفحه را دریافت کنید که نشان دهنده کارکرد صحیح Nginx است.

صفحه ‌Landing پیشفرض برای بررسی صحت عملکرد Nginx
صفحه ‌Landing پیشفرض برای بررسی صحت عملکرد Nginx


اگر با وارد کردن آدرس IP سرور در مرورگر، صفحه Landing بالا را مشاهده نکردید، ممکن است Firewall نصب شده روی سرور، اجازه دسترسی به سرور از طریق پورت HTTP (پورت ۸۰) را نمی‌دهد. بنابراین پس از چک کردن درستی آدرس IP و همینطور بررسی وضعیت سرویس، از باز بودن پورت ۸۰ روی سرور نیز مطمین شوید.

# check Firewall status:
$ sudo ufw status

# List the registered application profiles for Firewall, Nginx should have registered 3 profiles:
# 'Nginx HTTP' --> This profile opens only port 80 (normal, unencrypted web traffic)
# 'Nginx HTTPS' --> This profile opens only port 443 (TLS/SSL encrypted traffic)
# 'Nginx Full' --> This profile opens both port 80 and 443
$ sudo ufw app list

# Enable the most restrictive profile
$ sudo ufw allow 'Nginx HTTP'

# Check Firewall status again to verify the change
$ sudo ufw status


تنظیمات Nginx

حال که Nginx به درستی نصب و اجرا شده و در حال سرو کردن سایت Static پیشفرض است، می‌توان تنظیمات آن را تغییر داد.

تمامی فایل های مرتبط با تنظیمات Nginx در آدرس etc/nginx/ در سرور قرار دارند. فایل nginx.conf در این آدرس، شامل تنظیمات اصلی Nginx است. در زمان اجرای Nginx، تنظیمات موجود در این فایل بر روی Nginx اعمال می‌شوند.

اگر این فایل را باز کنید مشاهده خواهید کرد که ساختار کلی آن به شکل زیر است:

user www-data;
worker_processes auto;
include /etc/nginx/modules-enabled/*.conf;

events {
    worker_connections 768;
}

http {

    # Basic Settings
    keepalive_timeout 65;
    server_names_hash_bucket_size 64;
    include /etc/nginx/mime.types;
    
    # SSL Settings
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
    ssl_prefer_server_ciphers on;
    
    # Logging Settings
    access_log /var/log/nginx/access.log;
    error_log /var/log/nginx/error.log;
    
    # Gzip Settings
    gzip on;
    
    # Virtual Host Configs
    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
        
}
        
mail {

    server {
        ...
    }
    
}

همانطور که می‌بینید، ساختار این فایل به صورت یک سلسله مراتب از بلاک (Block) ها است. برای مثال بلاکِ events، بلاکِ http، بلاکِ mail و ... اما قبل از شروع شدن بلاک ها، تعدادی دستورالعمل (دایرکتیو) کلی (مثلا ;user www-data و ...) وجود دارند که تنظیمات خیلی کلی و عمومی Nginx را مشخص می‌کنند. برای مثال، Nginx در واقع یک پراسس اصلی (Master Process) در سیستم عامل دارد که فقط مسئولیت خواندن، ارزیابی و اعمال تنظیمات و همینطور مدیریت پراسس های کارگر (Worker Processes) را به عهده دارد. در واقع درخواست هایی که به سمت Nginx می‌آیند، توسط پراسس اصلی پردازش نمی‌شوند، بلکه تعدادی (معمولا به تعداد هسته های پردازشگر کامپیوتر) پراسس کارگر (Worker Process) که به وسیله پراسس اصلی ایجاد شده اند، به صورت همزمان، مسیولیت پردازش درخواست ها را به عهده می‌گیرند. دایرکتیو ;worker_processes auto به Nginx می‌فهماند که به تعداد هسته های پردازنده، Worker Process ایجاد کند.

برای یافتن تعداد هسته های پردازشی در یک سیستم لینوکسی می‌توانید از دستور زیر در ترمینال استفاده کنید:
$ grep processor /proc/cpuinfo | wc -l

این Process ها باید توسط یک User در سیستم عامل اجرا شوند. کاربر www-data در سیستم عامل Ubuntu برای این منظور در نظر گرفته شده و دایرکتیو ;user www-data این کاربر را به Nginx معرفی می‌کند.

دایرکتیو ;worker_connections 768 در داخل بلاک events حداکثر تعداد اتصال (Connection) به هر Worker Process را مشخص می‌کند. بنابراین اگر سرور شما ۴ پراسس کارگر داشته باشد که هر کدام از آنها در هر لحظه مجاز به پردازش ۷۶۸ اتصال باشند، این سرور در هر لحظه می‌تواند ۳۰۷۲=۷۶۸*۴ اتصال را پاسخگو باشد.

لازم به ذکر است که تعداد worker_connections نمی‌تواند از حداکثر تعداد ممکن برای فایل های باز در سیستم عامل تجاوز کند. در صورت نیاز باید این مقدار را نیز در تنظیمات سیستم عامل تعییر دهید.

تنظیمات کلی Nginx مثل تنظیمات مربوط به SSL، تنظیمات مربوط به Log درخواست ها و خطاهای پیش آمده، تنظیمات مربوط به فشرده سازی پاسخ ها به کمک Gzip و ... در بلاک http قرار می‌گیرند.

معمولا داخل بلاک http، یک یا چند بلاک server وجود دارد و البته خود بلاک server می‌تواند شامل یک یا چند بلاک location باشد:

http {
    ...
    server {
        location {
        ...
        }
    }
    ...
}

بلاک server معمولا شامل تنظیمات مختص به Web server مانند نام سرور (مثلا www.example.com)، پروتکل ارتباطی (HTTP/HTTPS)، آدرس محتوای استاتیکی که باید سرو شود و ... است و بلاک location شامل تنظیمات مربوط به Sub-directory ها (مثلا www.example.com/blog یا www.example.com/landing یا ...) است.

اگر فایل nginx.conf در مسیر etc/nginx/ را باز کرده باشید احتمالا متوجه شده اید که برای جلوگیری از شلوغی و ناخوانا شدن تنظیمات و همینطور مدیریت بهتر آن، بخش هایی از تنظیمات مثل بلاک های server، درون فایل های جداگانه در مسیر هایی از etc/nginx/ نوشته شده و در فایل nginx.conf با دستور include به آنها اشاره شده است. Nginx هنگام اجرا، تنظیمات موجود در آن فایل ها را نیز به فایل اصلی (nginx.conf) اضافه کرده و سپس آن را می‌خواند و تنظیمات را اعمال میکند.

بلاک server برای سایت پیش فرض Nginx که پیشتر به آن اشاره شد، درون فایلی به نام default در آدرس etc/nginx/sites-enabled/ قرار دارد که با دستور ;*/include /etc/nginx/sites-enabled در بلاک http از فایل nginx.conf به آن اضافه می‌شود. بنابراین با ویرایش فایل default در مسیر مذکور برای اعمال تنظیماتی مثل نام سایت خود (مثلا www.example.com) و همینطور تغییر محتوای Static موجود در آدرس var/www/html/ به محتوای دلخواه سایت خود، می‌توانید سایت خود را توسط Nginx سرو کنید.

توجه کنید که سرویس Nginx در هنگام اجرا شدن، تنظیمات را از فایل nginx.conf می‌خواند و این تنظیمات را تا اجرای بعدی نگه می‌دارد. بنابراین پس از اعمال هرگونه تغییری در فایل های تنظیمات باید سرویس Nginx را Restart یا Reload کنید. در غیر اینصورت تغییرات شما روی Nginx اعمال نمی‌شود.
همینطور برای اطمینان از عدم وجود خطای تایپی (Syntax Error) در تنظیمات Nginx میتوانید از دستور sudo nginx -t در ترمینال استفاده کنید. این دستور، فایل های تنظیمات (nginx.conf و سایر فایل هایی که include شده اند) را از نظر املایی (Syntax) بررسی کرده و در صورت وجود اشکال، شما را مطلع می‌کند.


افزودن Server Block (یا Virtual Host)

اگر قرار باشد که فقط یک سایت روی سرور فعال باشد، با تغییر تنظیمات مربوط به سایت پیشفرض (محتوای Static موجود در مسیر var/www/html/ و فایل default موجود در مسیر etc/nginx/sites-enabled/) و Restart کردن سرویس Nginx کار تمام است اما معمولا می‌خواهیم که چندین سایت را روی یک سرور میزبانی (Host) کنیم. برای این منظور باید از مفهمومی به نام Virtual Host کمک بگیریم. Virtual Host ها در Nginx به کمک بلاک های server ساخته می‌شوند. در واقع هر بلاک server درون بلاک http معرف یک Virtual Host است که می‌تواند یک سایت جداگانه را میزبانی کند.

عبارت Virtual Host بیشتر برای Apache HTTP Server به کار می‌رود و در Nginx عبارت معادل آن Server Block است.

بنابراین باید به ازای همه سایت هایی که قرار است روی سرور میزبانی شوند، Server Block ایجاد کنیم. بلاک های server را می‌توانیم در فایل nginx.conf و داخل بلاک http تعریف کنیم، اما برای جداسازی و مدیریت بهتر فایل های تنظیمات، بهتر است هر Server Block را داخل یک فایل تنظیمات جداگانه قرار داده و در فایل nginx.conf با دستور include به آن اشاره کنیم.

برای این منظور Nginx هنگام نصب، دو دایرکتوری به نام های sites-available و sites-enabled در مسیر etc/nginx/ ایجاد می‌کند. فایل های تنظیمات مربوط به تمامی Server Block هایی که روی این سرور فعال اند (یا قرار است در آینده فعال شوند) درون دایرکتوری sites-available قرار می‌گیرند. این دایرکتوری حکم یک آرشیو را دارد و تنظیمات موجود در آن، هرگز به nginx.conf اضافه نمی‌شوند. اما اگر مجددا به تنظیمات درون فایل nginx.conf نگاه کنید متوجه خواهید شد که در انتهای بلاک http، تمام فایل های موجود در دایرکتوری sites-enabled به این فایل include شده اند. (با دستور ;*/include /etc/nginx/sites-enabled )

بنابراین اگر قرار است یک سایت (Server Block) فعال باشد و توسط Nginx پاسخ‌دهی شود، باید فایل حاوی بلاک server مربوط به آن داخل دایرکتوری sites-enabled نیز کپی شود. کپی کردن و نگه داشتن دو رونوشت یکسان از یک فایل اصلا ایده جالبی نیست زیرا یکسان نگه داشتن آنها هنگام تغییرات، کار بسیار سختی است. بنابراین ایده بهتر این است که فایل تنظیمات را داخل دایرکتوری sites-available ذخیره کرده و در دایرکتوری sites-enabled با دستور زیر یک میانبر (Symbolic Link) به آن تعریف کنیم:

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

با اجرای دستور بالا یک Symbolic Link از فایل example.com در داخل دایرکتوری sites-enabled ایجاد می‌شود. در واقع مثل این خواهد بود که فایل example.com در دایرکتوری sites-enabled نیز وجود دارد. بنابراین بار بعدی که سرویس Nginx اجرا می‌شود، محتوای فایل example.com هم به nginx.conf اضافه خواهد شد.

پس تا اینجای کار فهمیدیم که تنظیمات کلی و مشترک بین همه سایت ها را درون فایل nginx.conf نوشته و به ازای همه سایت هایی که قرار است روی سرور میزبانی شوند، یک فایل تنظیمات به نام خودشان (مثلا example.com) در مسیر etc/nginx/sites-available/ ساخته و یک Symbolic Link به آنها در مسیر etc/nginx/sites-enabled/ ایجاد می‌کنیم. سپس به کمک دستور sudo nginx -t وجود Syntax Error در فایل های تنظیمات را بررسی کرده و در صورت نیاز آنها را اصلاح می‌کنیم. در نهایت برای اعمال تنظیمات جدید، سرویس Nginx باید Restart یا Reload شود.

هر Server Block معرف یک سایت مجزا است که محتوای Static یا Dynamic را سرو می‌کند. به ازای همه سایت هایی که محتوای Static سرو می‌کنند، یک دایرکتوری در مسیر var/www/ به نام خود سایت (مثلا example.com) ساخته و محتوای Static مربوط به آن سایت را در این دایرکتوری نگه می‌داریم. دقت کنید که باید در بلاک server مربوطه در مقابل دستور root این مسیر را معرفی کنیم.

بهتر است که فایل تنظیمات و محتوای مربوط یه سایت پیشفرض Nginx را حذف نکنید تا در صورتی که درخواست ارسال شده به سرور با هیچکدام از Server Block ها همخوانی نداشت، خطایی رخ ندهد و سایت دیفالت سرو شود.

شخصی سازی تنظیمات در Server Block

حال که با کلیات راه اندازی و تنظیمات Nginx آشنا شدید، لازم است کمی به جزییات دستورات (Directive های) موجود در بلاک server بپردازیم.

اگر فایل تنظیمات Server Block پیش فرض را باز کنید با ساختاری شبیه به زیر مواجه خواهید شد. این فایل همیشه می‌تواند به عنوان یک مثال مرجع مورد استفاده قرار گیرد.

server {

    listen 80;
    server_name example.com www.example.com;
    
    root /var/www/example.com;
    index index.html index.htm;
    
    location / {
        try_files $uri $uri/ =404;
    }
    
    location /download/ {
        alias /usr/share/download/;
        autoindex on;
    }
    
}

اینکه یک درخواست هنگام وارد شدن به Nginx بر اساس کدام Server Block پاسخ‌دهی شود، به دایرکتیو های listen و server_name در Server Block ها بستگی دارد. اگر درخواست وارد شده با این دایرکتیو ها در یکی از Server Block ها همخوانی داشت، توسط آن سایت (Server Block) پاسخ‌دهی می‌شود، در غیر اینصورت سایت (Server Block) پیشفرض، کار پاسخ‌دهی را انجام می‌دهد. برای مثال بلاک server در فایل تنظیمات بالا، به درخواست های وارد شده به پورت ۸۰ (پورت HTTP) گوش میکند و اگر نام سرور در درخواست ها example.com و یا www.example.com باشد، کار پاسخ‌دهی به آن را به عهده می‌گیرد.

دقت کنید که www.example.com یک Subdomain از example.com است و هر کدام از Subdomain ها در واقع سایت های مستقل از هم هستند بنابراین اگر می‌خواهید هر دوی آنها توسط یک Server Block پاسخ‌دهی شوند، باید نام هر دوی آنها را در مقابل دایرکتیو server_name اضافه کنید.

همانطور که گفتیم www.example.com و example.com در واقع دو سایت مجزا به حساب می‌آیند. بنابراین برای خراب نشدن SEO سایت و همینطور برای اینکه سرویس هایی مثل Google Analytics یا Google Crawler و ... با دو سایت مختلف مواجه نباشند بهتر است یکی از آنها (مثلا www.example.com) را به عنوان سایت اصلی خود در نظر گرفته و دیگری را به آن Redirect کنید.

وقتی چندین نام در مقابل دایرکتیو server_name قرار می‌گیرد، احتمال به وجود آمدن خطای زیر وجود دارد.

could not build the server_names_hash, you should increase server_names_hash_bucket_size: 32

برای جلوگیری از این خطای احتمالی باید میزان حافظه لازم برای ذخیره‌سازی رشته Hash شده ی نام ها را زیاد کنیم. برای این منظور دایرکتیو زیر را در بلاک http در فایل nginx.conf اضافه کنید.

server_names_hash_bucket_size 64;

اگر قرار است که Server Block محتوای Static سرو کند، باید محل قرار گیری آن محتوا را مقابل دایرکتیو root بیان کنیم. دایرکتیو index نیز به نقطه ورود به محتوا (فایلی که باید سرو شود) اشاره دارد. دایرکتیو location مربوط به تنظیمات Sub directory ها است. در مثال بالا، دو Sub directory (/ و /download/) تعریف شده اند که بررسی عملکرد آنها را به خود شما واگذار می‌کنیم.

اما اگر قرار است که Server Block محتوای Dynamic تولید شده توسط یک Web Application را سرو کند،‌ باید به عنوان یک Reverse Proxy برای آن Web Application تنظیم شود.

بلاک location برای پراکسی کردن درخواست ها به uWSGI (هندلر پایتون) چیزی شبیه به زیر است:

location / {
    include uwsgi_params;
    uwsgi_pass unix:/home/hamidreza/python-proj/myproject.sock;
}

برای اطلاعات بیشتر در رابطه با پراکسی کردن درخواست های Nginx به uWSGI برای تولید محتوای Dynamic توسط اپلیکیشن نوشته شده به زبان Python به این مقاله مراجعه کنید.

بلاک location برای پراکسی کردن درخواست ها به php-fpm (هندلر PHP) چیزی شبیه به زیر است:

location ~ \.php$ {
    fastcgi_split_path_info ^(.+\.php)(/.+)$;
    fastcgi_pass unix:/var/run/php7-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
} 

برای اطلاعات بیشتر در رابطه با پراکسی کردن درخواست های Nginx به php-fpm برای تولید محتوای Dynamic توسط اپلیکیشن نوشته شده به زبان PHP به این مقاله مراجعه کنید.


عیب‌یابی سیستم با بررسی Log درخواست ها

تمامی درخواست های وارد شده به Nginx در فایلی به نام access.log در مسیر var/log/nginx/ و تمامی خطاهای رخ داده شده هنگام پاسخ‌دهی به درخواست ها در فایل دیگری به نام error.log در همان مسیر ذخیره می‌شوند که می‌توان از آنها برای عیب‌یابی های احتمالی و ... استفاده کرد.

این فایل ها و مسیر ها توسط دایرکتیو های access_log و error_log در بلاک http از فایل nginx.conf تعریف شده اند و شما در صورت نیاز می‌توانید به ازای هر سایت مجزا، فایل های جداگانه ای را در Server Block مربوط به آنها تعریف کنید. مثلا ممکن است بخواهید Log های سایت admin.example.com را به جای فایل های تعریف شده در nginx.conf در فایل های admin.example.com.access.log و admin.example.com.error.log ذخیره کنید. برای این منظور می‌توانید دایرکتیو های زیر را به Server Block مربوطه اضافه کنید:

access_log /path/to/log main;
error_log /path/to/log error; 


فشرده‌سازی پاسخ های HTTP به کمک gzip

گاهی پاسخ هایی که Client ها از Web Server دریافت می‌کنند بسیار حجیم اند. مثلا تصاویر با رزولوشن بالا، فونت ها، فایل های JavaScript و CSS و ... که پهنای باند زیادی را اشغال کرده و پاسخ‌دهی را با کندی روبرو می‌کنند. این کندی می‌تواند تجربه کاربری بدی را برای سایت شما رقم بزند و همینطور SEO سایت را تحت تاثیر قرار دهد. در چنین شرایطی می‌توان پاسخ را در سرور، توسط ابزار هایی مثل gzip (مخفف GNU Zip که در تمامی توزیع های لینوکس به صورت پیشفرض وجود دارد) فشرده (Compress) کرد، اطلاعات فشرده شده و کم حجم تر را با سرعت بیشتر توسط کلاینت (مرورگر وب یا اپلیکیشن موبایل) دانلود کرد و سپس آن را از حالت فشرده خارج نمود. جدا از افزایش سرعت دانلود اطلاعات باید این نکته را در نظر داشت که عملیات فشرده سازی (Compression) روی سرور و بازیابی (Decompression) روی Client عملیات بسیار زمان بری اند که به ویژه برای Client هایی که توان پردازشی پایینی دارند ممکن است سرعت کلی پاسخ‌دهی را کمتر کنند. بنابراین بهتر است اولا پاسخ های پرتکرار پس از یک بار فشرده سازی، روی سرور Cache شوند تا دفعات بعد بدون نیاز به پردازش اضافی و به صورت کاملا Static سرو شوند. ثانیا اگر بیشتر کلاینت های مخاطب شما توان پردازشی پایینی دارند شاید فشرده سازی برای آنها ایده خوبی نباشد.

قابلیت فشرده‌سازی اطلاعات توسط gzip به صورت پیشفرض در Nginx پشتیبانی ‌می‌شود و ممکن است از قبل در فایل nginx.conf فعال شده باشد. اما به هر حال شما می‌توانید آن را برای یک Server Block مشخص، فعال و شخصی سازی کنید.

توجه کنید که اگر Client از این قابلیت (بازیابی پاسخ های فشرده شده به کمک gzip) پشتیبانی کند، هدر Accept-Encoding: gzip, deflate را همراه با درخواست خود به سرور ارسال می‌کند و سرور پاسخ فشرده شده را به او بر می‌گرداند. در غیر اینصورت نسخه اصلی و فشرده نشده از اطلاعات برای او ارسال می‌شود. با بررسی هدر Content-Encoding: gzip در پاسخ دریافت شده می‌توان متوجه شد که اطلاعات دریافتی توسط gzip فشرده شده اند.

برای فعال کردن gzip در یک سایت، موارد زیر را به Server Block مربوط به آن اضافه می‌کنیم.

server {
    listen 80;
    server_name example.com www.example.com;

    gzip on;
    gzip_comp_level    5;
    gzip_min_length    256;
    gzip_proxied       any;
    gzip_vary          on;

    gzip_types
    application/atom+xml
    application/javascript
    application/json
    application/ld+json
    application/manifest+json
    application/rss+xml
    application/vnd.geo+json
    application/vnd.ms-fontobject
    application/x-font-ttf
    application/x-web-app-manifest+json
    application/xhtml+xml
    application/xml
    font/opentype
    image/bmp
    image/svg+xml
    image/x-icon
    text/cache-manifest
    text/css
    text/plain
    text/vcard
    text/vnd.rim.location.xloc
    text/vtt
    text/x-component
    text/x-cross-domain-policy;
    # text/html is always compressed by gzip module
    
}

اولین دایرکتیو اضافه شده، ;gzip on است که قابلیت فشرده سازی توسط gzip را در Nginx فعال می‌کند. دومین دایرکتیو (;gzip_comp _level 5)، سطح فشرده سازی اطلاعات را مشخص می‌کند. سطح فشرده سازی اطلاعات، یک عدد بین ۱ تا ۹ است. هر چه این عدد بیشتر باشد پاسخ ها به میزان بیشتری فشرده شده و طبیعتاً زمان لازم برای فشرده سازی و بازیابی آنها نیز افزایش می‌یابد. سطح ۵، میزان فشرده سازی خوبی (نزدیک به ۷۵ درصد برای بیشتر فایل های ASCII) را با صرف میزان منابع قابل قبول ارایه می‌دهد. سطح فشرده سازی ۹ بسیار کندتر و با اشغال بخش زیادی از منابع سیستم انجام می‌شود ولی حجم پاسخ فشرده شده با آن، تفاوت چشمگیری با سطح ۵ ندارد. دایرکتیو سوم (;gzip_min_length 256) حداقل سایز پاسخ برای فشرده شدن را از مقدار پیشفرض ۲۰ بایت به ۲۵۶ بایت افزایش می‌دهد و پاسخ های کوچکتر از این مقدار را فشرده نمی‌کند. فایل های کوچکتر از ۲۵۶ بایت به راحتی و با سرعت دانلود می‌شوند و صرف انرژی برای فشرده تر کردن آنها معمولا نه تنها تاثیر چشمگیری ندارد بلکه در مواردی ممکن است حتی حجم پاسخ Compress شده از پاسخ اصلی بیشتر هم شود. دایرکتیو چهارم (;gzip_proxied any) باعث می‌شود که پاسخ درخواست هایی که مثلا توسط CDN ها (مثل ابر آروان) پراکسی شده اند نیز فشرده شوند. دایرکتیو پنجم (;gzip_vary on) به پراکسی ها (مثلا CDN آروان) می‌گوید که هر دو نسخه فشرده شده و فشرده نشده از پاسخ ها را کش کنند و با توجه به هدر Accept-Encoding در درخواست کاربران، نسخه مناسب را به آنها برگردانند. در غیر اینصورت ممکن است نسخه gzip شده برای کلاینتی که از آن پشتیبانی نمی‌کند ارسال شود. دایرکتیو آخر (;..... gzip_types) به Nginx می‌گوید که چه نوع فایل هایی را فشرده کند. همانطور که می‌بینید در جلوی این دایرکتیو، ۲۴ عدد از Media Type های معروف شامل تصاویر، فونت ها، فایل های JSON و ... درج شده اند که بسته به نیاز خود می‌توانید آنها را کم و زیاد کنید.

فشرده‌سازی پاسخ ها توسط gzip علاوه بر کاهش پهای باند مصرفی و افزایش سرعت، باعث کاهش سربار SSL نیز می‌شود. در واقع با این روش، تعداد رفت و برگشت‌های اطلاعات در طول فرآیند SSL Handshake کاهش پیدا می‌کند.


کش کردن پاسخ ها در سمت کلاینت

پاسخ بعضی از درخواست ها در طول زمان خیلی کم تغییر می‌کند. مثلا درخواست دانلود لوگوی شرکت، درخواست دانلود فونت متن های سایت، درخواست دانلود تصاویر ثابت صفحه اول، درخواست دانلود متن یک پست ثبت شده در وبلاگ و ... معمولا در طول ماه ها پاسخ ثابتی را بر می گردانند. چنین پاسخ هایی را می‌توان سمت Client (مثلا روی مرورگر وب کاربر) Cache کرد و علاوه بر افزایش سرعت بارگزاری، تعداد درخواست های اضافی به سرور را نیز کاهش داد. برای این کار باید یک Header خاص به پاسخ هایی که قرار است Cache شوند اضافه شده و مدت زمان معتبر بودن آن پاسخ در Cache کلاینت را مشخص کند.

این کار می‌تواند با افزودن یک بلاک location در داخل بلاک server (زیر تنظیمات gzip) به صورت زیر انجام شود.

location ~*  \.(jpg|jpeg|png|gif|ico|css|js|pdf)$ {
    expires 7d;
}

بلاک بالا، باعث Cache شدن همه فایل های jpg و jpeg و png و gif و ico و css و js و pdf به مدت یک هفته در کلاینت می‌شود. برای محتوایی که به ندرت دچار تغییرات می‌شوند (مثل پست های ثبت شده در وبلاگ) می‌توانید زمان بیشتری (مثلا یک ماه) را برای Cache شدن اطلاعات در نظر بگیرید.


فعال‌سازی HTTPS

تبادل اطلاعات با پروتکل HTTP در حالت کلی امنیت پایینی دارد و به راحتی در یک شبکه قابل شنود است. با این حال می‌توان این پروتکل را توسط پروتکل امنیتی TLS رمزنگاری کرد. در اینصورت به این پروتکل که امنیت بالاتری دارد، HTTP over TLS و یا HTTPS گفته می‌شود.

در گذشته به جای پروتکل TLS از پروتکل SSL استفاده می‌شد. در واقع TLS نسل جدید و جایگزین پروتکل SSL است. به همین دلیل ممکن است از هر کدام از نام های SSL و TLS و TLS/SSL برای اشاره به این پروتکل استفاده شود.

رمزنگاری اطلاعات رد و بدل شده بین Server و Client ها در HTTPS، توسط مکانیزم های رمزنگاری متقارن (استفاده از Private Key و Public Key) انجام می‌شود. در این حالت، کلید خصوصی، یک SSL Key است که باید در یک مکان امن و خصوصی در سرور قرار گیرد و کلید عمومی، یک SSL Certificate است که روی سرور قرار گرفته و برای همه Client ها ارسال می‌شود. Client ها از این Certificate برای دو منظور استفاده می‌کنند:

  1. رمز کردن اطلاعات به صورتی که فقط سرور دارنده SSL Key معادل، قادر به رمزگشایی آنها باشد.
  2. احراز هویت و مالکیت سایت مربوطه.

تولید SSL Key و SSL Certificate به راحتی و توسط ابزار OpenSSL توسط هر کسی امکان پذیر است. به چنین گواهینامه ای که توسط خود شما صادر (امضا) شده باشد، Self-signed SSL Certificate گفته می‌شود که می‌تواند اتصال بین Server شما با Client ها را امن کند اما Client ها با چنین گواهینامه ای قادر به احراز هویت سایت شما نیستند. در واقع Client ها (مثلا مرورگر های وب) فقط به گواهینامه هایی که توسط شرکت های قانونی (Certificate Authority) امضا شده باشند اعتماد کرده و هویت سایت را احراز می‌کنند. بنابراین برای اینکه کاربران هنگام بازکردن سایت شما در مرورگر، با اخطار زیر روبرو نشوند باید گواهینامه SSL شما توسط یک CA معتبر و قابل اعتماد مثل IdenTrust یا Comodo صادر (امضا) شده باشد. به چنین گواهینامه ای CA-Signed SSL Certificate یا Trusted Certificate گفته می‌شود.

اخطاری که در صورت استفاده از گواهینامه Self-signed دریافت خواهید کرد. کاربر برای باز کردن سایت شما مجبور به کلیک بر روی گزینه Proceed to ..... (unsafe) است.
اخطاری که در صورت استفاده از گواهینامه Self-signed دریافت خواهید کرد. کاربر برای باز کردن سایت شما مجبور به کلیک بر روی گزینه Proceed to ..... (unsafe) است.


گواهینامه های CA-Signed، خود در سه نوع DV و OV و EV صادر شده و به فروش می‌رسند که از نظر رمزنگاری تفاوتی با یکدیگر ندارند اما از نظر احراز هویت و مالکیت سایت، OV قوی تر از DV و EV قوی تر از OV است. DV مرسوم ترین نوع گواهینامه است که مالکیت دامنه (Domain) سایت شما را احراز می‌کند. دو نوع دیگر نیاز به ارسال و بررسی مدارک شرکت دارند و حتی مالکیت کسب و کار و حساب بانکی شما را نیز احراز می‌کنند.

گواهینامه های DV یا Domain Validated در واقع دامنه یک سایت را احراز هویت می‌کنند. بنابراین به ازای هر سایت باید یک گواهینامه مستقل گرفت. پیشتر گفتیم که Subdomain های یک سایت، خود، سایت های مستقلی به حساب می‌آیند پس به ازای هر Subdomain (مثلا mail.example.com یا blog.example.com) نیاز به یک گواهینامه مستقل داریم. از آنجا که معمولا هر کدام از این Subdomain ها به سرویس های متفاوتی روی سرور های مختلف اشاره می‌کنند، وجود گواهینامه های متفاوت، امنیت این سرور ها را افزایش می‌دهد. زیرا در صورت لو رفتن SSL Key مربوط به blog.example.com، امنیت سرویس mail.example.com به خطر نمی‌افتد.
با این حال گاهی مجبوریم که به ازای Subdomain های مختلف از یک گواهینامه واحد استفاده کنیم. مثلا فرض کنید هر کاربر در سایت شما یک صفحه مستقل با آدرس username.example.com دارد. در این صورت نمی‌توان به ازای هر کاربر جدید در سیستم، یک گواهینامه جدید خرید و از آن نگه داری کرد. در چنین حالتی از نوع خاصی از گواهینامه ها به نام Wildcard SSL Certificate استفاده می‌شود که به ازای همه Subdomain ها معتبر است.
توجه کنید که استفاده از یک Wildcard SSL Certificate برای همه سرور ها ممکن است امنیت سیستم های شما را به خطر بیندازد.

در گذشته ای نه چندان دور، صدور گواهینامه TLS/SSL توسط یک CA قابل اعتماد، بسیار گران قیمت و خارج از توان پرداختی بیشتر استارتاپ ها بود اما در سال های اخیر، یک CA معتبر به نام Lets Encrypt شروع به صدور و و امضای گواهینامه های CA-Signed رایگان از نوع DV کرده است. گواهینامه های صادر شده توسط Let's Encrypt تاریخ انقضای سه ماهه (۹۰ روزه) دارند که در هر زمان می‌توان آنها را تمدید (Renew) کرد.

برای فعال‌سازی HTTPS برای یک سایت باید تغییراتی را در Server Block مربوط به آن اعمال کرد. اولین تغییر مربوط به پورتی است که Server Block باید به درخواست های ارسال شده به آن گوش کند. همانطور که می‌دانید درخواست های HTTP به پورت ۸۰ سرور ارسال می‌شوند اما درخواست های HTTPS به پورت ۴۴۳. بنابراین اولین تغییر در Server Block به صورت زیر است:

server {
    listen 443 ssl;    # It was listen 80;
    listen [::]:443 ssl;    # It was listen [::]:80;
    ...
}
نکته: توجه کنید که پورت ۴۴۳ توسط Firewall شما مسدود نشده باشد. در صورت مسدود بودن توسط UFW می‌توانید با دستور sudo ufw allow 'Nginx Full' این پورت را باز کنید.

به عنوان تغییرات بعدی، باید آدرس فایل های SSL Certificate و SSL Key را توسط دایرکتیو های ssl_certificate و ssl_certificate_key به Server Block معرفی کرده و همینطور با تنظیمات مربوط به الگوریتم های رمزنگاری (Cipher Suite ها) امنیت HTTPS را بهتر کنیم. با این حال برای شلوغ نشدن فایل مربوط به Server Block و اینکه بتوان از تنظیمات SSL برای Server Block های دیگر هم استفاده کرد، این تنظیمات را در فایل های تنظیمات جداگانه در آدرس etc/nginx/snippets/ نوشته و در Server Block های مربوطه include می‌کنیم. دایرکتوری snippets در هنگام نصب Nginx برای جداسای فایل های تنظیمات و استفاده از آنها در بلاک های مختلف ایجاد می‌شود. بنابراین به آدرس etc/nginx/snippets/ رفته و دو فایل به نام های ssl-cert.conf و ssl-params.conf بسازید. در فایل ssl-cert.conf آدرس فایل های SSL Certificate و SSL Key را در مقابل دایرکتیو های ssl_certificate و ssl_certificate_key وارد کنید.

ssl_certificate /etc/ssl/certs/ssl-certificate.crt;
ssl_certificate_key /etc/ssl/private/ssl-key.key;

در فایل ssl-params.conf تنظیمات مربوط به Cipher Suite ها را از تنظیمات موجود در سایت https://cipherli.st کپی کنید. این تنظیمات که در واقع شامل امن ترین، قوی ترین و به‌روز ترین Cipher Suite های ممکن برای SSL اند، توسط یک هکر مشهور به نام Remy van Elst تهیه و نگه‌داری می‌شود و در صورت استفاده، امتیاز سایت شما را در SSL Labs به +A می‌رساند.

ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/dhparam.pem;
ssl_ciphers EECDH+AESGCM:EDH+AESGCM;
ssl_ecdh_curve secp384r1;
ssl_session_timeout  10m;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
resolver $DNS-IP-1 $DNS-IP-2 valid=300s;
resolver_timeout 5s; 
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block"

در خط سوم، آدرس یک فایل (dhparam.pem) مقابل دایرکتیو ssl_dhparam درج شده. این فایل در واقع یک گروه Diffie-Hellman قوی است که آشنایی با آن را به مخاطب واگذار می‌کنیم. به هر حال، برای تولید این فایل می‌توان از ابزار OpenSSL استفاده کرد:

$ sudo openssl dhparam -out /etc/nginx/dhparam.pem 4096

در خط چهارم از تنظیمات بالا تنها از دو Cipher Suite امن به نام های EECDH+AESGCM و EDH+AESGCM استفاده شده اما اگر Client های مخاطب شما قدیمی اند (مثلا Android های قبل از نسخه ۴.۴)، ممکن است از این الگوریتم ها پشتیبانی نکنند. در این صورت باید از تنظیمات و Cipher Suite های قدیمی تر که در سایت ذکر شده اند استفاده کنید.

در خط یازدهم از تنظیمات بالا، باید آدرس IP یک سرویس DNS دلخواه را برای Upstream کردن درخواست ها درج کنید که می‌توانید از سرویس Google استفاده کنید. برای این کار به جای $DNS-IP-1 از 8.8.8.8 و به جای DNS-IP-2$ از 8.8.4.4 استفاده کنید.

پیشنهاد می‌شود که خط سیزدهم که هدر Strict-Transport-Security را تنظیم می‌کند، فعلا کامنت کنید تا ابتدا مفهوم HSTS به ویژه حالت preload آن را کاملا درک کرده و بعداً آن را فعال کنید زیرا در صورت اشتباه ممکن است سایت شما برای مدت طولانی برای بعضی از کاربران غیر قابل دسترس شود.

حال باید این دو فایل تنظیمات جداگانه را در Server Block مربوطه include کنید:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    include snippets/ssl-cert.conf;
    include snippets/ssl-params.conf;
    . . .
}

با اعمال این تنظیمات، بار بعد که Nginx لود شود باید قادر به پاسخگویی به درخواست های HTTPS باشد. آن را تست کنید و اگر مشکلی وجود نداشت، می‌توانید تمام درخواست های HTTP (وارد شده روی پورت ۸۰) را به پورت ۴۴۳ منتقل (Redirect) کرده و به صورت امن به آنها پاسخ دهید. برای این کار باید یک Server Block دیگر برای درخواست های HTTP (پورت ۸۰) ایجاد کنیم زیرا Server Block قبلی را برای پاسخگویی به درخواست های HTTPS (پورت ۴۴۳) تغییر داده ایم. Server Block مربوط به HTTP به صورت زیر تعریف می‌شود:

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;

    return 301 https://$server_name$request_uri;
}

در این صورت درخواست هایی که به www.example.com می‌فرستیم، در ابتدا به صورت http://www.example.com ارسال شده و Server Block مربوط به HTTP، آدرس جدید (https://www.example.com) را همراه با کد 301 به عنوان پاسخ بر می‌گرداند. مرورگر پاسخ را گرفته و از روی کد ۳۰۱ متوجه میشود که ریدایرکت اتفاق افتاده، بنابراین محتوای هدر Location در پاسخ، شامل آدرس جدید را خوانده و یک درخواست دیگر به سمت https://www.example.com ارسال می‌کند.

توجه کنید که پاسخ با کد ۳۰۱ به عنوان Permanent Redirect توسط Client شناخته شده و دیگر هرگز از سمت Client درخواستی به آدرس قدیمی ارسال نمی‌شود و به جای آن از آدرس جدید استفاده خواهد شد. اگر در مورد این Redirect مطمین نیستید و یا به هر دلیل ممکن است بخواهید بعداً آن را تغییر دهید، بهتر است از کد ۳۰۲ استفاده کنید که Client آن را به عنوان Temporary Redirect شناسایی کرده و هر بار، توسط دو درخواست،‌ عملیات Redirect را انجام دهد.

واضح است که در این صورت برای دریافت محتوای سایت دو بار درخواست ارسال می‌شود (یک بار به صورت HTTP و بار دیگر به صورت HTTPS). برای جلوگیری از ارسال درخواست اضافه، با استفاده از قابلیت HSTS می‌توان Client را مجبور کرد که از ابتدا درخواست را به صورت HTTPS ارسال کند. فعال‌سازی قابلیت HSTS با افزودن یک هدر (Strict-Transport-Security) به پاسخ یکی از درخواست های HTTPS انجام می‌شود. Client به محض مشاهده این Header در پاسخ یک درخواست HTTPS، نام سایت را (به مدت مشخص شده در Header) در لیست HSTS خود ذخیره می‌کند و از این به بعد تمام درخواست ها به سایت را به صورت HTTPS ارسال می‌کند.

توجه کنید که اگر Client مخاطب شما به هر دلیل از TLS پشتیبانی نکند یا اعتبار گواهینامه TLS شما به هر دلیل از بین رفته باشد، احتمالا دسترسی به سایت شما ممکن نیست. حتی اگر بعدا قابلیت HSTS را غیر فعال کنید، باز هم تا مدت طولانی دسترسی کاربر به سایت با مشکل مواجه خواهد بود.

برای اضافه کردن این Header به تمام پاسخ ها در همه Subdomain ها بهتر است دایرکتیو زیر را به جای Server Block در بلاک http از فایل nginx.conf اضافه کنید.

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

این Header به مرورگر می‌فهماند که تا دو سال آینده (۶۳۰۷۲۰۰۰ ثانیه دیگر) همه درخواست ها به سایت و Subdomain های آن را در بستر HTTPS ارسال کند.

حتی با فعال بودن قابلیت HSTS، برای اولین درخواستی که از سمت Client به سایت ارسال می‌شود، احتمال حمله از نوع Downgrade Attack و دور زدن HSTS وجود دارد به همین دلیل مرورگر های وب، یک لیست از سایت ها با قابلیت HSTS را با عنوان HSTS Pre-load list درون پکیج خود دارند. البته که نگه‌داری از نام همه سایت های وب برای مرورگر ها امکان پذیر نیست اما فعلا می‌توانید برای این موضوع ثبت نام کنید.

در آخر لازم به ذکر است، صدور و استفاده از Certificate امضا شده توسط Let's Encrypt بسیار ساده تر است و دردسر های بالا را ندارد. زیرا این CA یک ابزار نرم‌افزاری به نام Certbot تولید کرده که تمامی این فرآیند ها و همینطور فرآیند تمدید گواهینامه را به صورت خودکار انجام می‌دهد. برای آشنایی با روش تولید و استفاده از این گواهینامه به این لینک مراجعه کنید.

پشتیبانی از درخواست های ارسال شده با پروتکل HTTP/2

درخواست هایی که از سمت Client ها (مرورگر وب کاربر، اپلیکیشن موبایل و ...) به Server ارسال می‌شوند، برپایه پروتکل HTTP اند. زمانی که اولین نسخه عمومی از این پروتکل (HTTP1.1) معرفی شد، بیشتر صفحات وب فقط شامل یک فایل HTML بودند که CSS ها نیز درون آن inline می‌شد. بنابراین در آن زمان با تعداد کمی Request، سایت بطور کامل توسط Client دریافت می‌شد. پروتکل HTTP1.1 این درخواست ها را در یک صف (Queue) قرار می‌داد و آنها را به ترتیب به Server ارسال می‌کرد. اما برای لود شدن سایت های امروزی، صد ها Request به سمت Server ارسال می‌شود و استفاده از صف برای ارسال ترتیبی درخواست ها، باعث کندی در بارگزاری صفحات می‌شود. کامپیوتر های امروزی برای انجام پردازش های موازی بهینه شده اند و نسخه جدید پروتکل HTTP یعنی HTTP/2 (یا به اختصار h2) نیز از این قابلیت بهره برده و درخواست ها را به صورت همزمان به سرور ارسال می‌کند. این همزمانی، به ویژه وقتی که تعداد درخواست های لازم برای بارگزاری کامل صفحه زیاد اند، باعث افزایش کلی در سرعت بارگزاری صفحه می‌شود.

همینطور HTTP/2 اطلاعات ارسال شده در Header درخواست ها را فشرده (Compress) می‌کند و اطلاعات را به جای متن به صورت Binary ارسال می‌کند که اینها خود در کاهش حجم داده های ارسالی و در نتیجه سرعت نهایی بارگزاری تاثیری به سزایی دارند.

نکته: به دلایل امنیتی، بیشتر مرورگر ها امکان ارسال درخواست های HTTP/2 به سرور هایی که ارتباط امن (HTTPS) برقرار نمی‌کنند را نمی‌دهند. بنابراین برای اینکه سایت شما از HTTP/2 پشیبانی کند باید حتما از گواهینامه SSL استفاده کنید و تمام ترافیک پورت ۸۰ را به پورت ۴۴۳ ریدایرکت (Redirect) کنید.
همینطور باید از یک کلید DHE یا Ephemeral Diffie-Hellman با اندازه ۲۰۴۸ بیت (یا بالاتر) در تنظیمات Nginx استفاده کنید که پیشتر، روش تولید و استفاده از آن توضیح داده شد.

بنابراین تا اینجای کار، دو Server Block، یکی برای پاسخ‌گویی به درخواست های HTTP و دیگری برای پاسخ‌گویی به درخواست های HTTPS داریم. بلاک مربوط به HTTP درخواست ها را به صورت HTTP1.1 دریافت می‌کند (پیشتر گفته شد که اکثر مرورگر های وب، به دلایل امنیتی، درخواست های HTTP/2 را فقط به سرور های HTTPS ارسال می‌کنند). سپس این بلاک، یک پاسخ با کد ۳۰۱ شامل یک آدرس HTTPS برای کاربر فرستاده و مرورگر وب کاربر، درخواست جدیدی را به Server Block مربوط به HTTPS ارسال می‌کند. برای اینکه این درخواست (در صورت پشتیبانی Client) به صورت HTTP/2 ارسال شود، باید Server Block مربوط به HTTPS به صورت زیر تغییر کند:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
}

همینطور باید توجه کرد که بعضی از Cipher Suite ها برای رمزنگاری پروتکل HTTP/2 به اندازه کافی امن نیستند و در صورت وجود باید حذف شوند.

در صورتی که تنظیمات SSL شما توسط نرم‌افزار Certbot انجام شده، فایل تنظیماتی با آدرس etc/letsencrypt/options-ssl-nginx.conf/ در Server Block مربوطه include شده که شامل Cipher Suite های ممکن است. ویرایش این فایل، فرآیند به روز رسانی Certbot را دچار مشکل می‌کند. بنابراین به جای ویرایش این فایل، آن را Comment کرده و به جای آن Cipher Suite های امن تر را توسط دایرکتیو ssl_ciphers معرفی کنید.

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
   # include /etc/letsencrypt/options-ssl-nginx.conf; 
    ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
}

با اعمال تغییرات بالا و راه‌اندازی مجدد Nginx، درخواست کاربران در صورت امکان به صورت HTTP/2 ارسال خواهد شد. برای بررسی این موضوع می‌توانید با استفاده از ابزار curl درخواستی را به سرور ارسال کرده و ورژن پروتکل و همینطور Header های پاسخ (مثلا Strict-Transport-Security و ...) را بررسی کنید.

در تصویر بالا، اولین درخواست با پروتکل HTTP1.1 به سرور HTTP (یعنی http://snapp.ir) ارسال شده و با پاسخ ۳۰۱ (Permanent Redirect) مواجه شده است. سپس مرورگر آدرس جدید را از هدر Location در پاسخ دریافت شده خوانده و درخواست جدیدی را با پروتکل HTTP/2 به سرور HTTPS (یعنی https://snapp.ir) ارسال کرده است. همانطور که مشاهده می‌کنید، این بار سرور پاسخ صحیح (با کد ۲۰۰) را به همراه هدر Strict-Transport-Security برای ۶ ماه، به کاربر ارسال کرده است.

برای آشنایی با HTTP/3 میتوانید از این لینک و یا این لینک استفاده کنید.

استفاده از Nginx به عنوان Cache Server

برای استفاده از Nginx به عنوان Cache Server می‌توانید از لینک زیر کمک بگیرید.

https://www.nginx.com/blog/nginx-caching-guide/

روش جایگزین برای HTTP Cache استفاده از پکیج Varnish است.