رفتن به محتوا
LoopX

دستورات و تنظیمات Nginx: برگه‌ی تقلب کامل

همه‌ی دستورهای دوره‌ی Nginx کاربردی در یک صفحه: ۱۷۹ دستور از ۱۶ درس، به ترتیب درس‌ها. هر دستور در درس خودش با خروجی واقعی اجرا و توضیح داده شده است؛ روی اسم درس بزن تا توضیح کامل و مثال‌ها را ببینی.

مبانی

Nginx چیست؟

دستورکاری که می‌کند
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 nginxmaster و worker ها
ab -n 2000 -c 50 URLآزمایش بار ساده

نصب و اجرا

دستورکاری که می‌کند
sudo apt install nginxنصب روی Ubuntu
apt-cache policy nginxنسخه‌ی موجود در مخزن
sudo systemctl status nginxوضعیت و چند خط آخر لاگ
sudo systemctl enable --now nginxفعال در بوت و شروع همین الان
sudo nginx -t && sudo systemctl reload nginxآزمایش و اعمال امن تنظیمات
sudo journalctl -u nginx --no-pager | tailلاگ سرویس برای عیب‌یابی
sudo dpkg --configure -aکامل کردن نصب نیمه‌کاره
sudo ss -tlnp "sport = :80"چه کسی پورت ۸۰ را گرفته؟
sudo ufw allow 'Nginx Full'باز کردن ۸۰ و ۴۴۳ در فایروال
docker run -d -p 8080:80 nginx:alpineNginx در داکر
docker run -d -p 8091:80 -v "$PWD/site:/usr/share/nginx/html:ro" nginx:alpineسرو کردن پوشه‌ی خودت
docker exec CONTAINER nginx -s reloadreload داخل کانتینر

ساختار فایل‌های تنظیمات

دستورکاری که می‌کند
sudo nginx -tآزمایش تنظیمات، با فایل و شماره‌ی خط خطا
sudo nginx -T | grep '^# configuration file'فایل‌هایی که واقعاً خوانده می‌شوند
sudo systemctl reload nginxاعمال تنظیمات بدون قطع
sudo ln -s /etc/nginx/sites-available/shop.test /etc/nginx/sites-enabled/روشن کردن یک سایت
sudo rm /etc/nginx/sites-enabled/shop.testخاموش کردن سایت
ls -l /etc/nginx/sites-enabled/سایت‌های فعال (باید -> نشان دهد)
include snippets/headers.conf;آوردن یک تکه‌ی مشترک
return 200 "ok\n";پاسخ مستقیم بدون فایل
curl --resolve shop.test:80:127.0.0.1 http://shop.test/آزمایش یک دامنه بدون DNS
grep -nvE '^\s*(#|$)' /etc/nginx/nginx.confخواندن فایل بدون کامنت

server block و چند سایت

دستورکاری که می‌کند
server { listen 80; server_name shop.test; root /var/www/shop.test; index index.html; }یک سایت
listen 80 default_server; server_name _; return 444;catch-all برای دامنه‌های ناشناخته
server_name shop.test www.shop.test;چند اسم برای یک سایت
server_name *.shop.test;همه‌ی زیردامنه‌ها
server_name ~^(?<user>[a-z0-9-]+)\.sites\.test$;regex با گروه نام‌دار
return 301 http://shop.test$request_uri;ریدایرکت با حفظ مسیر
listen 127.0.0.1:8087;فقط داخلی
echo "127.0.0.1 shop.test" | sudo tee -a /etc/hostsدامنه‌ی محلی برای آزمایش
curl -H "Host: shop.test" http://127.0.0.1/آزمایش با هدر Host دلخواه
curl -sv http://shop.test/ 2>&1 | grep '^> Host'دیدن هدر Host فرستاده‌شده
add_header X-Debug-Server $server_name always;کدام block جواب داد؟

location و مسیرها

