توی این درس یاد میگیری Nginx را به دو روش راه بیندازی: روی خود سرور با sudo apt install nginx (که آن را به یک سرویس systemd تبدیل میکند)، و داخل داکر با docker run -d -p 8080:80 nginx:alpine. سرویس را با systemctl کنترل میکنی و فرق حیاتی reload و restart را با یک آزمایش واقعی میبینی؛ فایروال را برای Nginx باز میکنی؛ و وقتی نصب یا اجرا شکست خورد، با systemctl status، journalctl و nginx -t دلیلش را پیدا و درستش میکنی.
مسئله: «نصب کردم ولی صفحه باز نمیشود»
Section titled “مسئله: «نصب کردم ولی صفحه باز نمیشود»”نصب Nginx یک خط است، ولی سؤالهای بعدش زیادند: الان در حال اجراست؟ بعد از ریبوت سرور خودش بالا میآید؟ تنظیمات را عوض کردم، چطور اعمالش کنم که سایت قطع نشود؟ پورت ۸۰ از بیرون باز است؟ و اگر بالا نیامد، پیام خطا کجاست؟ این درس جواب همینهاست. (و ماشین آزمایشی ما هم یک خطای واقعی و آموزنده جلویمان گذاشت.)
تشبیه: نصب یک کولر
Section titled “تشبیه: نصب یک کولر”نصب Nginx مثل نصب یک کولر است. خریدن و نصبش (apt install) یک کار است؛ ولی بعدش باید بدانی کلیدش کجاست (systemctl start و stop)، اینکه بعد از قطع برق خودش روشن شود (enable)، اینکه برای عوض کردن دما لازم نیست خاموش و روشنش کنی (reload بهجای restart)، و اینکه پنجره باید باز باشد تا باد بیرون برود (فایروال). و اگر روشن نشد، اول چراغ خطایش را نگاه میکنی (status و journalctl)، نه اینکه کولر را پس بدهی.
دو راه اجرای Nginx
Section titled “دو راه اجرای Nginx”| روی سرور (apt) | داخل داکر | |
|---|---|---|
| نصب | sudo apt install nginx |
docker run -d -p 8080:80 nginx:alpine |
| مدیریت | systemctl (سرویس systemd) |
docker start/stop/restart/logs |
| تنظیمات | /etc/nginx/ |
فایلهایی که داخل کانتینر mount میکنی |
| نسخه | نسخهی مخزن Ubuntu (اینجا ۱.۲۴) | هر نسخهای که tag بگویی (nginx:1.27-alpine) |
| کی بهتر است؟ | سرور معمولی، چند سایت، HTTPS با certbot | وقتی بقیهی اپها هم کانتینرند (Compose)، یا نسخهی خاص میخواهی |
هر دو را در این دوره به کار میبریم؛ مفاهیم و فایل تنظیمات در هر دو یکی است.
مثالهای عملی
Section titled “مثالهای عملی”این درس روی ماشین آزمایشی server (Ubuntu 24.04 با systemd واقعی) اجرا شده؛ اول Nginx را کامل از رویش پاک کردیم تا نصب را از صفر ببینیم. دستورها با root اجرا شدهاند؛ روی سرور خودت جلویشان sudo بگذار (همانطور که در متن آمده). بخش داکر روی یک موتور داکر جدا اجرا شده است.
مثال ۱: نصب با sudo apt install nginx
Section titled “مثال ۱: نصب با sudo apt install nginx”اول ببینیم نصب نیست و مخزن کدام نسخه را دارد:
command -v nginx || echo "nginx is not installed"apt-cache policy nginx | head -n 3nginx is not installednginx: Installed: (none) Candidate: 1.24.0-2ubuntu7.18apt-cache policy میگوید نسخهی Candidate (همان که نصب خواهد شد) 1.24.0 است. حالا نصب (-y یعنی سؤال «مطمئنی؟» را خودکار بله بگو):
apt-get install -y nginx 2>&1 | grep -v 'Reading database'echo "کد خروج apt: ${PIPESTATUS[0]}" Process: 17602 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=1/FAILURE)
Oct 04 12:42:45 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...Oct 04 12:42:45 server nginx[17602]: nginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol)Oct 04 12:42:45 server nginx[17602]: nginx: configuration file /etc/nginx/nginx.conf test failedOct 04 12:42:45 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILUREOct 04 12:42:45 server systemd[1]: nginx.service: Failed with result 'exit-code'.Oct 04 12:42:45 server systemd[1]: Failed to start nginx.service - A high performance web server and a reverse proxy server.dpkg: error processing package nginx (--configure): installed nginx package post-installation script subprocess returned error exit status 1Processing triggers for man-db (2.12.0-4build2) ...Processing triggers for ufw (0.36.2-6) ...Errors were encountered while processing: nginxE: Sub-process /usr/bin/dpkg returned an error code (1)کد خروج apt: 100بستهها دانلود و باز شدند، سرویس فعال (enable) شد (Created symlink ...multi-user.target.wants/nginx.service) و apt سعی کرد آن را شروع کند، ولی شکست خورد و آخرش Errors were encountered while processing: nginx و کد خروج ۱۰۰. روی بیشتر سرورها این مرحله بیمشکل تمام میشود و Nginx همان لحظه بالاست؛ ولی همین خطا یک درس واقعی است: نصب شکست نخورده، شروع سرویس شکست خورده. بستهها کامل نصب شدهاند و فقط مرحلهی «پیکربندی (configure)» ناتمام مانده. پس سراغ دلیلش میرویم، نه حذف و نصب دوباره.
مثال ۲: عیبیابی با systemctl status و journalctl
Section titled “مثال ۲: عیبیابی با systemctl status و journalctl”اولین دستور برای هر سرویسی که درست کار نمیکند:
systemctl status nginx --no-pager | head -n 12× nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled) Active: failed (Result: exit-code) since Sun 2026-10-04 12:42:45 UTC; 140ms ago Docs: man:nginx(8) Process: 17602 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=1/FAILURE)
Oct 04 12:42:45 server systemd[1]: Starting nginx.service - A high performance web server and a reverse proxy server...Oct 04 12:42:45 server nginx[17602]: nginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol)Oct 04 12:42:45 server nginx[17602]: nginx: configuration file /etc/nginx/nginx.conf test failedOct 04 12:42:45 server systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILUREOct 04 12:42:45 server systemd[1]: nginx.service: Failed with result 'exit-code'.Oct 04 12:42:45 server systemd[1]: Failed to start nginx.service - A high performance web server and a reverse proxy server.خط Active: failed وضعیت است و Process: ... ExecStartPre=/usr/sbin/nginx -t ... status=1/FAILURE میگوید قبل از شروع، آزمایش تنظیمات (nginx -t) شکست خورده است. چند خط آخر لاگ هم همانجاست. برای لاگ کامل سرویس:
journalctl -u nginx --no-pager | grep -E 'emerg|failed' | tail -n 3 | sed -E 's/^[A-Z][a-z]{2} [0-9]+ [0-9:]+ //'echo "--- همان را مستقیم از nginx -t:"nginx -tserver nginx[17587]: nginx: configuration file /etc/nginx/nginx.conf test failedserver nginx[17602]: nginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol)server nginx[17602]: nginx: configuration file /etc/nginx/nginx.conf test failed--- همان را مستقیم از nginx -t:nginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: [emerg] socket() [::]:80 failed (97: Address family not supported by protocol)nginx: configuration file /etc/nginx/nginx.conf test failedپیام اصلی این است: socket() [::]:80 failed (97: Address family not supported by protocol). یعنی Nginx میخواهد روی IPv6 (آدرس [::]) هم گوش بدهد، ولی هستهی این ماشین IPv6 ندارد. سایت پیشفرض Ubuntu دو خط listen دارد؛ یکی برای IPv4 و یکی برای IPv6:
grep -n 'listen' /etc/nginx/sites-available/default | head -n 222: listen 80 default_server;23: listen [::]:80 default_server;روی سروری که IPv6 دارد این دو خط با هم کار میکنند. روی سروری که IPv6 خاموش است (بعضی شرکتها و میزبانها خاموشش میکنند)، خط دوم را غیرفعال میکنیم:
sed -i 's/^\(\s*listen \[::\]:80\)/#\1/' /etc/nginx/sites-available/defaultgrep -n 'listen' /etc/nginx/sites-available/default | head -n 2nginx -t22: listen 80 default_server;23:# listen [::]:80 default_server;nginx: the configuration file /etc/nginx/nginx.conf syntax is oknginx: configuration file /etc/nginx/nginx.conf test is successful# اول خط آن را به کامنت تبدیل کرد و nginx -t حالا موفق است. حالا مرحلهی ناتمام نصب را کامل میکنیم. dpkg --configure -a همهی بستههایی را که پیکربندیشان نیمهکاره مانده، دوباره پیکربندی میکند:
dpkg --configure -a 2>&1 | grep -v '^$'echo "--- وضعیت بسته و سرویس:"dpkg -l nginx | tail -n 1 | awk '{print $1, $2, $3}'systemctl is-active nginxsystemctl is-enabled nginxSetting up nginx (1.24.0-2ubuntu7.18) ...--- وضعیت بسته و سرویس:ii nginx 1.24.0-2ubuntu7.18activeenabledii یعنی «نصبشده و پیکربندیشده» (اگر ناتمام بود iF یا iU میدیدی)، سرویس active و enabled است. درس مهم: وقتی apt خطا میدهد، اول ببین کدام مرحله شکست خورده؛ اغلب با یک اصلاح و dpkg --configure -a درست میشود.
مثال ۳: systemctl، کنترل سرویس
Section titled “مثال ۳: systemctl، کنترل سرویس”حالا که Nginx بالاست، systemctl status تصویر کامل را میدهد:
systemctl status nginx --no-pager | head -n 9● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/usr/lib/systemd/system/nginx.service; enabled; preset: enabled) Active: active (running) since Sun 2026-10-04 12:42:45 UTC; 31ms ago Docs: man:nginx(8) Process: 17642 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Process: 17644 ExecStart=/usr/sbin/nginx -g daemon on; master_process on; (code=exited, status=0/SUCCESS) Main PID: 17645 (nginx) CGroup: /system.slice/nginx.service ├─17645 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;"- Loaded: فایل سرویس (
/usr/lib/systemd/system/nginx.service) وenabledیعنی موقع بوت خودش اجرا میشود. - Active: active (running) و از کی.
- Main PID و CGroup: پروسهی master و worker ها (همانهایی که در درس قبل با
psدیدیم).
دستورهای کنترل:
systemctl stop nginxecho "after stop: $(systemctl is-active nginx); curl: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/ || true)"systemctl start nginxecho "after start: $(systemctl is-active nginx); curl: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/)"systemctl disable nginx 2>&1echo "is-enabled: $(systemctl is-enabled nginx)"systemctl enable nginx 2>&1echo "is-enabled: $(systemctl is-enabled nginx)"after stop: inactive; curl: 000after start: active; curl: 200Synchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.Executing: /usr/lib/systemd/systemd-sysv-install disable nginxRemoved "/etc/systemd/system/multi-user.target.wants/nginx.service".is-enabled: disabledSynchronizing state of nginx.service with SysV service script with /usr/lib/systemd/systemd-sysv-install.Executing: /usr/lib/systemd/systemd-sysv-install enable nginxCreated symlink /etc/systemd/system/multi-user.target.wants/nginx.service → /usr/lib/systemd/system/nginx.service.is-enabled: enabledبعد از stop، curl اصلاً وصل نشد (کد 000 یعنی جوابی نیامد). disable فقط اجرای خودکار هنگام بوت را برمیدارد و سرویس الان را خاموش نمیکند؛ enable برعکس. (systemctl enable --now nginx هر دو کار را با هم میکند: فعال و همین الان شروع.)
مثال ۴: reload در برابر restart، با یک تنظیم خراب
Section titled “مثال ۴: reload در برابر restart، با یک تنظیم خراب”بعد از هر تغییر تنظیمات باید Nginx را خبر کنی. دو راه هست و فرقشان حیاتی است. این آزمایش را ببین: یک فایل تنظیمات خراب (یک ; جاافتاده) میسازیم و هر دو را امتحان میکنیم:
printf 'server {\n listen 8090\n}\n' > /etc/nginx/conf.d/lx-broken.confecho "=== reload با تنظیم خراب:"systemctl reload nginx 2>&1 | head -n 2echo "سرویس: $(systemctl is-active nginx) | سایت: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/)"echo "=== restart با تنظیم خراب:"systemctl restart nginx 2>&1 | head -n 2echo "سرویس: $(systemctl is-active nginx) | سایت: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/ || true)"echo "=== اصلاح و شروع دوباره:"rm /etc/nginx/conf.d/lx-broken.confnginx -t 2>&1 | tail -n 1systemctl start nginx 2>&1 | head -n 1journalctl -u nginx --no-pager | grep -c 'Start request repeated too quickly'systemctl reset-failed nginxsystemctl start nginxecho "سرویس: $(systemctl is-active nginx) | سایت: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/)"=== reload با تنظیم خراب:Job for nginx.service failed.See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.سرویس: active | سایت: 200=== restart با تنظیم خراب:Job for nginx.service failed because the control process exited with error code.See "systemctl status nginx.service" and "journalctl -xeu nginx.service" for details.سرویس: failed | سایت: 000=== اصلاح و شروع دوباره:nginx: configuration file /etc/nginx/nginx.conf test is successfulJob for nginx.service failed because the control process exited with error code.6سرویس: active | سایت: 200reloadبا تنظیم خراب شکست خورد ولی سایت بالا ماند (کد ۲۰۰)؛ Nginx تنظیمات تازه را رد کرد و با تنظیمات قبلی ادامه داد.restartبا همان تنظیم خراب، Nginx را خاموش کرد و دیگر بالا نیاورد: سایت از دسترس خارج شد (000).
و یک نکتهی واقعی دیگر در قسمت آخر: بعد از اصلاح، اولین start هم شکست خورد! لاگ میگوید Start request repeated too quickly. systemd اگر سرویسی در مدت کوتاهی (بهصورت پیشفرض ۵ بار در ۱۰ ثانیه) پشت هم شروع شود یا شکست بخورد، جلوی شروع دوباره را موقتاً میگیرد تا یک سرویس خراب سیستم را درگیر نکند. ما در همین چند ثانیه چند بار Nginx را شروع کرده بودیم. systemctl reset-failed nginx شمارنده را صفر میکند (یا چند ثانیه صبر کن).
قاعدهی طلایی: همیشه nginx -t و بعد reload. restart را فقط وقتی لازم است بزن (مثلاً بعد از ارتقای نسخهی Nginx). یکخطی رایج: sudo nginx -t && sudo systemctl reload nginx (با &&، اگر آزمایش شکست بخورد reload اجرا نمیشود).
مثال ۵: صفحهی پیشفرض و فایروال
Section titled “مثال ۵: صفحهی پیشفرض و فایروال”صفحهی خوشامد Nginx از کجا میآید؟
curl -s http://localhost/ | grep -o '<title>.*</title>'ls -l /var/www/html/grep -E '^\s*(root|index)' /etc/nginx/sites-available/default<title>Welcome to nginx!</title>total 4-rw-r--r-- 1 root root 615 Oct 4 12:42 index.nginx-debian.html root /var/www/html; index index.html index.htm index.nginx-debian.html;سایت پیشفرض پوشهی /var/www/html را سرو میکند و اولین فایل از فهرست index را که پیدا کند (اینجا index.nginx-debian.html) نشان میدهد. اگر index.html خودت را در همین پوشه بگذاری، آن را نشان میدهد.
روی سرور واقعی، اگر فایروال (ufw، درس فایروال در دورهی لینوکس) روشن است، باید پورتهای وب را باز کنی. Nginx هنگام نصب پروفایلهای آماده به ufw اضافه میکند:
ufw app listufw app info 'Nginx Full'Available applications: Nginx Full Nginx HTTP Nginx HTTPS OpenSSHProfile: Nginx FullTitle: Web Server (Nginx, HTTP + HTTPS)Description: Small, but very powerful and efficient web server
Ports: 80,443/tcpNginx HTTP فقط پورت ۸۰، Nginx HTTPS فقط ۴۴۳، و Nginx Full هر دو. دستور باز کردن روی سرور واقعی: sudo ufw allow 'Nginx Full' (و قبلش مطمئن شو SSH هم مجاز است: sudo ufw allow OpenSSH، وگرنه با روشن کردن فایروال خودت را بیرون میاندازی).
مثال ۶: Nginx با داکر
Section titled “مثال ۶: Nginx با داکر”شکل کلی دستور:
docker run -d -p 8080:80 nginx:alpine-d یعنی در پسزمینه، -p 8080:80 یعنی «پورت ۸۰۸۰ میزبان را به پورت ۸۰ کانتینر وصل کن» (درس پورتها در دورهی داکر) و nginx:alpine ایمیج رسمی Nginx روی Alpine (کوچک). ما پورت 8091 و اسم lx-nginx را به کار میبریم تا با برنامههای دیگرت برخورد نکند (پورت ۸۰۸۰ را خود سایت LoopX در حالت داکری استفاده میکند):
docker run -d --name lx-nginx -p 8091:80 nginx:alpine > /dev/nullsleep 1docker ps --filter name=lx-nginx --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}' | sed 's/, \[::\][^ ]*//'docker exec lx-nginx nginx -vcurl -s -I http://localhost:8091/ | grep -iE '^(HTTP|server)'docker logs lx-nginx 2>&1 | tail -n 2NAMES IMAGE STATUS PORTSlx-nginx nginx:alpine Up 1 second 0.0.0.0:8091->80/tcpnginx version: nginx/1.31.6HTTP/1.1 200 OKServer: nginx/1.31.62026/10/04 12:37:07 [notice] 1#1: start worker process 24172.17.0.1 - - [04/Oct/2026:12:37:09 +0000] "HEAD / HTTP/1.1" 200 0 "-" "curl/8.5.0" "-"- نسخهی ایمیج (
1.31.x) از نسخهی مخزن Ubuntu (1.24) جدیدتر است؛ این یکی از دلیلهای استفاده از داکر است. (اگر نسخهی ثابت میخواهی، tag دقیق بنویس، مثلاًnginx:1.31-alpine.) docker logsلاگ دسترسی Nginx را نشان میدهد؛ در ایمیج رسمی، لاگها به stdout و stderr کانتینر فرستاده میشوند.
سایت خودت را با یک bind mount (درس volume در دورهی داکر) جای صفحهی پیشفرض بگذار:
mkdir -p siteecho '<h1>Coming soon: LoopX shop</h1>' > site/index.htmldocker rm -f lx-nginx > /dev/nulldocker run -d --name lx-nginx -p 8091:80 -v "$PWD/site:/usr/share/nginx/html:ro" nginx:alpine > /dev/nullsleep 1curl -s http://localhost:8091/docker rm -f lx-nginx > /dev/null<h1>Coming soon: LoopX shop</h1>در ایمیج رسمی، پوشهی سایت /usr/share/nginx/html است (نه /var/www/html مثل Ubuntu). :ro یعنی فقطخواندنی؛ کانتینر نمیتواند فایلهای سایتت را عوض کند.
پشت پرده: سرویس nginx در systemd چطور تعریف شده؟
Section titled “پشت پرده: سرویس nginx در systemd چطور تعریف شده؟”systemctl cat فایل سرویس را نشان میدهد:
systemctl cat nginx --no-pager | grep -vE '^\s*(#|$)'[Unit]Description=A high performance web server and a reverse proxy serverDocumentation=man:nginx(8)After=network-online.target remote-fs.target nss-lookup.targetWants=network-online.targetConditionFileIsExecutable=/usr/sbin/nginx[Service]Type=forkingPIDFile=/run/nginx.pidExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;'ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;'ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reloadExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pidTimeoutStopSec=5KillMode=mixed[Install]WantedBy=multi-user.targetExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;': قبل از هر شروع، تنظیمات آزمایش میشود (برای همین در مثال ۲ دلیل شکست،ExecStartPreبود).ExecStart: خود Nginx.ExecReload: اولnginx -tو بعدnginx -s reload. یعنیsystemctl reloadدر واقع به پروسهی master یک سیگنال میفرستد.PIDFile=/run/nginx.pid: شمارهی پروسهی master اینجا نوشته میشود.
خود Nginx هم دستور کنترل دارد: nginx -s SIGNAL. reload همان سیگنال HUP است که به master فرستاده میشود:
echo "master: $(cat /run/nginx.pid) | workers: $(pgrep -d ' ' -f 'nginx: worker')"kill -HUP "$(cat /run/nginx.pid)"sleep 1echo "master: $(cat /run/nginx.pid) | workers: $(pgrep -d ' ' -f 'nginx: worker')"master: 17827 | workers: 17828 17829 17830 17831master: 17827 | workers: 17849 17850 17851 17852با kill -HUP دستی همان اتفاق reload افتاد: worker های تازه، master ثابت. روی سرور systemdدار همیشه از systemctl استفاده کن (تا systemd وضعیت را بداند)؛ ولی داخل کانتینر داکر که systemd نیست، nginx -s reload راه اصلی است (درس Nginx در داکر).
جدولهای مرجع
Section titled “جدولهای مرجع”دستورهای سرویس:
| دستور | کار |
|---|---|
sudo apt install nginx |
نصب (و فعالسازی و شروع سرویس) |
sudo systemctl status nginx |
وضعیت، PID، چند خط آخر لاگ |
sudo systemctl start / stop nginx |
شروع / توقف |
sudo systemctl reload nginx |
خواندن دوبارهی تنظیمات بدون قطع (با تنظیم خراب، قبلی میماند) |
sudo systemctl restart nginx |
توقف و شروع دوباره (با تنظیم خراب، خاموش میماند) |
sudo systemctl enable / disable nginx |
اجرای خودکار هنگام بوت، روشن / خاموش |
sudo systemctl enable --now nginx |
فعال و همین الان شروع |
systemctl is-active / is-enabled nginx |
جواب یککلمهای (مناسب اسکریپت) |
sudo journalctl -u nginx |
لاگهای systemd برای nginx |
sudo nginx -t |
آزمایش تنظیمات |
sudo nginx -s reload |
reload با سیگنال (داخل کانتینر) |
sudo dpkg --configure -a |
تمام کردن پیکربندی بستههای نیمهکاره |
sudo systemctl reset-failed nginx |
صفر کردن شمارندهی شکست (بعد از Start request repeated too quickly) |
sudo apt remove nginx / purge nginx |
حذف برنامه / حذف با فایلهای تنظیمات |
مسیرهای مهم در Ubuntu:
| مسیر | چیست |
|---|---|
/etc/nginx/ |
همهی تنظیمات (درس بعد) |
/var/www/html/ |
سایت پیشفرض |
/var/log/nginx/access.log، error.log |
لاگها (درس لاگها) |
/run/nginx.pid |
PID پروسهی master |
/usr/lib/systemd/system/nginx.service |
فایل سرویس |
اشتباهات رایج
Section titled “اشتباهات رایج”۱) پورت ۸۰ را برنامهی دیگری گرفته
Section titled “۱) پورت ۸۰ را برنامهی دیگری گرفته”systemctl stop nginx(exec python3 -m http.server 80 --bind 0.0.0.0) > /dev/null 2>&1 &sleep 1systemctl reset-failed nginxsystemctl start nginx 2>&1 | head -n 1journalctl -u nginx --no-pager | grep 'Address already in use' | tail -n 1 | sed -E 's/^[A-Z][a-z]{2} [0-9]+ [0-9:]+ //'ss -tlnp 'sport = :80' | tail -n 1 | grep -o 'users:.*'pkill -f 'http.server 80'sleep 1systemctl reset-failed nginxsystemctl start nginx && echo "nginx: $(systemctl is-active nginx)"Job for nginx.service failed because the control process exited with error code.server nginx[17865]: nginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)users:(("python3",pid=17858,fd=3))nginx: activebind() to 0.0.0.0:80 failed (98: Address already in use): برنامهی دیگری (اینجا پایتون؛ در دنیای واقعی معمولاً Apache که از قبل نصب بوده) پورت را گرفته. ss -tlnp اسم پروسه را نشان داد. راهحل: برنامهی دیگر را متوقف یا روی پورت دیگری ببر (sudo systemctl disable --now apache2).
۲) nginx -t بدون sudo
Section titled “۲) nginx -t بدون sudo”su - ali -c 'nginx -t' 2>&12026/10/04 12:42:52 [warn] 17889#17889: the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1nginx: the configuration file /etc/nginx/nginx.conf syntax is ok2026/10/04 12:42:52 [emerg] 17889#17889: open() "/run/nginx.pid" failed (13: Permission denied)nginx: configuration file /etc/nginx/nginx.conf test failedکاربر معمولی به لاگ و فایل PID دسترسی ندارد و آزمایش شکست میخورد؛ این خطای تنظیمات نیست. راهحل: sudo nginx -t.
۳) restart بهجای reload
Section titled “۳) restart بهجای reload”مثال ۴: با تنظیم خراب، restart سایت را پایین میآورد. راهحل: sudo nginx -t && sudo systemctl reload nginx.
۴) حذف و نصب دوباره بهجای خواندن خطا
Section titled “۴) حذف و نصب دوباره بهجای خواندن خطا”مثال ۱ و ۲: apt خطا داد ولی بستهها نصب بودند. حذف و نصب دوباره همان خطا را تکرار میکرد. راهحل: systemctl status، journalctl -u nginx و nginx -t؛ بعد اصلاح و dpkg --configure -a.
۵) فراموش کردن فایروال
Section titled “۵) فراموش کردن فایروال”روی سرور، Nginx بالاست و curl localhost جواب میدهد، ولی از مرورگر خودت صفحه باز نمیشود. راهحل: sudo ufw status و sudo ufw allow 'Nginx Full' (و فایروال پنل ابریات، اگر داری).
تمرین اصلی درس: Nginx را نصب کن، صفحهی پیشفرض را با curl ببین، بعد index.html خودت را در /var/www/html بگذار و ثابت کن صفحه عوض شده. در پایان مطمئن شو سرویس enabled است (یعنی بعد از ریبوت هم بالا میآید).
دیدن جواب
echo "--- قبل:"curl -s http://localhost/ | grep -o '<title>.*</title>'echo '<!doctype html><title>My first site</title><h1>Hello, Nginx!</h1>' > /var/www/html/index.htmlecho "--- بعد:"curl -s http://localhost/ | grep -o '<title>.*</title>'systemctl is-enabled nginxrm /var/www/html/index.html--- قبل:<title>Welcome to nginx!</title>--- بعد:<title>My first site</title>enabledروی سرور خودت: sudo apt install nginx، بعد curl http://localhost یا آدرس IP سرور در مرورگر، و echo '...' | sudo tee /var/www/html/index.html. چون index.html در فهرست index قبل از index.nginx-debian.html آمده، Nginx همان را نشان داد. لازم نیست Nginx را reload کنی؛ فایلهای سایت با هر درخواست از دیسک خوانده میشوند (فقط تغییر تنظیمات reload میخواهد).
با داکر دو Nginx همزمان اجرا کن: یکی با نسخهی nginx:alpine روی پورت ۸۰۹۲ و یکی با سایت خودت (bind mount) روی پورت ۸۰۹۳. با docker ps هر دو را ببین، با curl به هر دو درخواست بفرست، و با docker logs ثابت کن هر کدام لاگ خودش را دارد. در پایان هر دو را پاک کن.
دیدن جواب
mkdir -p mysite && echo '<h1>my site on 8093</h1>' > mysite/index.htmldocker run -d --name lx-ng-a -p 8092:80 nginx:alpine > /dev/nulldocker run -d --name lx-ng-b -p 8093:80 -v "$PWD/mysite:/usr/share/nginx/html:ro" nginx:alpine > /dev/nullsleep 1docker ps --filter name=lx-ng- --format '{{.Names}} {{.Ports}}' | sed 's/, \[::\][^ ]*//' | sortcurl -s http://localhost:8092/ | grep -o '<title>.*</title>'curl -s http://localhost:8093/curl -s -o /dev/null http://localhost:8093/missing.htmlecho "--- لاگ lx-ng-a:"docker logs lx-ng-a 2>/dev/null | grep -c 'GET /'echo "--- لاگ lx-ng-b:"docker logs lx-ng-b 2>/dev/null | grep 'GET /' | awk '{print $6, $7, $9}'docker rm -f lx-ng-a lx-ng-b > /dev/nulllx-ng-a 0.0.0.0:8092->80/tcplx-ng-b 0.0.0.0:8093->80/tcp<title>Welcome to nginx!</title><h1>my site on 8093</h1>--- لاگ lx-ng-a:1--- لاگ lx-ng-b:"GET / 200"GET /missing.html 404هر کانتینر یک Nginx کاملاً جداست: پورت جدا، فایلهای جدا، لاگ جدا. در لاگ lx-ng-b درخواست موفق (۲۰۰) و درخواست فایل ناموجود (۴۰۴) را میبینی. docker logs فقط stdout (لاگ دسترسی) را به grep داد چون stderr را با 2>/dev/null دور ریختیم.
یک اسکریپت کوچک safe-reload.sh بنویس که: ۱) nginx -t بزند و اگر شکست خورد، خطا را نشان دهد و با کد ۱ خارج شود (بدون reload)؛ ۲) اگر موفق بود reload کند؛ ۳) بعد با curl بررسی کند سایت جواب ۲۰۰ میدهد. یک بار با تنظیمات سالم و یک بار با یک فایل خراب در conf.d اجرایش کن و نشان بده سایت در هر دو حالت بالا ماند.
دیدن جواب
cat > /usr/local/bin/safe-reload.sh <<'EOF'#!/usr/bin/env bash# safe-reload.sh: test nginx config, reload only if valid, then check the siteset -euo pipefailurl=${1:-http://localhost/}
if ! out=$(nginx -t 2>&1); then echo "config test FAILED, not reloading:" >&2 echo "$out" | sed 's/^/ /' >&2 exit 1fisystemctl reload nginxsleep 1code=$(curl -s -o /dev/null -w '%{http_code}' "$url")echo "reloaded; $url -> HTTP $code"[[ $code == 200 ]]EOFchmod +x /usr/local/bin/safe-reload.shecho "=== تنظیمات سالم:"safe-reload.sh; echo "کد خروج: $?"echo "=== تنظیمات خراب:"printf 'server { listen 8090 }\n' > /etc/nginx/conf.d/lx-bad.confsafe-reload.sh; echo "کد خروج: $?"echo "سایت: $(curl -s -o /dev/null -w '%{http_code}' http://localhost/)"rm /etc/nginx/conf.d/lx-bad.conf /usr/local/bin/safe-reload.sh=== تنظیمات سالم:reloaded; http://localhost/ -> HTTP 200کد خروج: 0=== تنظیمات خراب:config test FAILED, not reloading: 2026/10/04 12:42:53 [emerg] 17913#17913: unexpected "}" in /etc/nginx/conf.d/lx-bad.conf:1 nginx: configuration file /etc/nginx/nginx.conf test failedکد خروج: 1سایت: 200if ! out=$(nginx -t 2>&1) هم خروجی را نگه میدارد و هم شکست را بررسی میکند (درس مدیریت خطا). با فایل خراب، اسکریپت پیام دقیق Nginx را نشان داد و reload نکرد؛ سایت با همان تنظیمات قبلی بالا ماند.
آزمونک
Section titled “آزمونک”تنظیمات Nginx را عوض کردهای و نمیدانی درست است یا نه. امنترین کار؟
اگر nginx -t شکست بخورد، reload اجرا نمیشود؛ و حتی اگر reload شکست بخورد، Nginx با تنظیمات قبلی ادامه میدهد.
apt install nginx با «Errors were encountered while processing: nginx» تمام شد. اولین کار؟
اغلب بسته نصب شده و فقط شروع سرویس شکست خورده است.
فرق systemctl disable nginx و systemctl stop nginx؟
enable --now و disable --now هر دو کار را با هم میکنند.
با یک فایل تنظیمات خراب، کدام دستور سایت را از دسترس خارج میکند؟
restart خاموش میکند و با تنظیم خراب دوباره بالا نمیآید؛ reload رد میشود و قبلی میماند.
nginx شروع نمیشود و در journalctl میبینی bind() to 0.0.0.0:80 failed (98: Address already in use). یعنی چه؟
یک پورت را فقط یک برنامه میتواند بگیرد.
در docker run -d -p 8080:80 nginx:alpine، عدد ۸۰۸۰ چیست؟
شکل: -p میزبان:کانتینر.
systemctl reload nginx در عمل چه میکند؟
ExecReload در فایل سرویس همین را تعریف کرده است.
جمعبندی
Section titled “جمعبندی”- نصب روی سرور:
sudo apt install nginx؛ سرویسenabledو شروع میشود و سایت پیشفرض در/var/www/htmlاست. نسخهی مخزن را باapt-cache policy nginxببین. - کنترل:
systemctl status|start|stop|enable|disable nginx؛is-activeوis-enabledبرای اسکریپت. - بعد از تغییر تنظیمات:
sudo nginx -t && sudo systemctl reload nginx.reloadبدون قطع است و با تنظیم خراب قبلی را نگه میدارد؛restartبا تنظیم خراب سایت را پایین میآورد. - عیبیابی:
systemctl status nginx←journalctl -u nginx←nginx -t. خطاهای رایج: پورت گرفتهشده (Address already in use، باss -tlnp)، IPv6 نبودن (Address family not supported)، اجرای بدونsudo. بعد از اصلاح:dpkg --configure -a. - فایروال:
sudo ufw allow 'Nginx Full'(و SSH را فراموش نکن). - داکر:
docker run -d -p 8080:80 nginx:alpine؛ سایت در/usr/share/nginx/htmlبا-v ...:ro؛ لاگها درdocker logs؛ داخل کانتینرnginx -s reload.
| دستور | کاری که میکند |
|---|---|
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:alpine | Nginx در داکر |
docker run -d -p 8091:80 -v "$PWD/site:/usr/share/nginx/html:ro" nginx:alpine | سرو کردن پوشهی خودت |
docker exec CONTAINER nginx -s reload | reload داخل کانتینر |