نصب وب سرور روی سرور خالی: از صفر تا اولین درخواست

ترتیب درست نصب وب سرور، PHP و دیتابیس روی سرور خالی، با تست هر لایه پیش از رفتن به لایه بعد و خطاهایی که واقعاً سر راه می‌خورید.

۶ دقیقه به‌روزرسانی ۲۶ مهر ۱۴۰۵

سرور را خریده‌اید، با SSH وارد شده‌اید، و حالا جلوی یک پرامپت خالی نشسته‌اید. curl localhost چیزی برنمی‌گرداند، systemctl status nginx می‌گوید unit پیدا نشد، و نمی‌دانید اول باید وب سرور را بالا بیاورید یا PHP را. اگر همین‌جا ترتیب را اشتباه بروید، دو ساعت بعد با خطای 502 Bad Gateway و لاگی می‌جنگید که هیچ‌چیز مفیدی در آن نیست.

ترتیب درست این است: وب سرور، بعد PHP، بعد دیتابیس. هر لایه را قبل از رفتن به لایه بعد تست کنید. این کار ده دقیقه وقت می‌گیرد و بعداً ساعت‌ها وقت شما را نجات می‌دهد.

قبل از نصب وب سرور، این سه چیز را چک کنید

اول اینکه واقعاً روی همان سروری هستید که فکر می‌کنید. hostnamectl و ip a را بزنید. اگر سرور ابری دارید، ممکن است IP خصوصی ببینید و IP عمومی جای دیگری باشد.

دوم، ساعت سیستم. اگر ساعت عقب یا جلو باشد، بعداً SSL و کوکی‌ها رفتار عجیب نشان می‌دهند:

timedatectl set-timezone Asia/Tehran
timedatectl status

سوم، فضای دیسک و رم. روی یک سرور با ۱ گیگابایت رم، MySQL با تنظیمات پیش‌فرض به‌راحتی OOM می‌شود. free -m و df -h را قبل از هر نصبی ببینید.

انتخاب استک: Nginx یا Apache؟

جواب کوتاه من: Nginx. برای بار همزمان بالا، مصرف رم کمتر، و سرو کردن فایل استاتیک، Nginx انتخاب بهتری است. Apache را وقتی انتخاب می‌کنم که برنامه‌ای دارید که به .htaccess وابسته است و نمی‌خواهید بازنویسی‌اش کنید.

معیارNginxApache
مدل پردازشرویدادمحور، چند پروسهپروسه/ترد به ازای هر اتصال
مصرف رم زیر بار سنگینکمتربیشتر
فایل استاتیکسریع‌ترقابل قبول
تنظیمات per-directoryندارد.htaccess

روی Debian 12 یا Ubuntu 22.04 به بعد:

apt update
apt install -y nginx
systemctl enable --now nginx
curl -I http://127.0.0.1

اگر HTTP/1.1 200 OK گرفتید، لایه اول تمام است. اگر نه، journalctl -u nginx -n 50 را ببینید. شایع‌ترین علت: پورت ۸۰ قبلاً توسط چیزی مثل Apache یا یک پنل اشغال شده. با ss -tlnp | grep :80 ببینید چه کسی گوش می‌دهد.

نصب PHP و اتصال آن به وب سرور

PHP را به‌صورت FPM نصب کنید، نه به‌صورت ماژول Apache. FPM یک پروسه جداگانه است، می‌توانید جداگانه ری‌استارتش کنید، و Nginx از طریق سوکت یونیکس با آن حرف می‌زند.

apt install -y php8.2-fpm php8.2-mysql php8.2-curl php8.2-mbstring
systemctl enable --now php8.2-fpm
ls -l /run/php/php8.2-fpm.sock

آن سوکت را در کانفیگ سایت Nginx بدهید:

server {
    listen 80;
    server_name example.com;
    root /var/www/example;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }
}

حالا یک فایل تست بگذارید و از بیرون سرور با curl -I http://example.com/info.php چک کنید. اگر 502 گرفتید، تقریباً همیشه یعنی مسیر سوکت در کانفیگ با مسیر واقعی نمی‌خواند یا نسخه PHP را ارتقا داده‌اید و نام سوکت عوض شده. این‌جا اشتباه می‌کنند: کانفیگ را با php7.4-fpm.sock می‌نویسند، بعد PHP را به ۸.۲ ارتقا می‌دهند و سایت با ۵۰۲ می‌خوابد، در حالی که خود PHP سالم است و systemctl status php8.2-fpm سبز نشان می‌دهد.

فایل تست را بعد از تأیید پاک کنید. یک phpinfo() باز روی اینترنت، نقشه راه کاملی از نسخه‌ها و ماژول‌های شما به هر کسی می‌دهد.

دیتابیس: MySQL یا MariaDB، و تنظیماتی که واقعاً مهم‌اند

MariaDB را نصب کنید مگر اینکه برنامه‌تان صراحتاً MySQL 8 بخواهد. سازگاری دستوری بالاست و روی سرورهای کم‌رم سبک‌تر است.

apt install -y mariadb-server
mysql_secure_installation

در mysql_secure_installation به همه سؤال‌ها بله بگویید، به‌خصوص حذف کاربر ناشناس و غیرفعال‌کردن ورود root از راه دور. جزئیات بیشتر در راهنمای امنیت MySQL و محدودکردن دسترسی‌ها آمده.