دستورکاری که می‌کند
location = /health { return 200 "ok\n"; }تطبیق دقیق
location /api/ { proxy_pass http://127.0.0.1:3000; }پیشوندی: همه‌ی /api/...
location ^~ /static/ { ... }پیشوندی که regex را کنار می‌زند
location ~* \.(jpg|png|webp)$ { ... }regex بدون حساسیت به حروف
try_files $uri $uri/ =404;سایت استاتیک
try_files $uri $uri.html $uri/ =404;آدرس بدون .html
try_files $uri @app;نبود؟ برو به named location
location /static/ { root /srv; }/static/a ← /srv/static/a
location /static/ { alias /srv/assets/; }/static/a ← /srv/assets/a (اسلش‌ها هماهنگ)
add_header X-Matched "name" always;کدام location جواب داد؟
curl --path-as-is "http://site/a/../b"فرستادن مسیر بدون نرمال‌سازی curl

سرو سایت استاتیک

دستورکاری که می‌کند
try_files $uri $uri/ =404;سایت چندصفحه‌ای
error_page 404 /404.html;صفحه‌ی ۴۰۴ سفارشی با کد ۴۰۴
error_page 500 502 503 504 /50x.html;صفحه‌ی خطای سرور
location ^~ /errors/ { internal; }بستن دسترسی مستقیم به صفحه‌های خطا
location / { try_files $uri $uri/ /index.html; }SPA fallback
location /assets/ { try_files $uri =404; }۴۰۴ واقعی برای دارایی‌های SPA
location /downloads/ { alias /srv/downloads/; autoindex on; }فهرست پوشه‌ی دانلود
location ~ /\.(?!well-known) { deny all; }بستن .git، .env و فایل‌های مخفی
curl -s -o /dev/null -w '%{http_code} %{content_type}' URLکد و نوع پاسخ
curl -H "If-None-Match: $etag" URLآزمایش 304

لاگ‌ها

دستورکاری که می‌کند
sudo tail -f /var/log/nginx/access.logلاگ زنده
sudo tail -F /var/log/nginx/access.logزنده، حتی بعد از چرخش
awk '{print $1}' access.log | sort | uniq -c | sort -rn | headپرتکرارترین IPها
awk '{print $7}' access.log | sort | uniq -c | sort -rn | headپرتکرارترین صفحه‌ها
awk '{print $9}' access.log | sort | uniq -c | sort -rnتوزیع کدهای وضعیت
awk '$9 == 404 {print $1, $7}' access.log | sort | uniq -c | sort -rn۴۰۴ ها با IP
log_format timed '... rt=$request_time urt=$upstream_response_time';قالب با زمان پاسخ (در http)
access_log /var/log/nginx/shop.access.log timed;لاگ جدا برای یک سایت
access_log off;خاموش کردن لاگ (مثلاً favicon)
access_log ... if=$loggable;لاگ شرطی (با map)
error_log /var/log/nginx/error.log warn;فقط warn و بالاتر
sudo nginx -s reopenباز کردن دوباره‌ی فایل‌های لاگ
sudo logrotate -d /etc/logrotate.d/nginxاجرای آزمایشی logrotate

reverse proxy و HTTPS

reverse proxy

دستورکاری که می‌کند
proxy_pass http://127.0.0.1:3000;فرستادن به اپ (مسیر دست‌نخورده)
proxy_pass http://127.0.0.1:3000/;حذف پیشوند location از مسیر
include proxy_params;Host، X-Real-IP، X-Forwarded-For، X-Forwarded-Proto
proxy_set_header X-Real-IP $remote_addr;IP واقعی کاربر
proxy_read_timeout 120s;اپ کند (جلوگیری از ۵۰۴ زودهنگام)
proxy_connect_timeout 2s;تشخیص سریع اپ خاموش
client_max_body_size 20m;آپلود بزرگ‌تر از ۱ مگابایت
upstream app { server 127.0.0.1:3000; keepalive 16; }گروه اپ با اتصال‌های باز
proxy_http_version 1.1; proxy_set_header Connection "";لازم برای keepalive
error_page 502 503 504 /50x.html;صفحه‌ی دوستانه هنگام قطعی اپ
ss -tnp | grep :3000دیدن اتصال Nginx به اپ

WebSocket

دستورکاری که می‌کند
proxy_http_version 1.1;لازم برای ارتقای پروتکل
proxy_set_header Upgrade $http_upgrade;رساندن هدر Upgrade به اپ
proxy_set_header Connection $connection_upgrade;upgrade یا close (با map)
map $http_upgrade $connection_upgrade { default upgrade; '' close; }در context http (conf.d)
proxy_read_timeout 1h;قطع نشدن اتصال ساکت
curl -i -H 'Connection: Upgrade' -H 'Upgrade: websocket' -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: ...' URLآزمایش دست‌دادن (انتظار: 101)
new WebSocket(`${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${location.host}/ws/`)آدرس WebSocket نسبی در مرورگر
sudo apt install python3-websocketsکتابخانه‌ی WebSocket پایتون (برای آزمایش)

HTTPS با Let's Encrypt

دستورکاری که می‌کند
sudo apt install certbot python3-certbot-nginxنصب certbot و افزونه‌ی nginx
sudo certbot --nginx -d example.com -d www.example.comگرفتن و نصب گواهی
sudo certbot --nginx -d example.com --redirectبه‌علاوه‌ی انتقال HTTP به HTTPS
sudo certbot renew --dry-runآزمایش تمدید
sudo certbot certificatesفهرست و تاریخ انقضا
systemctl list-timers certbot.timerتمدید خودکار کی اجرا می‌شود
listen 443 ssl; ssl_certificate .../fullchain.pem; ssl_certificate_key .../privkey.pem;TLS دستی در Nginx
return 301 https://$host$request_uri;انتقال به HTTPS
echo | openssl s_client -connect IP:443 -servername example.comدیدن گواهی و زنجیره
openssl x509 -in cert.pem -noout -issuer -dates -ext subjectAltNameخواندن گواهی
openssl req -x509 -newkey rsa:2048 -nodes -days 365 -keyout k.key -out c.crt -subj '/CN=name'گواهی خودامضا

امنیت و هدرهای امنیتی

دستورکاری که می‌کند
server_tokens off;پنهان کردن نسخه (در http)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;HSTS (روی HTTPS)
add_header X-Content-Type-Options "nosniff" always;جلوگیری از حدس نوع فایل
add_header X-Frame-Options "SAMEORIGIN" always;جلوگیری از clickjacking
add_header Referrer-Policy "strict-origin-when-cross-origin" always;محدود کردن Referer
add_header Content-Security-Policy-Report-Only "default-src 'self'" always;آزمایش CSP بدون مسدود کردن
include snippets/security-headers.conf;یک بار نوشتن، همه‌جا استفاده
proxy_hide_header X-Powered-By;حذف هدر اپ
allow 127.0.0.1; deny all;فقط از IP های مشخص
htpasswd -c /etc/nginx/.htpasswd adminساخت فایل رمز
auth_basic "Admin"; auth_basic_user_file /etc/nginx/.htpasswd;رمز برای یک location
curl -sI https://example.comدیدن هدرهای پاسخ

عملکرد و مقیاس

عملکرد: gzip و کش

دستورکاری که می‌کند
curl -H "Accept-Encoding: gzip" -I URLفشرده می‌شود؟ (Content-Encoding)
curl -so /dev/null -w '%{size_download}' -H 'Accept-Encoding: gzip' URLاندازه‌ی منتقل‌شده
limit_rate 10k;محدود کردن سرعت هر پاسخ (شبیه‌سازی اینترنت کند)
curl -so /dev/null -w "%{time_total}" URLزمان کل دریافت
gzip_types text/css application/javascript application/json image/svg+xml;فشرده‌سازی CSS و JS و ...
gzip_comp_level 5; gzip_min_length 256; gzip_vary on; gzip_proxied any;تنظیم متعادل
gzip_static on;سرو .gz آماده
gzip -k -9 file.cssساخت file.css.gz و نگه داشتن اصلی
expires 1y; add_header Cache-Control "public, immutable" always;فایل hash‌دار
add_header Cache-Control "no-cache" always;HTML: همیشه بپرس
listen 443 ssl http2;HTTP/2 (Nginx 1.24)

load balancing

دستورکاری که می‌کند
upstream backend { zone backend 64k; server 127.0.0.1:9411; ... }گروه سرور با حالت مشترک
proxy_pass http://backend;فرستادن به گروه
server 127.0.0.1:9411 weight=3;سهم بیشتر
least_conn;کم‌مشغول‌ترین عضو
ip_hash;چسبندگی با سه بخش اول IP
hash $remote_addr consistent;چسبندگی با کل IP
server ... max_fails=2 fail_timeout=10s;کنار گذاشتن عضو خراب
server ... backup;عضو ذخیره
server ... down;خارج از سرویس موقت
log_format lb '... $upstream_addr $upstream_status';کدام عضو جواب داد
systemctl start lx-app@9411اجرای نمونه از unit قالبی systemd
curl --interface 127.0.0.2 URLدرخواست از یک IP دیگر
resolver 127.0.0.11; server app:80 resolve;دیدن scale در داکر
docker compose up -d --scale app=5تغییر تعداد نسخه‌ها

محدودسازی درخواست‌ها

دستورکاری که می‌کند
limit_req_zone $binary_remote_addr zone=perip:10m rate=2r/s;تعریف سطل برای هر IP
limit_req zone=perip;اعمال بدون هجوم
limit_req zone=perip burst=5;صف تا ۵ درخواست
limit_req zone=perip burst=5 nodelay;تا ۵ اضافه فوراً
limit_req_status 429;کد رد
limit_req_dry_run on;فقط لاگ، بدون رد
limit_req_log_level warn;سطح لاگ
limit_conn_zone $binary_remote_addr zone=conns:10m;تعریف شمارنده‌ی اتصال
limit_conn conns 2;حداکثر ۲ همزمان
geo $limited { default 1; 10.0.0.0/8 0; }برچسب IP های مورد اعتماد
map $limited $limit_key { 0 ""; 1 $binary_remote_addr; }کلید خالی برای لیست سفید
seq 10 | xargs -P 10 -I{} curl -s -o /dev/null -w "%{http_code}\n" URLآزمایش با درخواست همزمان

Nginx در داکر و Compose

دستورکاری که می‌کند
docker run -d -p 127.0.0.1:8099:80 -v ./conf:/etc/nginx/conf.d:ro nginx:alpineNginx با تنظیمات خودت
docker exec CONTAINER nginx -tتست تنظیمات
docker compose exec nginx nginx -s reloadreload بدون ریستارت
docker compose exec nginx nginx -Tکل تنظیمات نهایی
docker compose logs nginxلاگ دسترسی و خطا
proxy_pass http://api:8080;proxy به سرویس با اسم
resolver 127.0.0.11 valid=5s;DNS داخلی داکر
server api:8080 resolve;resolve دوباره‌ی اسم (در upstream با zone)
docker compose exec nginx getent hosts apiIP فعلی سرویس
-v ./templates:/etc/nginx/templates:ro -e NAME=...قالب با envsubst

پروژه: استقرار کامل

دستورکاری که می‌کند
certbot certonly --webroot -w /var/www/letsencrypt -d DOMAIN --deploy-hook "systemctl reload nginx"گواهی بدون دست زدن به تنظیمات
ln -sfn RELEASE current.new && mv -T current.new currentعوض کردن اتمی نسخه
gzip -k -9 assets/*فایل‌های .gz برای gzip_static
systemctl enable --now lx-shop-api@3001نسخه‌ی API از unit قالبی
listen 443 ssl http2;HTTPS با HTTP/2
return 301 https://shop.test$request_uri;انتقال به دامنه‌ی اصلی
include snippets/lx-shop-security.conf;هدرهای امنیتی در هر location
proxy_hide_header X-Powered-By;پنهان کردن فناوری اپ
location ~ /\. { deny all; }محافظت از فایل‌های نقطه‌دار
log_format shop '... rt=$request_time urt=$upstream_response_time';لاگ با زمان
curl -w "%{time_appconnect} %{time_starttransfer}" URLزمان TLS و اولین بایت
openssl x509 -in CERT -noout -checkend 1209600گواهی تا ۱۴ روز دیگر معتبر است؟
certbot renew --dry-runآزمایش تمدید