توی این درس یاد میگیری Nginx (تلفظ: «اِنجیناِکس») دقیقاً چیست و چرا تقریباً جلوی هر سایت جدی یک Nginx (یا چیزی شبیه آن) نشسته است. سه نقش اصلیاش را با مثال واقعی میبینی: وبسرور (web server) که فایلها را مستقیم میفرستد، reverse proxy که درخواستها را به اپلیکیشن پشتش میرساند، و load balancer که بار را بین چند سرور پخش میکند. با nginx -v نسخهاش را میبینی، با curl -I میفهمی یک سایت با چه وبسروری جواب میدهد، و میفهمی معماری رویدادمحور (event-driven) Nginx چه فرقی با Apache دارد.
مسئله: اپلیکیشن تو تنها جلوی اینترنت
Section titled “مسئله: اپلیکیشن تو تنها جلوی اینترنت”فرض کن یک اپ Node.js یا Python نوشتهای که روی پورت 3000 گوش میدهد. میتوانی همین را مستقیم روی اینترنت بگذاری؟ از نظر فنی بله، ولی خیلی زود به اینها میخوری:
- HTTPS: گواهی، رمزنگاری و تمدیدش را باید خود اپ مدیریت کند.
- فایلهای استاتیک: هزاران عکس، CSS و JS؛ اپ تو برای فرستادن هر کدام وقت پردازنده میگذارد.
- چند دامنه روی یک سرور:
shop.example.comوblog.example.comهر دو روی پورت ۸۰ و ۴۴۳ میآیند؛ کدام اپ جواب بدهد؟ - بار زیاد: وقتی یک نسخه از اپ کافی نیست و سه نسخه داری، چه کسی درخواستها را تقسیم کند؟
- محافظت: محدودکردن درخواستهای زیاد، هدرهای امنیتی، پنهانکردن جزئیات اپ.
اینها کار اپ تو نیست. کار یک برنامهی تخصصی است که جلوی اپ بنشیند: Nginx.
تشبیه: پذیرش یک ساختمان اداری
Section titled “تشبیه: پذیرش یک ساختمان اداری”Nginx مثل میز پذیرش یک ساختمان اداری است. همه از یک در ورودی (پورت ۸۰ و ۴۴۳) وارد میشوند و اول به پذیرش میرسند:
- اگر فقط یک بروشور میخواهند (فایل استاتیک)، پذیرش خودش از قفسه برمیدارد و میدهد؛ لازم نیست مزاحم کارمندها شود (وبسرور).
- اگر کار واقعی دارند، پذیرش آنها را به اتاق درست میفرستد و جواب را برمیگرداند؛ مراجع اصلاً نمیداند اتاق کجاست (reverse proxy).
- اگر سه کارمند همان کار را انجام میدهند، پذیرش مراجعان را بینشان تقسیم میکند تا یکی زیر بار نرود (load balancer).
- و پذیرش است که کارت شناسایی را چک میکند و آدمهای مشکوک را راه نمیدهد (HTTPS، محدودیت درخواست، هدرهای امنیتی).
سه نقش Nginx
Section titled “سه نقش Nginx”| نقش | Nginx چه میکند | نمونه |
|---|---|---|
| وبسرور | فایلها را مستقیم از دیسک میفرستد | سایت استاتیک، خروجی build یک اپ React یا Astro، عکسها |
| reverse proxy | درخواست را به یک سرور دیگر (اپ) میفرستد و جواب را به کاربر برمیگرداند | جلوی اپ Node، Python، PHP یا یک کانتینر |
| load balancer | درخواستها را بین چند نسخه از یک اپ پخش میکند | سه نسخه از API پشت یک آدرس |
در عمل یک Nginx معمولاً هر سه کار را همزمان انجام میدهد، بهعلاوهی پایان دادن HTTPS (TLS termination)، فشردهسازی (gzip)، کش و محدودسازی درخواستها؛ همهی اینها را در درسهای این دوره میسازی.
مثالهای عملی
Section titled “مثالهای عملی”این درس روی ماشین آزمایشی server (Ubuntu 24.04 با systemd) اجرا شده که Nginx از مخزن خود Ubuntu رویش نصب است؛ نصب را در درس بعد قدمبهقدم میبینی. دستورها با کاربر root اجرا شدهاند؛ روی سرور خودت جلویشان sudo بگذار.
مثال ۱: nginx -v، کدام نسخه؟
Section titled “مثال ۱: nginx -v، کدام نسخه؟”اولین دستور هر Nginx: نسخهاش چیست؟
nginx -vecho "--- کد خروج: $?"echo "--- nginx -V: نسخه بهعلاوهی گزینههای build (چند خط اول):"nginx -V 2>&1 | head -n 3nginx -V 2>&1 | grep -o -- '--with-http_[a-z0-9_]*' | head -n 6nginx version: nginx/1.24.0 (Ubuntu)--- کد خروج: 0--- nginx -V: نسخه بهعلاوهی گزینههای build (چند خط اول):nginx version: nginx/1.24.0 (Ubuntu)built with OpenSSL 3.0.13 30 Jan 2024TLS SNI support enabled--with-http_ssl_module--with-http_stub_status_module--with-http_realip_module--with-http_auth_request_module--with-http_v2_module--with-http_dav_modulenginx -v(v کوچک) فقط نسخه را میگوید:1.24.0، ساختهشده برای Ubuntu.nginx -V(V بزرگ) بهعلاوهی نسخهی OpenSSL و همهی گزینههایی که Nginx با آنها ساخته (compile) شده را نشان میدهد. وقتی میخواهی ببینی یک ماژول (مثلاًhttp_ssl_moduleبرای HTTPS یاhttp_v2_moduleبرای HTTP/2) در Nginx تو هست یا نه، اینجا را نگاه میکنی.- این دستورها خروجی را روی stderr چاپ میکنند (برای همین با
2>&1بهgrepدادیم).
مثال ۲: Nginx بهعنوان وبسرور
Section titled “مثال ۲: Nginx بهعنوان وبسرور”Nginx الان در حال اجراست و پوشهی /var/www/html را سرو میکند. با curl یک درخواست میفرستیم؛ -i هدرهای پاسخ را هم نشان میدهد:
systemctl is-active nginxcurl -s -i http://localhost/ | head -n 12activeHTTP/1.1 200 OKServer: nginx/1.24.0 (Ubuntu)Date: Sun, 04 Oct 2026 12:41:56 GMTContent-Type: text/htmlContent-Length: 615Last-Modified: Sun, 04 Oct 2026 12:38:27 GMTConnection: keep-aliveETag: "6ac248c3-267"Accept-Ranges: bytes
<!DOCTYPE html><html>خط اول وضعیت (status) است: HTTP/1.1 200 OK. بعد هدرها: Server: nginx/1.24.0 (Ubuntu) میگوید چه کسی جواب داد؛ Content-Type نوع فایل؛ Content-Length اندازه؛ Last-Modified و ETag برای کش مرورگر. بعد از یک خط خالی، بدنه (body) شروع میشود: همان صفحهی «Welcome to nginx!».
حالا فایل خودمان را میگذاریم. وبسرور یعنی همین: یک فایل در پوشه، یک آدرس در مرورگر.
echo '<h1>Hello from LoopX</h1>' > /var/www/html/hello.htmlcurl -s http://localhost/hello.htmlecho "--- فایلی که نیست:"curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost/nothing.htmlrm /var/www/html/hello.html<h1>Hello from LoopX</h1>--- فایلی که نیست:HTTP 404آدرس /hello.html به فایل /var/www/html/hello.html نگاشت (map) شد. برای فایل ناموجود، Nginx کد 404 داد. (-w "%{http_code}" به curl میگوید فقط کد وضعیت را چاپ کند.)
مثال ۳: curl -I، هر سایت با چه وبسروری جواب میدهد؟
Section titled “مثال ۳: curl -I، هر سایت با چه وبسروری جواب میدهد؟”curl -I (I بزرگ) فقط هدرها را میگیرد (یک درخواست HEAD). هدر Server معمولاً نام وبسرور را لو میدهد. برای مقایسه، یک وبسرور سادهی دیگر هم بالا میآوریم: سرور داخلی پایتون:
mkdir -p /srv/lx-py && echo "python here" > /srv/lx-py/index.html(cd /srv/lx-py && exec python3 -m http.server 9001 --bind 127.0.0.1) > /dev/null 2>&1 &sleep 1echo "=== Nginx:"curl -s -I http://localhost/ | grep -iE '^(HTTP|server)'echo "=== Python http.server:"curl -s -I http://127.0.0.1:9001/ | grep -iE '^(HTTP|server)'=== Nginx:HTTP/1.1 200 OKServer: nginx/1.24.0 (Ubuntu)=== Python http.server:HTTP/1.0 200 OKServer: SimpleHTTP/0.6 Python/3.12.3روی سایتهای واقعی هم همین را امتحان کن (این بخش تمرین اول درس است):
curl -sI https://www.wikipedia.org | grep -i '^server'curl -sI https://github.com | grep -i '^server'curl -sI https://www.digikala.com | grep -i '^server'مثال ۴: Nginx بهعنوان reverse proxy
Section titled “مثال ۴: Nginx بهعنوان reverse proxy”حالا همان سرور پایتون (روی 127.0.0.1:9001، که از بیرون دیده نمیشود) را پشت Nginx میگذاریم. یک فایل تنظیمات کوچک میسازیم که هر درخواست به پورت 8081 را به پایتون بفرستد (جزئیات نحو را در درسهای بعد کامل یاد میگیری):
server { listen 8081; location / { proxy_pass http://127.0.0.1:9001; }}nginx -tsystemctl reload nginxsleep 1curl -s -i http://localhost:8081/ | grep -iE '^(HTTP|server)|python'nginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successfulHTTP/1.1 200 OKServer: nginx/1.24.0 (Ubuntu)python herenginx -tتنظیمات را قبل از اعمال بررسی میکند (درس ساختار تنظیمات) وsystemctl reload nginxآن را بدون قطع سرویس اعمال میکند.- جواب (
python here) از پایتون آمد، ولی هدرServerحالاnginxاست: کاربر فقط Nginx را میبیند. Nginx هدرServerاپ پشتش را بهصورت پیشفرض پنهان میکند و هدر خودش را میگذارد. - پایتون فقط روی
127.0.0.1گوش میدهد؛ یعنی از بیرون سرور قابل دسترس نیست و فقط Nginx به آن میرسد. این الگوی استاندارد است.
مثال ۵: Nginx بهعنوان load balancer
Section titled “مثال ۵: Nginx بهعنوان load balancer”دو نسخهی «اپ» (دو سرور پایتون با محتوای متفاوت تا ببینیم کدام جواب داد) و یک Nginx که بینشان پخش کند:
upstream lx_app { zone lx_app 64k; server 127.0.0.1:9011; server 127.0.0.1:9012;}
server { listen 8082; location / { proxy_pass http://lx_app; }}for port in 9011 9012; do mkdir -p /srv/lx-app-$port echo "response from app on port $port" > /srv/lx-app-$port/index.html (cd /srv/lx-app-$port && exec python3 -m http.server $port --bind 127.0.0.1) > /dev/null 2>&1 &donesleep 1nginx -t 2>&1 | tail -n 1systemctl reload nginxsleep 1for i in 1 2 3 4; do curl -s http://localhost:8082/donenginx: configuration file /etc/nginx/nginx.conf test is successfulresponse from app on port 9011response from app on port 9012response from app on port 9011response from app on port 9012بلوک upstream یک گروه از سرورها با یک اسم (lx_app) تعریف میکند و proxy_pass به آن گروه میفرستد. Nginx بهصورت پیشفرض به نوبت (round robin) پخش میکند: ۹۰۱۱، ۹۰۱۲، ۹۰۱۱، ۹۰۱۲. خط zone یک حافظهی مشترک میسازد تا همهی worker ها یک نوبت مشترک داشته باشند؛ بدون آن هر worker نوبت خودش را نگه میدارد و ترتیب کمی به هم میریزد (در درس load balancing هر دو حالت را میبینی). اگر یکی از نسخهها از کار بیفتد، Nginx درخواست را به بقیه میدهد:
pkill -f 'http.server 9012'sleep 1for i in 1 2 3; do curl -s -o /dev/null -w "HTTP %{http_code} " http://localhost:8082/ curl -s http://localhost:8082/doneHTTP 200 response from app on port 9011HTTP 200 response from app on port 9011HTTP 200 response from app on port 9011با اینکه یکی از دو نسخه خاموش است، همهی درخواستها با 200 جواب گرفتند (از نسخهی سالم). جزئیات (least_conn، max_fails و …) در درس load balancing.
مثال ۶: سریع، با حافظهی کم
Section titled “مثال ۶: سریع، با حافظهی کم”یکی از دلیلهای محبوبیت Nginx این است که با منابع کم تعداد زیادی اتصال همزمان را جواب میدهد. با ابزار ab (ApacheBench) دو هزار درخواست با ۵۰ اتصال همزمان میفرستیم؛ یک بار به Nginx و یک بار به سرور سادهی پایتون، هر دو برای یک فایل کوچک:
cp /srv/lx-py/index.html /var/www/html/py.htmlecho "=== Nginx:"ab -q -n 2000 -c 50 http://127.0.0.1/py.html 2>&1 | grep -E 'Requests per second|Failed requests|Time per request.*mean\)$'echo "=== Python http.server:"ab -q -n 2000 -c 50 http://127.0.0.1:9001/index.html 2>&1 | grep -E 'Requests per second|Failed requests|Time per request.*mean\)$'rm /var/www/html/py.html=== Nginx:Failed requests: 0Requests per second: 19389.24 [#/sec] (mean)Time per request: 2.579 [ms] (mean)=== Python http.server:Failed requests: 0Requests per second: 71.97 [#/sec] (mean)Time per request: 694.763 [ms] (mean)اعداد دقیق به سختافزار بستگی دارند و روی سیستم تو فرق میکنند، ولی فاصلهی چند برابری (اینجا بیش از صد برابر) همیشه هست: سرور پایتون برای آزمایش ساخته شده، Nginx برای همین کار. (این مقایسه منصفانه نیست و قرار هم نیست باشد؛ نکته این است که فایل استاتیک را به Nginx بسپار، نه به اپ.)
پشت پرده: master، worker و حلقهی رویداد
Section titled “پشت پرده: master، worker و حلقهی رویداد”Nginx یک برنامهی تکپروسه نیست. یک پروسهی master دارد که تنظیمات را میخواند، پورتها را باز میکند و چند پروسهی worker میسازد که کار واقعی (جواب دادن به درخواستها) را انجام میدهند:
ps -o pid,ppid,user,cmd -C nginxecho "--- تعداد worker ها در تنظیمات:"grep -E '^\s*worker_(processes|connections)' /etc/nginx/nginx.confecho "--- تعداد هستههای CPU: $(nproc)" PID PPID USER CMD 14851 1 root nginx: master process /usr/sbin/nginx -g daemon on; master_process on; 14904 14851 www-data nginx: worker process 14905 14851 www-data nginx: worker process 14906 14851 www-data nginx: worker process 14909 14851 www-data nginx: worker process--- تعداد worker ها در تنظیمات:worker_processes auto; worker_connections 768;--- تعداد هستههای CPU: 4- master با کاربر
rootاجرا میشود (چون باز کردن پورت ۸۰ زیر ۱۰۲۴ دسترسی root میخواهد) ولی خودش به درخواستها جواب نمیدهد. - worker ها با کاربر کمدسترسی
www-dataاجرا میشوند؛ اگر کسی از راه یک باگ worker را در اختیار بگیرد، دسترسی root ندارد. worker_processesتعداد worker هاست (auto، پیشفرض Ubuntu، یعنی یکی به ازای هر هستهی CPU؛ اینجا ۴ هسته و ۴ worker) وworker_connectionsحداکثر اتصال همزمان هر worker.
راز سرعت در مدل رویدادمحور است. Apache در حالت کلاسیکش برای هر اتصال یک پروسه یا thread جدا اختصاص میدهد؛ اگر ده هزار کاربر با اینترنت کند وصل باشند، ده هزار پروسه یا thread منتظر میمانند و هر کدام حافظه میخورند. هر worker Nginx یک حلقهی رویداد (event loop) است: از سیستمعامل (با epoll در لینوکس) میپرسد «کدام اتصالها الان دادهی آماده دارند؟» و فقط به همانها رسیدگی میکند؛ بقیه هیچ منبعی جز چند کیلوبایت حافظه نمیگیرند.
وقتی تنظیمات را با reload عوض میکنی، master تنظیمات تازه را میخواند، worker های جدید میسازد و به worker های قدیمی میگوید درخواستهای در حال اجرا را تمام کنند و بروند. برای همین reload سرویس را قطع نمیکند:
echo "قبل از reload: $(pgrep -d ' ' -f 'nginx: worker')"systemctl reload nginxsleep 1echo "بعد از reload: $(pgrep -d ' ' -f 'nginx: worker')"echo "master عوض شد؟ $(pgrep -f 'nginx: master')"قبل از reload: 14904 14905 14906 14909بعد از reload: 16951 16952 16953 16954master عوض شد؟ 14851شمارهی پروسهی worker ها عوض شد (worker های تازه) ولی master همان ماند.
جدولهای مرجع
Section titled “جدولهای مرجع”Nginx در برابر Apache:
| Nginx | Apache httpd | |
|---|---|---|
| مدل اتصال | رویدادمحور (چند worker، هر کدام هزاران اتصال) | ماژولهای MPM: prefork (پروسه به ازای اتصال)، worker، event |
| فایل استاتیک و اتصالهای زیاد | بسیار سریع با حافظهی کم | خوب، با حافظهی بیشتر |
| تنظیمات | فقط فایلهای اصلی؛ بعد از تغییر reload |
بهعلاوهی .htaccess در هر پوشه (بدون reload، ولی کندتر) |
| اجرای PHP | به PHP-FPM میفرستد (proxy) | میتواند با mod_php داخل خودش اجرا کند |
| کاربرد رایج امروز | reverse proxy، load balancer، سایت استاتیک | میزبانی اشتراکی و برنامههایی که .htaccess میخواهند |
دستورهای این درس:
| دستور | کار |
|---|---|
nginx -v |
نسخه |
nginx -V |
نسخه + گزینهها و ماژولهای build |
nginx -t |
آزمایش تنظیمات (درس سوم) |
systemctl reload nginx |
اعمال تنظیمات بدون قطع سرویس |
curl -i URL |
پاسخ با هدرها |
curl -I URL |
فقط هدرها (درخواست HEAD) |
curl -s -o /dev/null -w "%{http_code}" URL |
فقط کد وضعیت |
ps -o pid,user,cmd -C nginx |
پروسههای master و worker |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) فکر کردن که Nginx «زبان برنامهنویسی» یا «فریمورک» است
Section titled “۱) فکر کردن که Nginx «زبان برنامهنویسی» یا «فریمورک» است”Nginx کد اپ تو (Python، PHP، Node) را اجرا نمیکند؛ فایل میفرستد یا درخواست را به برنامهی دیگری میرساند. برای PHP هم Nginx درخواست را به PHP-FPM میدهد. راهحل: اپ را جدا اجرا کن (سرویس systemd یا کانتینر) و Nginx را جلویش بگذار.
۲) دو برنامه روی یک پورت
Section titled “۲) دو برنامه روی یک پورت”python3 -m http.server 80 --bind 0.0.0.0 2>&1 | tail -n 1OSError: [Errno 98] Address already in useNginx پورت ۸۰ را گرفته و برنامهی دیگری نمیتواند همان را بگیرد (Address already in use). برعکسش هم رایج است: Apache نصب است و Nginx بالا نمیآید. راهحل: با ss -tlnp (درس پورتها در دورهی لینوکس) ببین چه کسی پورت را گرفته؛ اپها را روی پورتهای داخلی (مثل 127.0.0.1:3000) بگذار و فقط Nginx روی ۸۰ و ۴۴۳ باشد.
۳) اعتماد کامل به هدر Server
Section titled “۳) اعتماد کامل به هدر Server”هدر Server را هر کسی میتواند عوض یا پنهان کند (درس هدرهای امنیتی: server_tokens off). راهحل: آن را یک سرنخ بدان، نه مدرک.
۴) nginx -V بدون 2>&1 در pipe
Section titled “۴) nginx -V بدون 2>&1 در pipe”echo "فقط stdout:"nginx -V 2>/dev/null | grep -c sslecho "--- با 2>&1:"nginx -V 2>&1 | grep -c sslفقط stdout:0--- با 2>&1:1وقتی فقط stdout به grep برسد (اینجا stderr را دور ریختیم؛ بدون 2>/dev/null همان متن روی صفحه میآید ولی باز به grep نمیرسد)، شمارش ۰ است، چون nginx -V روی stderr مینویسد و pipe فقط stdout را میبرد. راهحل: 2>&1.
تمرین اصلی درس: با curl -sI بررسی کن سه سایت معروف (مثلاً ویکیپدیا، GitHub و یک سایت ایرانی که زیاد استفاده میکنی) با چه وبسروری جواب میدهند. اگر هدر Server نبود یا اسم CDN بود، دنبال هدرهای دیگری بگرد که سرنخ میدهند (مثل x-powered-by، via یا x-cache).
دیدن جواب
for site in https://www.wikipedia.org https://github.com https://www.digikala.com; do echo "== $site" curl -sI "$site" | grep -iE '^(server|via|x-powered-by|x-cache):'doneخروجی به زمان و جای تو بستگی دارد (و در محیط آزمایشی ما بدون اینترنت مستقیم اجرا نشد). چیزهایی که معمولاً میبینی: بعضی سایتها nginx یا nginx/1.x، بعضی اسم CDN یا وبسرور سفارشیشان (مثل cloudflare، ATS، envoy)، و بعضی اصلاً هدر Server نمیفرستند. هدر via یعنی پاسخ از یک proxy گذشته است. روی سرور خودمان همین کار را واقعاً اجرا کردیم:
for url in http://localhost/ http://localhost:8081/ http://127.0.0.1:9001/; do printf '%-26s ' "$url" curl -sI "$url" | grep -i '^server' | tr -d '\r'donehttp://localhost/ Server: nginx/1.24.0 (Ubuntu)http://localhost:8081/ Server: nginx/1.24.0 (Ubuntu)http://127.0.0.1:9001/ Server: SimpleHTTP/0.6 Python/3.12.3فایل /var/www/html/about.html بساز و با curl -i سه چیز را از هدرهای پاسخ پیدا کن: نوع محتوا، اندازهی بدنه به بایت، و تاریخ آخرین تغییر. بعد فایل را عوض کن و ببین کدام هدرها عوض شدند. در پایان فایل را پاک کن و کد وضعیت را دوباره بگیر.
دیدن جواب
printf '<h1>About LoopX</h1>\n' > /var/www/html/about.htmltouch -d '2026-01-01 10:00:00' /var/www/html/about.htmlcurl -s -i http://localhost/about.html | grep -iE '^(content-type|content-length|last-modified|etag)'echo "--- بعد از تغییر:"printf '<h1>About LoopX</h1>\n<p>Practical lessons in Persian.</p>\n' > /var/www/html/about.htmlcurl -s -i http://localhost/about.html | grep -iE '^(content-length|last-modified|etag)'rm /var/www/html/about.htmlecho "--- بعد از حذف:"curl -s -o /dev/null -w "HTTP %{http_code}\n" http://localhost/about.htmlContent-Type: text/htmlContent-Length: 21Last-Modified: Thu, 01 Jan 2026 10:00:00 GMTETag: "695645a0-15"--- بعد از تغییر:Content-Length: 58Last-Modified: Sun, 04 Oct 2026 12:42:31 GMTETag: "6ac249b7-3a"--- بعد از حذف:HTTP 404Content-Type: text/html از پسوند .html آمده (Nginx از جدول mime.types میخواند). Content-Length دقیقاً اندازهی فایل است و Last-Modified زمان تغییر فایل روی دیسک. ETag از زمان تغییر و اندازه ساخته میشود؛ پس با تغییر فایل هر سه عوض شدند. مرورگر با همینها میفهمد نسخهی کششدهاش هنوز معتبر است یا نه (درس عملکرد).
یک reverse proxy روی پورت 8083 بساز که درخواستها را به سه نسخهی پایتون (پورتهای ۹۰۲۱ تا ۹۰۲۳) پخش کند. با یک حلقه ۶ درخواست بفرست و بشمار هر نسخه چند بار جواب داد. بعد یک نسخه را خاموش کن و دوباره ۶ درخواست بفرست. در پایان همه را پاک کن.
دیدن جواب
for port in 9021 9022 9023; do mkdir -p /srv/lx-app-$port echo "app-$port" > /srv/lx-app-$port/index.html (cd /srv/lx-app-$port && exec python3 -m http.server $port --bind 127.0.0.1) > /dev/null 2>&1 &donecat > /etc/nginx/conf.d/lx-three.conf <<'EOF'upstream lx_three { zone lx_three 64k; server 127.0.0.1:9021; server 127.0.0.1:9022; server 127.0.0.1:9023;}server { listen 8083; location / { proxy_pass http://lx_three; }}EOFsleep 1nginx -t 2>&1 | tail -n 1 && systemctl reload nginxsleep 1echo "=== سه نسخه:"for i in $(seq 6); do curl -s http://localhost:8083/; done | sort | uniq -cpkill -f 'http.server 9022'sleep 1echo "=== بعد از خاموشی 9022:"for i in $(seq 6); do curl -s http://localhost:8083/; done | sort | uniq -crm -f /etc/nginx/conf.d/lx-three.confsystemctl reload nginxsleep 1pkill -f 'http.server 902'nginx: configuration file /etc/nginx/nginx.conf test is successful=== سه نسخه: 2 app-9021 2 app-9022 2 app-9023=== بعد از خاموشی 9022: 3 app-9021 3 app-9023با سه نسخه و zone مشترک، هر کدام دقیقاً ۲ بار (round robin). بعد از خاموشی یکی، دو نسخهی باقیمانده هر کدام ۳ بار جواب دادند و هیچ درخواستی شکست نخورد. sort | uniq -c (درس pipe ها) شمارش را انجام داد.
آزمونک
Section titled “آزمونک”اپ Node تو روی 127.0.0.1:3000 اجرا میشود و Nginx روی پورت ۸۰ درخواستها را به آن میفرستد. Nginx در این حالت چه نقشی دارد؟
reverse proxy درخواست را به سرور دیگری میرساند و جواب را برمیگرداند؛ کاربر فقط Nginx را میبیند.
تفاوت nginx -v و nginx -V چیست؟
برای بررسی تنظیمات nginx -t.
چرا پروسهی master Nginx با root و worker ها با www-data اجرا میشوند؟
اصل کمترین دسترسی.
راز اینکه Nginx با چند worker هزاران اتصال همزمان را با حافظهی کم جواب میدهد چیست؟
اتصال بیکار فقط چند کیلوبایت حافظه میگیرد.
در یک upstream با دو سرور، یکی خاموش میشود. با تنظیمات پیشفرض چه میشود؟
وقتی اتصال به یکی شکست بخورد، Nginx سراغ سرور بعدی میرود.
nginx -V | grep ssl هیچ چیزی پیدا نمیکند ولی خروجی روی صفحه هست. چرا؟
pipe فقط stdout را میبرد.
چرا systemctl reload nginx سرویس را قطع نمیکند؟
restart برعکس، کل سرویس را میبندد و دوباره بالا میآورد.
جمعبندی
Section titled “جمعبندی”- Nginx برنامهای است که جلوی سایتها و اپها مینشیند: وبسرور (فایل از دیسک)، reverse proxy (رساندن درخواست به اپ و برگرداندن جواب)، load balancer (پخش بین چند نسخه)؛ بهعلاوهی HTTPS، فشردهسازی، کش و محدودسازی.
- اپها روی پورتهای داخلی (
127.0.0.1:3000) گوش میدهند و فقط Nginx روی ۸۰ و ۴۴۳ است. nginx -vنسخه،nginx -Vماژولها (هر دو روی stderr).curl -iپاسخ با هدر وcurl -Iفقط هدر؛ هدرServerسرنخ است، نه مدرک.- معماری: یک master (root، تنظیمات و پورتها) و چند worker (
www-data، کار واقعی)؛ هر worker یک حلقهی رویداد باepollاست.reloadworker ها را بدون قطع سرویس عوض میکند. - در برابر Apache: Nginx برای اتصالهای زیاد، فایل استاتیک و proxy سبکتر است؛ Apache با
.htaccessوmod_phpدر میزبانی اشتراکی هنوز رایج است.
| دستور | کاری که میکند |
|---|---|
nginx -v | نسخهی Nginx |
nginx -V 2>&1 | grep -o -- "--with-[a-z0-9_]*" | ماژولهای build شده |
curl -i http://localhost/ | پاسخ کامل با هدرها |
curl -sI https://site | grep -i ^server | وبسرور یک سایت (فقط هدرها) |
curl -s -o /dev/null -w "%{http_code}\n" URL | فقط کد وضعیت |
nginx -t && systemctl reload nginx | آزمایش و اعمال تنظیمات |
proxy_pass http://127.0.0.1:9001; | reverse proxy به یک اپ |
upstream app { server a; server b; } | گروه سرورها برای load balancing |
ps -o pid,user,cmd -C nginx | master و worker ها |
ab -n 2000 -c 50 URL | آزمایش بار ساده |