WIUNIX ACADEMY
آموزش نصب وردپرس با Nginx و کش FastCGI در اوبونتو و دبیان
وردپرس را با PHP-FPM، MariaDB و HTTPS نصب کنید؛ سپس فقط صفحات عمومیِ مشخص را کش کنید و جداسازی نشست کاربران و محتوای رمزدار را بسنجید.
محیطت را انتخاب کنآموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
آموزش متناسب با مقادیر تو
تنظیمات این آموزش
مقادیر نمونه را برای محیط خودت تنظیم کن؛ متن و دستورهای مرتبط با هم تغییر میکنند. رمز، کلید خصوصی و توکن وارد نکن. مقادیر فقط در همین زبانه نگهداری میشوند و به سرور یا لینک اشتراکگذاری فرستاده نمیشوند. پیش از اجرا، DNS، گواهیها و سیاست شبکهٔ واقعی را بررسی کن.
ویرایش 4 مقدار این آموزش
از اینجا شروع کن
در پایان چه چیزی خواهی داشت؟
یک سایت وردپرس با HTTPS و هویت PHP اختصاصی داشته باشید و کش محدود عمومی را از راه بدنهٔ واقعی پاسخ و جداسازی کاربران بسنجید.
سیستمعاملها و نسخههای پوششدادهشده
بازبینی ۲۰۲۶-۱۰-۲۰: نصب واقعی WordPress 7.1.3 با PHP-FPM 8.3.6، بستهٔ اوبونتو 8.3.6-0ubuntu0.24.04.12، MariaDB 10.11.14 و Nginx 1.24.0 در فضای شبکهٔ جدا روی Ubuntu 24.04.4 amd64 با مسیر آزمایشی و بستههای رسمی استخراجشده بررسی شد. جداسازی بدنه و نشست و رمز نوشته، هدرهای خصوصی، شکست، بیاعتبارسازی و بازگشت کش موفق بودند. این آزمون نصب کامل APT/systemd، ACME و فایروال عمومی، همهٔ سیستمعاملها، بازیابی پشتیبان یا WooCommerce نیست. مسیرهای محیطی همچنان مبتنی بر مستنداتاند و تصاویر DEMO نمایشی هستند.
قبل از شروع
- سرور تازهٔ اوبونتو یا دبیان با systemd و sudo و SSH موجود؛ حداقل ۲ گیگابایت RAM و ۱۰ گیگابایت فضای آزاد برای آزمایش کوچک تکسایتی؛ ظرفیت تولید جدا محاسبه شود.
- دامنهٔ تحت اختیار، A و AAAA درست، دسترسی ۸۰ و ۴۴۳، حساب و ایمیل ACME مجاز و IP عمومی سیستم مدیریت.
- کلاینت Bash/curl و حسابهای staging با فایل کوکی خصوصی؛ این مسیر سایت یا دیتابیس موجود، CDN، پراکسی یا شنوندهٔ عمومی FPM را فرض نمیکند.
- PHP 8.5 از مخزن همین انتشار؛ سوکت اختصاصی در مرحلهٔ pool ساخته میشود.
قدم بعدی
بررسی سرور تازه و DNS
این مسیر برای نصب تازهٔ یک سایت است. دامنهٔ نمونه، ایمیل و IP مجاز مدیر را همهجا با مقادیر واقعی عوض کنید؛ اگر با IPv6 مدیریت میکنید، همان IP دقیق نیز مجاز شود. رکوردهای A و AAAA باید به این سرور برسند. در فایروال موجود دسترسی ۸۰ و ۴۴۳ را با حفظ SSH فراهم کنید. تنظیم سایت یا دیتابیس دیگری را بازنویسی و فایروال تازه را بدون بررسی فعال نکنید. حضور CDN یا پراکسی به طراحی جداگانهٔ اعتماد نیاز دارد. تا پایان نصب، محدودیت IP را نگه دارید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
cat /etc/os-release
uname -m
sudo ss -lntup
sudo nginx -T 2>/dev/null | head -80
getent ahosts blog.example.com
سیستمعامل و DNS درستاند و مسیرها و پورتها با نصب دیگری تداخل ندارند.
قدم بعدی
نصب بستههای رسمی توزیع
بستهها از مخزن امضاشدهٔ همان انتشار نصب میشوند؛ مخزن نسخهٔ دیگر یا PPA بررسینشده را جایگزین نکنید. PHP در اوبونتو ۲۶٫۱۰ و ۲۶٫۰۴ برابر ۸٫۵، در ۲۴٫۰۴ برابر ۸٫۳، در دبیان ۱۳ برابر ۸٫۴ و در دبیان ۱۲ برابر ۸٫۲ است. pool اختصاصی، سوکت ثابت این آموزش را میسازد و نام سوکت پیشفرض حدس زده نمیشود. نصب بسته ممکن است سرویس را روشن کند؛ هنوز پوشهٔ وردپرس وجود ندارد. پورت دیتابیس باید فقط محلی یا غیرفعال باشد.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo apt-get update
sudo apt-get install -y nginx mariadb-server php8.5-fpm php8.5-cli php8.5-mysql php8.5-curl php8.5-gd php8.5-mbstring php8.5-xml php8.5-zip php8.5-intl curl ca-certificates tar rsync openssl nano certbot
php8.5 -v
mariadb --version
nginx -v
sudo systemctl enable --now mariadb php8.5-fpm nginx
sudo ss -lntp 'sport = :3306'
)
APT بدون خطای امضا یا وابستگی تمام میشود؛ نسخهها را ثبت کنید. شنوندهٔ عمومی ۳۳۰۶ وجود ندارد.
ورود به کنسول محلی دیتابیس
در نصب تازه، ورود مدیر محلی معمولاً با احراز هویت سوکت یونیکس انجام میشود. تاریخچهٔ SQL را غیرفعال کنید و رمز واقعی را در آرگومان پوسته ننویسید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo env MYSQL_HISTFILE=/dev/null mariadb
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
ساخت کاربر محدود به دیتابیس سایت
در کنسول، رمز تصادفی اختصاصی ۶۴ نویسهای hexadecimal از مدیر رمز جایگزین کنید؛ فقط 0–9 و a–f تا در رشتهٔ SQL و PHP نیاز به escape نداشته باشد. کاربر فقط مجوزهای لازم برای جدولهای همین وردپرس دارد؛ مدیریت سراسری، ورود راه دور و GRANT OPTION ندارد. GRANT بلافاصله اعمال میشود و FLUSH PRIVILEGES لازم نیست. رمز را برای فایل تنظیمات نگه دارید. اگر نام دیتابیس یا کاربر از قبل وجود دارد، ادامه ندهید.
کنسول مدیر MariaDB که در پنل قبل باز شد؛ نه Bash.
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_site'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_LONG_RANDOM_PASSWORD';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, INDEX
ON wordpress.* TO 'wp_site'@'localhost';
SHOW GRANTS FOR 'wp_site'@'localhost';
EXIT;
SHOW GRANTS دسترسی همین دیتابیس را نشان میدهد و مجوز مدیریت سراسری ندارد.
قدم بعدی
بررسی هویت و دسترسی شبکهٔ دیتابیس
به پوسته برگردید و رمز را فقط در prompt تعاملی وارد کنید. اگر ۳۳۰۶ عمومی است، ابتدا bind و سیاست شبکهٔ MariaDB را اصلاح کنید؛ سایت به دیتابیس عمومی احتیاج ندارد.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
mariadb -u wp_site -p wordpress -e 'SELECT DATABASE(), CURRENT_USER();'
sudo mariadb -e 'SELECT @@bind_address;'
sudo ss -lntp 'sport = :3306'
دیتابیس wordpress، هویت wp_site@localhost و شنونده محلی است.
قدم بعدی
دریافت و کنترل فایلهای وردپرس
کد PHP آرشیو مستقل از معماری است. تا HTTPS و هر دو checksum تأیید نشدهاند، استخراج و نصب انجام نمیشود. SHA1 از نشانی رسمی انتشار آمده و SHA256 از همان آرشیو تأییدشده در این بازبینی محاسبه شده؛ SHA256 را امضای ناشر معرفی نمیکنیم. این کنترلها ناشر آلوده را پوشش نمیدهند. برای استفادهٔ بعدی، انتشار جاری را دوباره بررسی کنید. کد متعلق به root است و فقط uploads برای هویت PHP قابلنوشتن خواهد بود.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
umask 077
work=$(mktemp -d)
cd "$work"
curl --proto '=https' --proto-redir '=https' -fL --connect-timeout 10 --max-time 180 -o wordpress-7.1.3.tar.gz https://wordpress.org/wordpress-7.1.3.tar.gz
curl --proto '=https' --proto-redir '=https' -fL --connect-timeout 10 --max-time 60 -o wordpress.sha1 https://wordpress.org/wordpress-7.1.3.tar.gz.sha1
[ "$(tr -d '\r\n ' < wordpress.sha1)" = 491a78c7676b15dffcc69130c6054b8f49228a91 ]
printf '%s %s\n' 491a78c7676b15dffcc69130c6054b8f49228a91 wordpress-7.1.3.tar.gz | sha1sum --check --strict -
printf '%s %s\n' d2a09acb6a15e3b9c471d72557753c266d6f41a79ed19bfe04cbfe49e283b2a5 wordpress-7.1.3.tar.gz | sha256sum --check --strict -
tar -xzf wordpress-7.1.3.tar.gz
sudo test ! -e /var/www/wordpress
sudo adduser --system --no-create-home --group wp-php
sudo install -d -o root -g root -m 0755 /var/www/wordpress
sudo rsync -a --chown=root:root wordpress/ /var/www/wordpress/
sudo find /var/www/wordpress -type d -exec chmod 0755 {} +
sudo find /var/www/wordpress -type f -exec chmod 0644 {} +
sudo install -d -o wp-php -g www-data -m 0755 /var/www/wordpress/wp-content/uploads
printf 'Retained verified download: %s\n' "$work"
)
هر دو کنترل OK میدهند، مقصد تازه ایجاد و آرشیو تأییدشده حفظ میشود.
بازکردن pool اختصاصی PHP
در این آزمایش، وجود pool پیشفرض تداخلی ندارد؛ سایت از سوکت آن استفاده نمیکند. pool سایت دیگری را غیرفعال نکنید. متن پنل بعدی را در nano با Ctrl+O، Enter و Ctrl+X ذخیره کنید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo nano /etc/php/8.5/fpm/pool.d/wordpress.conf
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
اجرای PHP با هویت اختصاصی
مسیر فایل باید متعلق به نسخهٔ انتخابشده باشد. نام سوکت ثابت است، اما مسیر و سرویس نسخهدار با سیستمعامل تغییر میکند. پنج worker و ۱۲۸ مگابایت نقطهٔ شروع آزمایش کوچکاند، نه تضمین ظرفیت تولید.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
[wordpress]
user = wp-php
group = wp-php
listen = /run/php/wordpress.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = ondemand
pm.max_children = 5
pm.process_idle_timeout = 10s
pm.max_requests = 500
chdir = /var/www/wordpress
security.limit_extensions = .php
php_admin_value[upload_max_filesize] = 16M
php_admin_value[post_max_size] = 16M
php_admin_value[memory_limit] = 128M
php_admin_flag[display_errors] = off
php_admin_flag[log_errors] = on
pool با wp-php اجرا میشود و سوکت ۰۶۶۰ در اختیار www-data است.
قدم بعدی
اعتبارسنجی PHP پیش از restart
restart برای مدتی کوتاه همهٔ poolهای این نسخه را قطع میکند. پیش از آن، آزمون تنظیمات باید موفق شود.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo php-fpm8.5 -t
sudo systemctl restart php8.5-fpm
systemctl is-active php8.5-fpm
sudo stat -c '%U:%G %a %n' /run/php/wordpress.sock
)
آزمون موفق است، سرویس فعال و سوکت www-data:www-data با مجوز ۶۶۰ است.
تولید مقادیر تصادفی احراز هویت
این فرمان خصوصی اجرا شود؛ خروجی در تصویر، گزارش یا Git قرار نگیرد. برای هر یک از هشت جایگاه بعدی، یک مقدار متفاوت بردارید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
for n in $(seq 1 8); do openssl rand -hex 48; done
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
ساخت فایل محافظتشدهٔ تنظیمات
این مرحله فقط برای نصب تازه است؛ guard فایل موجود را نمیپذیرد. روی سایت فعال تکرار نکنید. پنل بعدی محتوای فایل است و فرمان پوسته نیست.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo test ! -e /var/www/wordpress/wp-config.php
sudo install -o root -g wp-php -m 0640 /dev/null /var/www/wordpress/wp-config.php
sudo nano /var/www/wordpress/wp-config.php
)
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
تنظیم اتصال وردپرس به دیتابیس
همهٔ جایگاهها و دو مقدار دامنه را عوض کنید. پیشوند جدول کنترل امنیتی نیست. TLS در همین Nginx پایان مییابد؛ به هدر دلخواه کاربر برای تشخیص HTTPS اعتماد نکنید. ویرایشگر کد پیشخوان خاموش است. کدهای متعلق به root به بهروزرسانی منظم مدیریتی نیاز دارند؛ برای رفع پیام بهروزرسانی، کل درخت را قابلنوشتن نکنید.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
<?php
define( 'DB_NAME', 'wordpress' );
define( 'DB_USER', 'wp_site' );
define( 'DB_PASSWORD', 'REPLACE_WITH_THE_DATABASE_PASSWORD' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );
// Replace every placeholder with a DIFFERENT local random value.
define( 'AUTH_KEY', 'REPLACE_1' );
define( 'SECURE_AUTH_KEY', 'REPLACE_2' );
define( 'LOGGED_IN_KEY', 'REPLACE_3' );
define( 'NONCE_KEY', 'REPLACE_4' );
define( 'AUTH_SALT', 'REPLACE_5' );
define( 'SECURE_AUTH_SALT', 'REPLACE_6' );
define( 'LOGGED_IN_SALT', 'REPLACE_7' );
define( 'NONCE_SALT', 'REPLACE_8' );
$table_prefix = 'wp_';
define( 'WP_HOME', 'https://blog.example.com' );
define( 'WP_SITEURL', 'https://blog.example.com' );
define( 'FORCE_SSL_ADMIN', true );
define( 'DISALLOW_FILE_EDIT', true );
define( 'WP_DEBUG', false );
if ( ! defined( 'ABSPATH' ) ) { define( 'ABSPATH', __DIR__ . '/' ); }
require_once ABSPATH . 'wp-settings.php';
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.