یک نکته که کمتر گفته می‌شود: bind-address در MariaDB به‌صورت پیش‌فرض 127.0.0.1 است و همین درست است. اگر آن را به 0.0.0.0 تغییر دادید تا از یک سرور دیگر وصل شوید، پورت ۳۳۰۶ را روی اینترنت باز کرده‌اید. در این حالت حداقل با ufw allow from 10.0.0.5 to any port 3306 دسترسی را به IP مشخص محدود کنید.

برای برنامه‌های PHP، کاربر دیتابیس را با localhost بسازید نه %:

CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'رمز-قوی';
GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;

حالا از داخل PHP با PDO وصل شوید و یک SELECT 1 بزنید. اگر این کار کرد، سه لایه آماده‌اند.

SSL و سخت‌سازی، پیش از آنکه سایت را عمومی کنید

Certbot را نصب کنید و گواهی بگیرید. شرط اول: دامنه باید از قبل به IP سرور اشاره کند و پورت ۸۰ از بیرون باز باشد. اگر DNS تازه تنظیم شده، ممکن است چند دقیقه تا چند ساعت طول بکشد؛ عجله نکنید و لاگ Certbot را بخوانید.

apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com

مراحل کامل و خطاهای رایج در نصب گواهینامه رایگان با Certbot توضیح داده شده. بعد از این، فایروال را ببندید: فقط ۲۲، ۸۰ و ۴۴۳ باز بماند. اگر پنل مدیریتی دارید، دسترسی‌اش را به IP خودتان محدود کنید.

تست هر لایه، به ترتیب

  1. curl -I http://127.0.0.1 روی خود سرور: وب سرور زنده است؟
  2. یک فایل PHP ساده که فقط echo "ok"; دارد: FPM وصل است؟
  3. یک اسکریپت PHP که به دیتابیس وصل می‌شود: اعتبارنامه‌ها درست‌اند؟
  4. curl -I https://example.com از بیرون: DNS، فایروال و SSL همه سالم‌اند؟

اگر جایی گیر کردید، به‌جای حدس زدن، لاگ همان لایه را بخوانید: /var/log/nginx/error.log، journalctl -u php8.2-fpm، /var/log/mysql/error.log. در نود درصد موارد جواب در همان چند خط آخر است.

یک تذکر دربارهٔ منابع: اگر روی یک VPS کوچک همه این‌ها را با هم بالا می‌آورید و بعد از نصب سایت کند می‌شود، احتمالاً مشکل تنظیمات نیست، کمبود رم است. با free -m و vmstat 1 ببینید swap چقدر درگیر می‌شود. اگر مرتب swap می‌زنید، یا رم را بالا ببرید یا سرویس‌های غیرضروری را خاموش کنید. برای بارهای جدی‌تر، مهاجرت به سرور ابری با منابع قابل ارتقا کم‌دردسرتر از تیون کردن یک ماشین اشباع‌شده است.

اگر ترجیح می‌دهید کل این مسیر را خودتان مدیریت نکنید و فقط کد را آپلود کنید، هاست لینوکس همین استک را آماده در اختیارتان می‌گذارد. ولی اگر هدف یادگیری یا کنترل کامل است، همین مسیر دستی ارزشش را دارد.

پرسش‌های پرتکرار

چرا بعد از نصب PHP سایت من خطای 502 Bad Gateway می‌دهد؟

در بیشتر موارد مسیر سوکت FPM در کانفیگ Nginx با مسیر واقعی روی دیسک یکی نیست. با ls /run/php/ نام دقیق سوکت را ببینید و همان را در fastcgi_pass بگذارید. علت دوم این است که سرویس PHP-FPM اصلاً بالا نیامده؛ systemctl status php8.2-fpm را چک کنید.

اگر هر دو درست بود، به /var/log/nginx/error.log نگاه کنید. پیام connect() to unix:... failed (13: Permission denied) یعنی مشکل دسترسی کاربر www-data به سوکت است، نه خود PHP.

آیا باید Apache را حذف کنم اگر Nginx نصب می‌کنم؟

اگر Apache روی پورت ۸۰ گوش می‌دهد، Nginx بالا نمی‌آید یا سایت به Apache می‌رود و شما فکر می‌کنید کانفیگ Nginx اثر ندارد. با ss -tlnp | grep :80 ببینید کدام پروسه پورت را گرفته. اگر به Apache نیازی ندارید، systemctl disable --now apache2 کافی است؛ حذف کامل لازم نیست.

کدام نسخه PHP را نصب کنم؟

نسخه‌ای که برنامه‌تان رسماً پشتیبانی می‌کند، نه جدیدترین نسخه موجود. اگر روی یک CMS کار می‌کنید، صفحه نیازمندی‌های همان نسخه را ببینید. نصب PHP 8.2 روی برنامه‌ای که برای 7.4 نوشته شده، خطاهای deprecated و گاهی خطای مرگبار می‌دهد.

نکته عملی: نسخه PHP را در نام سوکت هاردکد نکنید اگر بعداً ارتقا می‌دهید. یک symlink یا متغیر در کانفیگ داشته باشید تا ارتقا یک تغییر تک‌خطی باشد.

بعد از نصب، اولین کاری که باید بکنم چیست؟

فایروال را ببندید و فایل‌های تست را پاک کنید. یک info.php باقی‌مانده روی اینترنت، نسخه دقیق PHP، مسیرهای نصب و ماژول‌های فعال شما را به هر کسی نشان می‌دهد. بعد از آن، بکاپ خودکار دیتابیس را تنظیم کنید؛ نصب بدون بکاپ، نصب ناتمام است.

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

آیا این مطلب برایتان مفید بود؟