راهاندازی سایت با Nginx روی اوبونتو در عمل ده دقیقه طول میکشد و در تصور خیلیها یک بعدازظهر — تفاوت فقط در دانستن ترتیب درست قدمهاست: نصب وبسرور، پوشه و مجوزهای درست، بلوک server، گواهی رایگان SSL و چند بهینهسازی کوچک. همان ترتیب را میرویم، با خروجی واقعی هر دستور و علامتگذاری جاهای گیرافتادن.
پیشنیازها: قبل از شروع چه چیزی باید آماده باشد؟
- یک سرور اوبونتو (۲۲.۰۴، ۲۴.۰۴ یا ۲۶.۰۴) با دسترسی root؛
- دسترسی SSH با کاربری که sudo دارد (راهنمای کامل: اتصال به سرور با SSH)؛
- یک دامنه که رکورد A آن به آیپی سرور اشاره کند (نمیدانید چطور؟ آموزش رکوردهای DNS).
سومی را جدی بگیرید: بخش بزرگی از شکستهای گواهی SSL از همینجاست که دامنه هنوز به آیپی سرور resolve نمیشود. از خودِ سرور تست کنید — dig روی نصب استاندارد نیست و با sudo apt install bind9-dnsutils -y میآید:
dig +short example.ir
203.0.113.45
اگر خروجی خالی بود یا آیپی دیگری برگشت، وقت ادامه نرسیده: رکورد A را اصلاح کنید و به اندازهی TTL صبر کنید (در DNS مدیریتشدهی مهران هاست حداقل TTL شصت ثانیه است).
کدام نسخهی اوبونتو؟ تفاوتهایی که روی پیکربندی اثر میگذارند
نسخهای که انتخاب میکنید تعیین میکند چه Nginx و PHPای میگیرید و — نکتهای که خیلیها را غافلگیر میکند — با چه دستوری HTTP/2 را روشن میکنید:
| نسخهی اوبونتو | Nginx در مخزن | PHP پیشفرض | روش فعالکردن HTTP/2 | پایان پشتیبانی استاندارد |
|---|---|---|---|---|
| ۲۲.۰۴ LTS | 1.18.0 | 8.1 | listen 443 ssl http2; | می ۲۰۲۷ |
| ۲۴.۰۴ LTS | 1.24.0 | 8.3 | listen 443 ssl http2; | می ۲۰۲۹ |
| ۲۶.۰۴ LTS | 1.28.3 | 8.5 | دستور مستقل http2 on; | می ۲۰۳۱ |
ستون چهارم منبع یکی از رایجترین سردرگمیهاست: Nginx از 1.25.1 پارامتر http2 روی listen را منسوخ و http2 on; را جایگزین کرد. یعنی روی ۲۶.۰۴ نوشتن listen 443 ssl http2; هشدار میدهد، و برعکس http2 on; روی دو نسخهی قدیمیتر پیکربندی را میشکند.
دربارهی HTTP/3 نسخه تعیینکننده است. روی ۲۲.۰۴ و ۲۴.۰۴ در دسترس نیست: 1.18 و 1.24 قدیمیتر از 1.25.0 هستند که QUIC از آن شروع شد، و بستهی ۲۴.۰۴ با پرچم --with-http_v3_module ساخته نشده. اما روی ۲۶.۰۴ ورق برگشته: دبیان این پرچم را از 1.26.0-2 فعال کرده و بستهی 1.28.3 آن را دارد — پس برای h3 لازم نیست سراغ مخزن mainline خودِ nginx.org بروید. آپاستریم هنوز آن را آزمایشی میداند، پس بستهی خودتان را بررسی کنید؛ خروجی خالی یعنی در دسترس نیست:
nginx -V 2>&1 | grep -o with-http_v3_module
قدم ۱: نصب Nginx روی اوبونتو
sudo apt update && sudo apt install nginx -y
sudo systemctl enable --now nginx
خط دوم اطمینانخاطر است، نه ضرورت: بستهی اوبونتو خودش سرویس را استارت و برای بوت فعال میکند. اما در ایمیجهای ابری و کانتینرهایی که با policy-rc.d جلوی استارت خودکار را میگیرند، این اتفاق نمیافتد:
systemctl status nginx --no-pager | head -6
● 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 Mon 2026-09-07 10:12:41 UTC; 8s ago
Docs: man:nginx(8)
Main PID: 1841 (nginx)
Tasks: 3 (limit: 4613)
(روی ۲۲.۰۴ مسیر یونیت /lib/systemd/system/ است.) آیپی سرور را در مرورگر باز کنید: صفحهی «Welcome to nginx» یعنی وبسرور زنده است. اگر UFW فعال دارید:
sudo ufw allow 'Nginx Full'
Rule added
Rule added (v6)
sudo ufw status
Status: active
To Action From
-- ------ ----
OpenSSH ALLOW Anywhere
Nginx Full ALLOW Anywhere
OpenSSH (v6) ALLOW Anywhere (v6)
Nginx Full (v6) ALLOW Anywhere (v6)
پروفایل Nginx Full هر دو پورت 80 و 443 را باز میکند (Nginx HTTP فقط 80، Nginx HTTPS فقط 443). وسوسهی بستن پورت 80 بهنام «امنتر بودن» را کنار بگذارید؛ صدور گواهی رایگان به آن نیاز دارد.
قدم ۲: پوشهی سایت و مجوزهایی که بعداً دردسر نسازند
sudo mkdir -p /var/www/example.ir/html
sudo tee /var/www/example.ir/html/index.html >/dev/null <<'EOF'
<!doctype html>
<meta charset="utf-8">
<h1>سلام دنیا! 🚀</h1>
EOF
بهجای example.ir دامنهی خودتان را بگذارید. ساختار /var/www/domain/html اجباری نیست اما قرارداد خوبی است: پوشههای جانبی مثل لاگ اپ کنارِ html مینشینند، بیرون از وب.
حالا مالکیت و مجوزها — بخشی که خیلی از آموزشها با یک chmod 777 از رویش رد میشوند؛ مجوزی که دیگر پیکربندی نیست، دعوتنامه است. قاعدهی درست: کاربر وبسرور فقط بخوانَد و مالکِ فایلها کسِ دیگری باشد:
sudo chown -R $USER:www-data /var/www/example.ir
sudo find /var/www/example.ir -type d -exec chmod 750 {} \;
sudo find /var/www/example.ir -type f -exec chmod 640 {} \;
شما مالک هستید و مینویسید، و گروه www-data — کاربری که کارگرهای Nginx و PHP-FPM با آن اجرا میشوند — فقط میخواند. آموزشهایی که کل سایت را به www-data میسپارند همین محافظ را از بین میبرند: وقتی وبسرور مالک است، هر اسکریپت PHP — از جمله وبشل آپلودشده — کد سایت را بازنویسی میکند. اگر اپ به نوشتن نیاز دارد فقط همان پوشه را استثنا کنید:
sudo chown -R www-data:www-data /var/www/example.ir/html/wp-content/uploads
قدم ۳: تعریف سایت در Nginx با بلوک server
Nginx روی اوبونتو قرارداد دوپوشهای دارد: پیکربندی سایتها در /etc/nginx/sites-available/ نوشته و با یک لینک نمادین در /etc/nginx/sites-enabled/ فعال میشود — یعنی غیرفعالکردن موقت یک سایت فقط حذف یک لینک است. پس بلوک زیر را با sudo nano /etc/nginx/sites-available/example.ir بنویسید — همنامکردن فایل با دامنه قرارداد است، نه اجبار:
server {
listen 80;
listen [::]:80;
server_name example.ir www.example.ir;
root /var/www/example.ir/html;
index index.html index.php;
charset utf-8;
access_log /var/log/nginx/example.ir.access.log;
error_log /var/log/nginx/example.ir.error.log;
location / {
try_files $uri $uri/ =404;
}
}
سه نکته. خط listen [::]:80; همان پورت را روی IPv6 هم باز میکند؛ بدون آن بازدیدکنندهی IPv6 به بلوک شما نمیرسد: تا وقتی سایت default فعال است همان «Welcome to nginx» را میگیرد، وگرنه مرورگر بعد از مکثی به IPv4 برمیگردد — یعنی سایت اشتباه یا کندی، نه خطای واضح. server_name تعیین میکند بلوک به کدام نامها پاسخ دهد — برای همین هر دو صورتِ با و بدون www آمده. و charset utf-8; را جدی بگیرید: Nginx پیشفرض هیچ charset در هدر Content-Type اعلام نمیکند. صفحهی HTML با تگ meta charset سالم میماند، اما فایل .txt، خروجی مستقیم PHP یا پاسخ JSON بدون هدر صریح با حدسِ مرورگر خوانده میشود و فارسی بههم میریزد.
حالا با یک لینک نمادین فعالش کنید و پیکربندی را تست بگیرید:
sudo ln -s /etc/nginx/sites-available/example.ir /etc/nginx/sites-enabled/
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo systemctl reload nginx
nginx -t را به عادت تبدیل کنید؛ پیکربندی خراب را قبل از اعمال لو میدهد. بین reload و restart هم تفاوت هست: اولی پیکربندی جدید را بدون قطع اتصالهای در جریان به کارگرها میدهد، دومی سرویس را پایین و بالا میکند.
قدم ۴: HTTPS رایگان با Let's Encrypt
Let's Encrypt گواهی مورد اعتماد همهی مرورگرها را رایگان صادر میکند و ابزار رسمی خودکارسازیاش Certbot نام دارد. دو راه نصب دارید:
# راه ساده — از مخزن خود اوبونتو
sudo apt install certbot python3-certbot-nginx -y
# راه توصیهشدهی خود پروژه — نسخهی همیشه بهروز
# اگر قبلاً نسخهی apt را نصب کردهاید، طبق دستور رسمی Certbot اول حذفش کنید
sudo apt-get remove certbot -y
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/local/bin/certbot
تفاوت در تازگی نسخه است: بستهی اوبونتو ۲۴.۰۴ روی 2.9.0 قفل است، اما snap خودش بهروز میشود و تیم Certbot رسماً همان را توصیه میکند. آن خط حذف هم تشریفاتی نیست: با هر دو نصب، زمانبندِ apt جداگانه روی همان /etc/letsencrypt اجرا میشود و دو نسخهی Certbot سراغ یک گواهی میروند. سپس:
sudo certbot --nginx -d example.ir -d www.example.ir
Certbot ایمیل و پذیرش شرایط را میپرسد، بعد اعتبارسنجی HTTP-01 را اجرا میکند: فایلی موقت زیر /.well-known/acme-challenge/ میگذارد که سرورهای Let's Encrypt از پورت 80 میخوانند. سپس گواهی را نصب، بلوک را برای پورت 443 بازنویسی و ریدایرکت HTTP به HTTPS را ایجاد میکند:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.ir/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.ir/privkey.pem
This certificate expires on 2026-12-06.
These files will be updated when the certificate renews.
Deploying certificate
Successfully deployed certificate for example.ir to /etc/nginx/sites-enabled/example.ir
Successfully deployed certificate for www.example.ir to /etc/nginx/sites-enabled/example.ir
خطهای پایانی را بشمارید: بهازای هر نامی که با -d دادهاید باید یک خط deploy ببینید. اگر یکی کم بود، همان نام اعتبارسنجی نشده است.
Let's Encrypt سقفهای نرخی دارد که در آزمونوخطا زود پر میشوند: ۵۰ گواهی برای هر دامنهی ثبتشده در هفت روز، ۵ گواهی برای مجموعهی دقیقاً یکسانی از نامها در هفت روز، و ۵ شکست اعتبارسنجی برای هر نام در هر ساعت. پس هنگام آزمایش --dry-run بزنید که سهمیه را نمیسوزاند. وایلدکارت و اعتبارسنجی DNS در راهنمای کامل نصب گواهی رایگان SSL با Certbot آمده است.
کاری که Certbot برایتان انجام نمیدهد: روشنکردن HTTP/2
Certbot بلوک 443 را میسازد اما HTTP/2 را فعال نمیکند؛ باید دستی اضافه کنید، به شکلی که در جدول بالا دیدید: روی ۲۶.۰۴ خط http2 on; داخل بلوک 443، و روی نسخههای قدیمیتر پارامتر چسبیده به listen. بعد nginx -t، ریلود و تأیید:
curl -sI --http2 https://example.ir | head -1
HTTP/2 200
تمدید خودکار گواهی کجا بیصدا میشکند؟
گواهیهای Let's Encrypt تا ۱۰ فوریه ۲۰۲۷ نود روز اعتبار دارند و بعد از آن ۶۴ روز، و قرار است بدون دخالت شما تمدید شوند. Certbot هنگام نصب زمانبندی میسازد که روزی دو بار اجرا میشود و هر گواهی را با ماندن یکسوم عمرش تمدید میکند:
systemctl list-timers | grep certbot
Mon 2026-09-07 21:47:00 UTC 11h left Mon 2026-09-07 09:12:03 UTC 1h ago snap.certbot.renew.timer snap.certbot.renew.service
sudo certbot renew --dry-run
Congratulations, all simulated renewals succeeded:
/etc/letsencrypt/live/example.ir/fullchain.pem (success)
نام یونیت به روش نصب بستگی دارد: با snap زمانبند snap.certbot.renew.timer است و با apt نامش certbot.timer میشود. اگر هیچکدام را ندیدید، تمدید خودکار وجود ندارد.
حالا بخش مهمتر: چرا این سازوکار گاهی بیصدا میشکند. Let's Encrypt سرویس ایمیل هشدار انقضا را در ژوئن ۲۰۲۵ تعطیل کرد؛ تور ایمنی قدیمی دیگر نیست: اگر تمدید یک شب شکست بخورد هیچکس نمیگوید — تا وقتی بازدیدکنندهها هشدار قرمز مرورگر را ببینند.
دلایلش قابلپیشگیریاند: پورت 80 که بعداً روی فایروال بسته شده؛ رکورد A که با جابهجایی سرور عوض شده اما گواهی هنوز روی سرور قبلی تمدید میشود؛ یا بلوکی که دستی ویرایش شده و /.well-known/ را به ریدایرکتی سراسری فرستاده. پایش انقضا را به مانیتورینگ سرور اضافه کنید:
echo | openssl s_client -connect example.ir:443 -servername example.ir 2>/dev/null \
| openssl x509 -noout -enddate
notAfter=Dec 6 08:14:22 2026 GMT
قدم ۵ (اختیاری): PHP برای سایتهای داینامیک
تا اینجا سایت فقط فایل ایستا سرو میکند. برخلاف آپاچی، Nginx خودش PHP را اجرا نمیکند؛ درخواست را با FastCGI به سرویس جداگانهای به نام PHP-FPM میسپارد:
sudo apt install php8.3-fpm php8.3-mysql php8.3-mbstring php8.3-xml php8.3-curl -y
systemctl status php8.3-fpm --no-pager | head -3
● php8.3-fpm.service - The PHP 8.3 FastCGI Process Manager
Loaded: loaded (/usr/lib/systemd/system/php8.3-fpm.service; enabled)
Active: active (running)
نسخه را متناسب با اوبونتوی خودتان انتخاب کنید (جدول بالا) و داخل بلوک server این را اضافه کنید:
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
اسنیپت آمادهی snippets/fastcgi-php.conf بیارزش نیست: علاوه بر پارامترهای استاندارد FastCGI، خط try_files $fastcgi_script_name =404; را دارد که پیش از فرستادن درخواست به مفسر مطمئن میشود فایل PHP وجود دارد — همین یک خط خانوادهای از حملههای قدیمی را میبندد که با مسیرهای دستکاریشده اسکریپت دلخواه اجرا میکردند.
سه تنظیمی که بعداً به آنها برمیگردید
دو پیشفرض محافظهکارانهی Nginx با اپ واقعی خودشان را نشان میدهند: سقف یکمگابایتی بدنهی درخواست — آپلود بزرگتر با HTTP 413 رد میشود — و مهلت شصتثانیهای پاسخ FastCGI. اما این سقف دوم رقیب دارد. max_execution_time در PHP پیشفرض سی ثانیه است، ولی روی لینوکس فقط زمان اجرای خودِ اسکریپت را میشمارد؛ کوئری دیتابیس، فراخوانی API و خواندن از سوکت در آن حساب نمیشوند. یعنی حلقهی سنگینِ CPU اول به سقف PHP میخورد و HTTP 500 میدهد، اما کوئری کند — علت واقعی بیشتر ۵۰۴ها — تایمر PHP را جلو نمیبرد و بعد از شصت ثانیه 504 از Nginx میگیرید.
client_max_body_size 32m;
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 120s;
}
همین قاعده برای آپلود هم برقرار است: سقفش دو جا تعریف شده — client_max_body_size در Nginx و upload_max_filesize و post_max_size در /etc/php/8.3/fpm/php.ini — و سختگیرترینشان برنده است. برای مهلت ۱۲۰ ثانیه هم max_execution_time = 120 را همانجا بگذارید و PHP-FPM را جداگانه ریلود کنید؛ ریلود Nginx کافی نیست.
وردپرس و اپهای تکورودی: تنظیم try_files
اگر وردپرس یا هر فریمورک PHP مدرنی نصب کنید، احتمالاً صفحهی اصلی درست کار میکند اما هر لینک داخلی خطای 404 میدهد. پیکربندی قدم سوم میگفت «اگر فایل یا پوشهای با این آدرس نبود، 404 بده»، و آدرسی مثل /blog/nginx-setup/ فایلی روی دیسک ندارد؛ وردپرس باید آن را از index.php بسازد. آپاچی این کار را با .htaccess میکند که Nginx نمیخواندش:
location / {
try_files $uri $uri/ /index.php?$args;
}
ترجمهاش: اول دنبال فایلی با همین نام بگرد، بعد پوشهای با همین نام، و اگر نبود درخواست را با همان پارامترهای کوئری به index.php بسپار. برای لاراول همین الگو با ریشهی public جواب میدهد. برای نصب کامل، راهنمای نصب وردپرس روی سرور را دنبال کنید.
سه بهینهسازی کوچک با اثر بزرگ
فشردهسازی gzip
در /etc/nginx/nginx.conf معمولاً فعال است؛ مطمئن شوید این خطها از کامنت درآمدهاند:
gzip on;
gzip_vary on;
gzip_min_length 256;
gzip_types text/css application/javascript application/json image/svg+xml;
حجم فایلهای متنی بهشکل چشمگیری کم میشود — هم سرعت، هم ترافیک خروجی که جداگانه بر اساس گیگابایت حساب میشود. ماژول ngx_brotli معمولاً یک قدم جلوتر میرود. دو نکته: text/html لازم نیست چون Nginx همیشه آن را فشرده میکند، و gzip_vary on; هدر Vary: Accept-Encoding را میفرستد تا کشهای میانی دو نسخه را قاتی نکنند. تصویر و ویدیو را نگذارید؛ از قبل فشردهاند.
کش فایلهای استاتیک
location ~* \.(css|js|png|jpg|jpeg|gif|svg|webp|woff2)$ {
add_header Cache-Control "public, max-age=2592000, immutable";
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Strict-Transport-Security "max-age=300" always;
access_log off;
}
این بلوک به مرورگر میگوید سی روز سراغ سرور نیاید و immutable یک قدم جلوتر میرود: در این بازه حتی درخواست اعتبارسنجی هم نفرست. شرطش نسخهدار بودن آدرس فایلهاست؛ اگر همیشه همان style.css را بازنویسی میکنید، کاربران قدیمی تا یک ماه نسخهی کهنه را میبینند.
دو نکته دربارهی بلوک. expires 30d; را عمداً ننوشتیم: خودش هدر Cache-Control میسازد و با add_header پاسخ دو هدر متناقض میگیرد. و چهار هدر امنیتی عیناً تکرار شدهاند — به دلیلِ تلهای که چند خط پایینتر میآید.
برای بردن همین کش تا نزدیک کاربر، اگر نِیمسرورهای دامنه را به مهران هاست سپرده باشید میتوانید CDN مهران هاست را با یک کلید کنار همان رکورد A و بدون هزینهی جداگانه روشن کنید؛ نودهای لبه در ایران و اروپا فایل ایستا را نگه میدارند و سرور شما فقط بار دینامیک را میکشد.
هدرهای امنیتی
add_header X-Content-Type-Options nosniff;
add_header X-Frame-Options SAMEORIGIN;
add_header Referrer-Policy strict-origin-when-cross-origin;
add_header Strict-Transport-Security "max-age=300" always;
سهتای اول بهترتیب حدسزدن نوع محتوا، جاسازی سایت شما در فریمِ سایت دیگر و نشت اطلاعات هدر Referer را محدود میکنند. چهارمی — HSTS — به مرورگر میگوید این دامنه را فقط با HTTPS باز کن.
عیبیابی سریع: علامت، علت، اولین اقدام
پیش از هر حدسی sudo nginx -t بزنید و لاگ خطا را با sudo tail -f /var/log/nginx/error.log زنده تماشا کنید:
| علامت | علت محتمل | اولین اقدام |
|---|---|---|
| 502 Bad Gateway | PHP-FPM خاموش است یا مسیر سوکت با نسخهی PHP نمیخواند | systemctl status php8.3-fpm و مقایسهی fastcgi_pass با محتوای /run/php/ |
| 403 Forbidden | مالکیت یا مجوز پوشه، یا نبودن فایل ایندکس | بازبینی با ls -l و اطمینان از اینکه گروه www-data حق خواندن دارد |
| 404 روی همهی صفحههای داخلی | قاعدهی بازنویسی برای اپ تکورودی نوشته نشده | افزودن try_files با ارجاع نهایی به index.php در location / |
| فایل PHP دانلود میشود بهجای اجرا | بلوک location ~ \.php$ وجود ندارد | افزودن بلوک FastCGI و ریلود Nginx |
| صفحهی پیشفرض Nginx | لینک sites-enabled ساخته نشده یا server_name نمیخورد | ls -l /etc/nginx/sites-enabled/ و حذف فایل default |
| 413 Request Entity Too Large | سقف پیشفرض یکمگابایتی بدنهی درخواست | افزایش client_max_body_size و همزمان upload_max_filesize در php.ini |
| 504 Gateway Time-out | عبور از مهلت شصتثانیهای Nginx؛ اگر بهجایش خطای 500 میگیرید، به سقف سیثانیهای خود PHP خوردهاید | افزایش همزمان fastcgi_read_timeout و max_execution_time |
| Certbot در مرحلهی challenge شکست میخورد | پورت 80 بسته، رکورد A غلط، یا ریدایرکت سراسری | sudo ufw status و dig +short example.ir |
| هدرهای امنیتی روی بعضی مسیرها نیست | ارثبری add_header در بلوک داخلی قطع شده | تکرار هدرها در همان بلوک location |
خطای 502 آنقدر پرتکرار است که برایش راهنمای جداگانه نوشتهایم: ریشهیابی گامبهگام خطای 502 Bad Gateway.
تمام شد — سایت بالاست
الان یک وبسرور واقعی با HTTPS خودکار دارید: بلوک server تمیز، تمدید پایششده، PHP-FPM متصل، و فشردهسازی و کش روشن.
سه کار میماند برای همین روز اول: نصب unattended-upgrades برای وصلههای امنیتی خودکار؛ بردن پشتیبانِ /var/www و /etc/nginx و دیتابیس به بیرون از سرور با یک بازیابی آزمایشی — پشتیبانی که کنار خودِ داده نشسته پشتیبان نیست؛ و ثبت وضعیت فعلی با آزمون سرعت سایت مهران هاست. این ابزار از سرور پنل در خارج از ایران درخواست میفرستد، نه از شبکهی خانگی ایران؛ پس عدد را برای مقایسهی قبل و بعدِ خودتان بخوانید، نه تجربهی بازدیدکنندهی ایرانی.
قدم بعدی سفتکردن خودِ سرور است: کلید SSH بهجای رمز، بستن ورود مستقیم root و فایروالی که فقط پورتهای لازم را باز بگذارد — همه در چکلیست امنیت سرور لینوکس. اگر این مسیر برایتان زیاد است، روی هاست اشتراکی با cPanel یا دایرکتادمین این لایهها از پیش پیکربندی شدهاند.
سؤالات پرتکرار
برای راهاندازی سایت با Nginx روی اوبونتو چه پیشنیازهایی لازم است؟
سه چیز: یک سرور اوبونتو نسخهی ۲۲.۰۴ یا بالاتر، دسترسی SSH با کاربری که اختیار sudo دارد، و دامنهای که رکورد A آن به آیپی سرور اشاره کند. با دستور dig مطمئن شوید دامنه واقعاً به همان آیپی resolve میشود؛ وگرنه مرحلهی گرفتن گواهی SSL شکست میخورد. کل فرایند از نصب تا فعالشدن HTTPS، اگر رکورد A درست باشد، حدود ده دقیقه است.
تفاوت Nginx و آپاچی برای یک سایت ساده چیست؟
مهمترین تفاوت عملی این است که Nginx فایل htaccess را نمیخواند؛ هر قاعدهی بازنویسی آدرس باید در بلوک server نوشته و با ریلود اعمال شود. Nginx همچنین PHP را خودش اجرا نمیکند و درخواست را با FastCGI به PHP-FPM میسپارد، در حالی که آپاچی از قدیم میتوانست ماژول PHP را درون خودش اجرا کند — هرچند روی اوبونتوی امروزی MPM پیشفرضِ event با mod_php کار نمیکند و توصیهی رایج آنجا هم PHP-FPM است.
چرا Certbot خطا میدهد و گواهی SSL صادر نمیشود؟
سه علت بیشترین سهم را دارند: دامنه هنوز به آیپی سرور اشاره نمیکند، پورت 80 روی فایروال بسته است، یا ریدایرکتی سراسری مسیر اعتبارسنجی را منحرف کرده. اعتبارسنجی HTTP-01 لازم دارد سرورهای Let's Encrypt فایلی را زیر مسیر well-known از روی پورت 80 بخوانند. هر نام در هر ساعت فقط پنج شکست مجاز دارد، پس برای آزمایش از dry-run استفاده کنید.
گواهی Let's Encrypt چند وقت یکبار تمدید میشود و اگر تمدید نشود چه میشود؟
گواهیها تا فوریه ۲۰۲۷ نود روز اعتبار دارند و بعد از آن پیشفرض Let's Encrypt ۶۴ روز میشود، و Certbot با یک زمانبند خودکار هر گواهی را وقتی حدود یکسوم عمرش باقی مانده تمدید میکند. اگر این فرایند بشکند هیچ هشداری نمیگیرید، چون Let's Encrypt سرویس ایمیل اطلاعرسانی انقضا را در ژوئن ۲۰۲۵ تعطیل کرد. نتیجه، هشدار قرمز مرورگر برای همهی بازدیدکنندگان است.
بعد از نصب وردپرس روی Nginx چرا صفحههای داخلی خطای 404 میدهند؟
چون قاعدهی بازنویسی آدرس تعریف نشده است. وردپرس این قاعده را روی آپاچی از فایل htaccess میگیرد و Nginx آن را نمیخواند، پس آدرس مقالهای که روی دیسک فایلی ندارد به 404 میرسد. راهحل، نوشتن try_files با ارجاع نهایی به index.php در بلوک اصلی location و ریلود Nginx است. همین الگو برای لاراول و اپهای تکصفحهای هم پاسخ میدهد.