WIUNIX ACADEMY
آموزش نصب وردپرس با Nginx و کش FastCGI در اوبونتو و دبیان
وردپرس را با PHP-FPM، MariaDB و HTTPS نصب کنید؛ سپس فقط صفحات عمومیِ مشخص را کش کنید و جداسازی نشست کاربران و محتوای رمزدار را بسنجید.
محیطت را انتخاب کنآموزش متناسب با محیط تو
کجا اجرا میکنی؟
سیستمعامل و نسخه را انتخاب کن تا مراحل، دستورها و راهحلها برای همان محیط نمایش داده شوند.
از اینجا شروع کن
در پایان چه چیزی خواهی داشت؟
یک سایت وردپرس با 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';
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
کنترل نحو و مجوزها
این کنترلها محتوای خصوصی تنظیمات را چاپ نمیکنند.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo php8.5 -l /var/www/wordpress/wp-config.php
if sudo grep -q REPLACE_ /var/www/wordpress/wp-config.php; then
echo 'Replace all configuration placeholders first' >&2; exit 1
fi
sudo -u wp-php test -r /var/www/wordpress/wp-config.php
sudo -u wp-php test ! -w /var/www/wordpress/wp-config.php
sudo -u wp-php test -w /var/www/wordpress/wp-content/uploads
)
PHP تنظیمات را میخواند اما نمینویسد؛ uploads قابلنوشتن است و جایگاه خالی باقی نمانده.
آمادهسازی پوشه و سیاست کش
پوشه در اختیار worker است. تنظیم پیشفرض توزیع، conf.d را داخل http وارد میکند؛ آزمون کامل این فرض را بررسی میکند. map را داخل server نگذارید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo install -d -o www-data -g www-data -m 0700 /var/cache/nginx/wordpress
sudo nano /etc/nginx/conf.d/wordpress-cache.conf
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
کش فقط برای صفحات عمومیِ مشخص
تنها صفحهٔ نخست و sample-page مجازند. تمام مسیرهای دیگر، از جمله ورود و مدیریت، پیشنمایش، API، cron، خرید و حساب، خوراک، جستوجو و برگهٔ رمزدار خارج از فهرستاند. هر کوکی، Authorization، پارامتر، روش غیر از GET یا مسیر percent-encoded هم خواندن و هم نوشتن کش را متوقف میکند. کوکی ورود، رمز نوشته، دیدگاه و نشست ناشناختهٔ افزونه نیز پوشش داده میشود. پیش از خصوصی یا رمزدارکردن صفحه، آن را از فهرست بردارید و نسل کلید را عوض کنید. محتوای وابسته به مکان، دستگاه یا کاربر را بدون بررسی جداگانهٔ کلید و هدرها اضافه نکنید. حتی UTM عمداً bypass میشود؛ نادیدهگرفتن آن نیازمند بررسی برنامه است.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
# http context: included by the stock Debian/Ubuntu nginx.conf
fastcgi_cache_path /var/cache/nginx/wordpress levels=1:2 keys_zone=WORDPRESS:20m
max_size=512m inactive=10m use_temp_path=off;
map $request_method $wp_skip_method { default 1; GET 0; }
# Every cookie is private until separately assessed, including WordPress,
# wp-postpass, comment_author, WooCommerce and plugin session cookies.
map $http_cookie $wp_skip_cookie { default 1; "" 0; }
map $http_authorization $wp_skip_auth { default 1; "" 0; }
map $args $wp_skip_args { default 1; "" 0; }
# Opt in ONLY known public HTML URLs. Everything else stays dynamic.
map $request_uri $wp_skip_route {
default 1;
"/" 0;
"/sample-page/" 0;
}
# Defense in depth for the standard private/dynamic endpoints.
map $request_uri $wp_private_path {
default 0;
~*^/(wp-admin|wp-login\.php|wp-cron\.php|wp-json|xmlrpc\.php|cart|checkout|my-account|account)(/|\?|$) 1;
~*% 1;
}
سقف کش ۵۱۲ و ناحیهٔ کلید ۲۰ مگابایت تعریف شده؛ کش سایت هنوز خاموش است.
آمادهسازی HTTP فقط برای چالش
پورت ۸۰ باید برای مرجع صدور گواهی باز باشد. اگر گواهی از قبل مدیریت میشود، از همان روند مجاز و مسیر درست استفاده کنید و صدور موازی نسازید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo install -d -o root -g root -m 0755 /var/lib/letsencrypt/.well-known/acme-challenge
sudo nano /etc/nginx/sites-available/wordpress
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
نوشتن سایت موقت HTTP
دامنه را عوض کنید. در HTTP فقط چالش ACME ارائه میشود و وردپرس در دسترس عمومی نیست.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
server {
listen 80;
listen [::]:80;
server_name blog.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/lib/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
location / { return 404; }
}
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
فعالسازی و آزمون چالش
اگر لینک سایت از قبل وجود دارد، علت را بررسی کنید. reload فقط پس از اعتبارسنجی انجام میشود. پاسخ چالش را از بیرون سرور هم ببینید؛ دسترسی محلی برای اثبات دسترسی CA کافی نیست.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo test ! -e /etc/nginx/sites-enabled/wordpress
sudo ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/wordpress
sudo nginx -t
sudo systemctl reload nginx
printf 'acme-path-check\n' | sudo tee /var/lib/letsencrypt/.well-known/acme-challenge/academy-check >/dev/null
curl -fsS --connect-timeout 5 --max-time 15 http://blog.example.com/.well-known/acme-challenge/academy-check | grep -Fx acme-path-check
)
اعتبارسنجی موفق است و بدنه دقیقاً acme-path-check است.
قدم بعدی
دریافت TLS پیش از نصب وردپرس
ایمیل و دامنه را عوض کنید و پیش از agree-tos شرایط CA را بخوانید و بپذیرید. فرمان حساب و گواهی واقعی ایجاد میکند. چالش از HTTP موجود میگذرد. شکست صدور پیش از ویرایشگر متوقف میشود؛ پس از موفقیت پنل بعدی را جایگزین کنید. نصب را با استثنای خطای گواهی مرورگر یا curl -k ادامه ندهید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo certbot certonly --webroot -w /var/lib/letsencrypt -d blog.example.com --email YOUR_REAL_EMAIL --agree-tos
sudo test -s /etc/letsencrypt/live/blog.example.com/fullchain.pem
sudo test -s /etc/letsencrypt/live/blog.example.com/privkey.pem
sudo nano /etc/nginx/sites-available/wordpress
)
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
حفاظت از نصب با TLS و محدودیت IP
دامنه، مسیر گواهی و IP مدیر را عوض کنید و کش را خاموش نگه دارید. محدودیت سطح server همهٔ فایلهای ایستا و PHP را میپوشاند. اجرای PHP در uploads و دریافت تنظیمات و فایلهای مخفی ممنوع است. HTTP پس از چالش به دامنهٔ ثابت HTTPS میرود.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
server {
listen 80;
listen [::]:80;
server_name blog.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/lib/letsencrypt;
default_type text/plain;
try_files $uri =404;
}
location / { return 301 https://blog.example.com$request_uri; }
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name blog.example.com;
if ($host != blog.example.com) { return 444; }
ssl_certificate /etc/letsencrypt/live/blog.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blog.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
root /var/www/wordpress;
index index.php;
client_max_body_size 16m;
# Temporary installation gate. Replace with YOUR actual public admin IP.
allow 203.0.113.10;
deny all;
location / { try_files $uri $uri/ /index.php?$args; }
location ~* ^/wp-content/uploads/.*\.php(?:/|$) { return 403; }
location = /wp-config.php { deny all; }
location ~ /\. { deny all; }
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param HTTPS on;
fastcgi_pass unix:/run/php/wordpress.sock;
fastcgi_cache off;
fastcgi_cache_key "$scheme|$request_method|$host|$request_uri|wp-v1";
fastcgi_cache_methods GET;
fastcgi_cache_valid 200 60s;
fastcgi_cache_lock on;
fastcgi_cache_bypass $wp_skip_method $wp_skip_cookie $wp_skip_auth $wp_skip_args $wp_skip_route $wp_private_path;
fastcgi_no_cache $wp_skip_method $wp_skip_cookie $wp_skip_auth $wp_skip_args $wp_skip_route $wp_private_path;
add_header X-WP-Cache $upstream_cache_status always;
}
}
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
آزمون TLS و دسترسی نصبکننده
اعتبارسنجی و reload روی سرور است. اگر خروجی سرور مجاز نیست، curl HTTPS را از سیستم مجاز اجرا کنید. شما باید نصبکننده را با ۲۰۰ و مبدأ مستقلِ غیرمجاز باید ۴۰۳ ببیند. برای عبور آزمون مجوز عمومی ندهید.
ترمینال سرور، مدیر دارای sudo.
(
set -euo pipefail
sudo nginx -t
sudo systemctl reload nginx
sudo ss -lntp 'sport = :443'
)
گواهی معتبر با دامنه تطبیق دارد و نصبکننده فقط از IP تعیینشده باز است.
کنترل پاسخ ۲۰۰ نصبکننده از کلاینت مجاز
از سیستم مجاز اجرا کنید؛ کنترل گواهی روشن بماند. از شبکهٔ مستقل غیرمجاز همین بررسی را با انتظار ۴۰۳ تکرار کنید؛ آن پاسخ منفی مجوز ادامهٔ نصب از مبدأ غیرمجاز نیست.
سیستم مجاز، Bash دارای curl.
(
set -euo pipefail
work=$(mktemp -d)
code=$(curl -sS --connect-timeout 5 --max-time 20 -D "$work/installer.h" -o "$work/installer.html" -w '%{http_code}' https://blog.example.com/wp-admin/install.php)
[ "$code" = 200 ]
grep -F WordPress "$work/installer.html"
)
HTTPS معتبر، پاسخ دقیق ۲۰۰ و بدنهٔ واقعی نصبکننده.
قدم بعدی
تکمیل نصب پشت محدودیت IP
از سیستم مجاز، نشانی نصب را باز کنید. عنوان سایت، نام مدیر غیرپیشفرض، رمز قوی و ایمیل واقعی را بدهید؛ نصب را تمام کنید و پیشخوان را ببینید. اطلاعات ورود در شواهد ثبت نشود. در STAGING برگهٔ نمونهٔ موجود را ویرایش کنید، نه اینکه نامک تکراری بسازید؛ نامک sample-page و متن PUBLIC_CACHE_MARKER باشد. برگهٔ جداگانهٔ Home با متن PUBLIC_HOME_MARKER را در تنظیمات ← خواندن، صفحهٔ نخست ایستا انتخاب کنید. پیوند یکتا را «نام نوشته» بگذارید و ذخیره کنید. برگهٔ sample-page عمومی بماند؛ برگهٔ رمزدار جدا با نامک locked-test و متن LOCKED_CONTENT_MARKER بسازید. نام نمایشی دو حساب آزمایشی CACHE_USER_A و CACHE_USER_B باشد و نوار ابزار سایت در شناسنامهٔ هر دو روشن شود. هر حساب باید نام خودش و پنجرهٔ خصوصی هیچکدام را نشان دهد. آزمونهای بعدی بر همین تفاوت واقعی بدنه تکیه دارند.
نوار نشانی مرورگر سیستم مجاز؛ نه پوستهٔ سرور.
https://blog.example.com/wp-admin/install.php
پیشخوان و جدولها آمادهاند و برگههای عمومی و رمزدارِ جدا، با کش خاموش درست نمایش داده میشوند.
قدم بعدی
بررسی دیتابیس و بدنهٔ عمومی
curl از IP مجاز اجرا شود. عنوان واقعی سایت را جایگزین کنید. پاسخ ۲۰۰ و بدنهٔ منطبق لازم است؛ هدایت به نصب موفقیت نیست.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
code=$(curl -sS --connect-timeout 5 --max-time 20 -o /tmp/wp-installed-public.html -w '%{http_code}' https://blog.example.com/)
[ "$code" = 200 ]
grep -F 'YOUR_PUBLIC_SITE_TITLE' /tmp/wp-installed-public.html
sudo mariadb wordpress -e "SHOW TABLES LIKE 'wp_options';"
)
عنوان در صفحهٔ نخست است و wp_options وجود دارد.
نگهداری نقطهٔ بازگشت تنظیمات
نسخهٔ خصوصی root ساختار مسیرها را نگه میدارد و پیش از ویرایشگر هر دو فایل را مقایسه میکند. نشانی چاپشده را ثبت کنید؛ این پشتیبان تنظیمات است، نه دیتابیس و بارگذاریها.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo sh -eu <<'SAVE'
umask 077
install -d -m 0700 /root/academy-backups
backup=$(mktemp -d /root/academy-backups/wp-nginx-XXXXXXXX)
cp -a --parents /etc/nginx/sites-available/wordpress /etc/nginx/conf.d/wordpress-cache.conf "$backup/"
cmp /etc/nginx/sites-available/wordpress "$backup/etc/nginx/sites-available/wordpress"
cmp /etc/nginx/conf.d/wordpress-cache.conf "$backup/etc/nginx/conf.d/wordpress-cache.conf"
printf 'Verified pre-cache configuration: %s\n' "$backup"
SAVE
sudo nano /etc/nginx/sites-available/wordpress
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
فعالسازی کش عمومیِ بررسیشده
در location موجود PHP فقط خط خاموشبودن کش را عوض کنید. هر دو کنترل bypass و no-cache و محدودیت IP آزمایش باقی بمانند. رفتار پیشفرض Nginx برای Set-Cookie، کنترلهای خصوصی Cache-Control، Vary و X-Accel-Expires حفظ شود. برای گرفتن HIT هدرها را نادیده نگیرید و کوکی را پنهان نکنید. پاسخ عمومی ۲۰۰ در نبود زمان اعتبار بالادست، TTL شصتثانیهای دارد؛ هدر بالادست میتواند اولویت داشته باشد. افزونهٔ شخصیسازِ فاقد کوکی یا هدر درست با یک هدر کش امن نمیشود؛ چنین URLی را مجاز نکنید.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
# In the PHP location, replace ONLY the existing cache-off line:
fastcgi_cache WORDPRESS;
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
اعتبارسنجی پیش از reload
شکست آزمون مانع reload میشود. reload موفق اعتبار تنظیمات را نشان میدهد؛ حریم خصوصی را با بدنه بسنجید.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo nginx -t
sudo systemctl reload nginx
systemctl is-active nginx
)
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
آزمون مستقل MISS و HIT مهمان
در staging بلافاصله پس از نسل تازهٔ کلید و پیش از گرمشدن برگه اجرا کنید. انتظار MISS سپس HIT و بدنههای عمومی برابر است. اگر از قبل گرم شده، با پنل نگهداری نسل استفادهنشده بگذارید و یک بار تکرار کنید؛ فایل کش فعال را حذف نکنید. curl باید از مبدأ مجاز بیاید.
کلاینت مجاز staging، Bash/curl؛ فایل کوکی خصوصی و محلی همان سیستم است.
(
set -euo pipefail
umask 077
work=$(mktemp -d)
base=https://blog.example.com
for n in 1 2; do
code=$(curl -sS --connect-timeout 5 --max-time 20 -H 'Cookie:' -H 'Authorization:' -D "$work/$n.h" -o "$work/$n.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -i '^X-WP-Cache:' "$work/$n.h"
done
grep -Eiq '^X-WP-Cache: MISS[[:space:]]*$' "$work/1.h"
grep -Eiq '^X-WP-Cache: HIT[[:space:]]*$' "$work/2.h"
cmp "$work/1.html" "$work/2.html"
grep -F 'PUBLIC_CACHE_MARKER' "$work/2.html"
if grep -Fq 'CACHE_USER_A' "$work/2.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
printf 'Retained anonymous evidence: %s\n' "$work"
)
دو پاسخ ۲۰۰، ابتدا MISS سپس HIT و بدنهٔ عمومی برابر بدون نشانگر کاربر.
قدم بعدی
آزمون نشست واقعی و جداسازی کاربران
با ابزار نشست مورداعتماد خود، دو ورود واقعی staging را خصوصی در فایل کوکی با فرمت Netscape صادر کنید. آزمون در Bash/curl سیستم مجاز است و مسیر فایلها محلیِ همان کلاینت است. کوکی ورود ساختگی اثبات احراز هویت نیست. نوار ابزار و نام نمایشی باید شناخت هر حساب توسط وردپرس را نشان دهد؛ BYPASS تنها کافی نیست. بدنهها خصوصی بمانند. کوکیهای ساختگی رمز نوشته، سبد و افزونه فقط سیاست Nginx را میسنجند و آزمون ورود یا خرید واقعی نیستند.
سیستم مجاز، Bash/curl و فایل کوکی خصوصی نشستهای واقعی staging.
(
set -euo pipefail
umask 077
work=$(mktemp -d)
base=https://blog.example.com
# Use an EXISTING private Netscape-format jar exported from your staging login.
# It must be root/user readable only. Never paste cookies into source or logs.
jar=$HOME/wp-staging-user-a.cookies
[ -s "$jar" ]
chmod 0600 "$jar"
for n in 1 2; do
code=$(curl -sS --connect-timeout 5 --max-time 20 -b "$jar" -D "$work/a$n.h" -o "$work/a$n.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/a$n.h"
grep -F 'id="wpadminbar"' "$work/a$n.html"
grep -F 'CACHE_USER_A' "$work/a$n.html"
if grep -Fq 'CACHE_USER_B' "$work/a$n.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
done
code=$(curl -sS --connect-timeout 5 --max-time 20 -H 'Cookie:' -D "$work/public.h" -o "$work/public.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -F 'PUBLIC_CACHE_MARKER' "$work/public.html"
if grep -Fq 'CACHE_USER_A' "$work/public.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
for cookie in 'wp-postpass_demo=test' 'woocommerce_items_in_cart=1' 'plugin_session=test'; do
code=$(curl -sS --connect-timeout 5 --max-time 20 -b "$cookie" -D "$work/bypass.h" -o "$work/bypass.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/bypass.h"
done
jar_b=$HOME/wp-staging-user-b.cookies
[ -s "$jar_b" ]
chmod 0600 "$jar_b"
code=$(curl -sS --connect-timeout 5 --max-time 20 -b "$jar_b" -D "$work/b.h" -o "$work/b.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/b.h"
grep -F 'CACHE_USER_B' "$work/b.html"
if grep -Fq 'CACHE_USER_A' "$work/b.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
code=$(curl -sS --connect-timeout 5 --max-time 20 -H 'Cookie:' -D "$work/public-after-b.h" -o "$work/public.html" -w '%{http_code}' "$base/sample-page/")
[ "$code" = 200 ]
grep -F PUBLIC_CACHE_MARKER "$work/public.html"
if grep -Fq CACHE_USER_A "$work/public.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
if grep -Fq 'CACHE_USER_B' "$work/public.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
printf 'Private evidence retained at %s; inspect locally, do not publish cookies/bodies.\n' "$work"
)
حسابهای A و B با BYPASS فقط هویت خود را میبینند و پاسخ مهمان بعدی هیچکدام را ندارد.
قدم بعدی
کنترل پارامترها و مسیرهای پویا
پیشنمایش ممکن است به ورود هدایت شود. statusهای محدود رفتار ورود و دسترسی را میپذیرند، اما BYPASS لازم است و 5xx یا شکست ارتباط رد میشود. بدنه نیز باید متعلق به همان مسیر باشد. هر query string از جمله UTM بهجای حذف پنهانی، bypass میشود.
کلاینت مجاز staging، Bash/curl؛ فایل کوکی خصوصی و محلی همان سیستم است.
(
set -euo pipefail
work=$(mktemp -d)
n=0
for target in '/sample-page/?preview=true' '/sample-page/?utm_source=qa' '/wp-login.php' '/wp-json/'; do
n=$((n + 1))
code=$(curl -sS --connect-timeout 5 --max-time 20 -D "$work/$n.h" -o "$work/$n.body" -w '%{http_code}' "https://blog.example.com$target")
case "$code" in 200|301|302|401|403|404) ;; *) echo "Unexpected status $code" >&2; exit 1;; esac
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/$n.h"
printf '%s -> %s, BYPASS\n' "$target" "$code"
done
)
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
تفکیک کلید صفحات بازنویسیشده و روش درخواست
کلید شامل scheme، روش، دامنهٔ کنترلشده، URI اصلی و نسل است. بازنویسی پیوند یکتا نباید کلید همهٔ صفحات را index.php کند. فقط GET مجاز است؛ HEAD نیز عمداً bypass میشود تا پاسخِ بدون بدنه کلید GET را پر نکند. POST خالیِ مهمان به برگهٔ عمومی آزمایش اقدام فرم ندارد و باید bypass شود. Nginx برای POST از موتور کش عبور نمیکند؛ بنابراین هدر ممکن است بهجای BYPASS غایب باشد، اما پاسخ کششدهٔ HIT یا STALE مجاز نیست.
کلاینت مجاز staging، Bash/curl؛ فایل کوکی خصوصی و محلی همان سیستم است.
(
set -euo pipefail
work=$(mktemp -d)
code=$(curl -sS --connect-timeout 5 --max-time 20 -D "$work/home.h" -o "$work/home.html" -w '%{http_code}' https://blog.example.com/)
[ "$code" = 200 ]
grep -F PUBLIC_HOME_MARKER "$work/home.html"
if grep -Fq PUBLIC_CACHE_MARKER "$work/home.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
code=$(curl -sS --connect-timeout 5 --max-time 20 -X POST -d '' -D "$work/post.h" -o "$work/post.html" -w '%{http_code}' https://blog.example.com/sample-page/)
[ "$code" = 200 ]
if grep -Eiq '^X-WP-Cache: (HIT|STALE|UPDATING|REVALIDATED)[[:space:]]*$' "$work/post.h"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
grep -F PUBLIC_CACHE_MARKER "$work/post.html"
curl -sS --head --connect-timeout 5 --max-time 20 https://blog.example.com/sample-page/
)
کلید دو صفحه متفاوت است؛ POST بدنهٔ عمومی درست دارد و از کش نیست؛ HEAD بدون بدنه bypass میشود.
قدم بعدی
اثبات جداسازی محتوای رمزدار
برگهٔ locked-test در فهرست مجاز نیست. رمز آزمایشی آن را در مرورگر امن وارد و کوکی واقعی post-password را خصوصی صادر کنید. مهمان باید فرم را بدون متن محافظتشده ببیند؛ نشست دارای رمز متن را ببیند؛ مهمان تازه باز هم آن را نبیند. پیش از توسعهٔ تنظیمات، گردش خرید و حساب و افزونههای واقعی را با کاربران مجزا بسنجید. این آموزش WooCommerce نصب نمیکند و رفتار افزونهٔ دیگر را اثبات نمیکند.
کلاینت مجاز staging، Bash/curl؛ فایل کوکی خصوصی و محلی همان سیستم است.
(
set -euo pipefail
umask 077
work=$(mktemp -d)
base=https://blog.example.com
code=$(curl -sS --connect-timeout 5 --max-time 20 -D "$work/locked.h" -o "$work/locked.html" -w '%{http_code}' "$base/locked-test/")
[ "$code" = 200 ]
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/locked.h"
grep -F 'post-password-form' "$work/locked.html"
if grep -Fq LOCKED_CONTENT_MARKER "$work/locked.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
# Existing private jar from entering this test post password in your browser.
jar=$HOME/wp-staging-postpass.cookies
[ -s "$jar" ]
chmod 0600 "$jar"
code=$(curl -sS --connect-timeout 5 --max-time 20 -b "$jar" -D "$work/unlocked.h" -o "$work/unlocked.html" -w '%{http_code}' "$base/locked-test/")
[ "$code" = 200 ]
grep -Eiq '^X-WP-Cache: BYPASS[[:space:]]*$' "$work/unlocked.h"
grep -F LOCKED_CONTENT_MARKER "$work/unlocked.html"
code=$(curl -sS --connect-timeout 5 --max-time 20 -D "$work/again.h" -o "$work/again.html" -w '%{http_code}' "$base/locked-test/")
[ "$code" = 200 ]
if grep -Fq LOCKED_CONTENT_MARKER "$work/again.html"; then
echo 'Unexpected cached/private content or status' >&2; exit 1
else
rc=$?; [ "$rc" = 1 ] || exit "$rc"
fi
)
همه BYPASS هستند و فقط نشست دارای رمز، نشانگر متن محافظتشده را میبیند.
قدم بعدی
بازکردن سایت آماده برای بازدیدکنندگان
پس از موفقیت نصب و آزمونهای staging، فقط خطوط allow/deny موقتِ سطح server در HTTPS را حذف کنید. محافظت location برای تنظیمات و فایل مخفی و تمام قواعد bypass باقی بمانند. پنل قبلی اعتبارسنجی و reload را اجرا و از اتصال مستقل، پاسخ عمومی ۲۰۰ و ورود را بررسی کنید. کش بیرونی CDN نباید نتیجهٔ آزمون مبدأ را بپوشاند.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo nano /etc/nginx/sites-available/wordpress
سایت کامل HTTPS عمومی است؛ نشست و مسیر خصوصی همچنان کش نمیشوند.
آمادهسازی hook تمدید
مسیر چالش HTTP حفظ شود. timer موجود بستهٔ Certbot مسئول تمدید است؛ زمانبند موازی نسازید. hook بعدی پیش از reload گواهی جدید، Nginx را اعتبارسنجی میکند.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo install -d -m 0755 /etc/letsencrypt/renewal-hooks/deploy
sudo nano /etc/letsencrypt/renewal-hooks/deploy/20-nginx-validated
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
اعتبارسنجی استقرار گواهی تمدیدشده
این متن محتوای فایل است؛ آن را در نشست پوستهٔ نامرتبط اجرا نکنید.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
#!/bin/sh
set -eu
/usr/sbin/nginx -t
/bin/systemctl reload nginx
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
آزمون تمدید و زمانبندی
اجرای مستقیم hook فقط پس از اعتبارسنجی reload میکند. dry-run با ACME آزمایشی ممکن است طول بکشد و معمولاً deploy hook را اجرا نمیکند؛ فراخوانی مستقیم، رفتار hook را جدا میسنجد.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
(
set -euo pipefail
sudo chmod 0750 /etc/letsencrypt/renewal-hooks/deploy/20-nginx-validated
sudo /etc/letsencrypt/renewal-hooks/deploy/20-nginx-validated
sudo certbot renew --dry-run
systemctl list-timers --all | grep certbot
)
hook و dry-run موفقاند و timer موجود زمان اجرا دارد.
بیاعتبارکردن کش بدون حذف فایل فعال
وجود API یا ماژول purge را فرض نمیکنیم. برای تغییر فوری، پیش از عوضشدن حریم صفحه، کش را خاموش یا URL را از فهرست حذف کنید؛ سپس نسل استفادهنشدهٔ پنل بعدی را بگذارید و اعتبارسنجی و reload کنید. کل سایت کوچک بیاعتبار میشود، نه یک URL. فایل قدیمی با کلید تازه خوانده نمیشود و با محدودیت حجم و زمان بیاستفاده منقضی میشود. به نسل قدیمی برنگردید. انتشار عادی وردپرس این کش را پاک نمیکند؛ محتوا تا TTL واقعی میتواند بماند. در staging نشانگر را به PUBLIC_CACHE_MARKER_V2 عوض کنید، نسل تازه بدهید و آزمون مهمان را با نشانگر جدید تکرار کنید؛ متن قبلی نباید باشد.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo nano /etc/nginx/sites-available/wordpress
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
تغییر نسل کلید کش
خط کلید قبلی را جایگزین کنید؛ خط تکراری اضافه نکنید. نسل قبلاً استفادهنشده باشد و سپس اعتبارسنجی و reload کنید.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
# Replace the previous key directive with this NEW generation:
fastcgi_cache_key "$scheme|$request_method|$host|$request_uri|wp-v2";
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
خاموشکردن کش با حفظ سایت
اگر کاربری محتوای دیگری را دید، با خط بعدی کش را فوراً خاموش و اعتبارسنجی و reload کنید. نسخههای CDN یا توزیع بیرونی را هم از روند مسئول آن بیاعتبار و دامنهٔ افشا را بررسی کنید. فایل وردپرس، دیتابیس، uploads، حساب و گواهی را حفظ کنید. پوشهٔ کش فعال حذف نشود.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo nano /etc/nginx/sites-available/wordpress
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
قدم بعدی
بازگشت به PHP مستقیم بدون حذف داده
فقط خط انتخاب کش را جایگزین کنید؛ تا وجود ارجاع، zone بماند. پس از اعتبارسنجی و reload، بدنه و نشست باید درست باشند؛ این بار X-WP-Cache غایب است. پیش از فعالسازی دوباره سیاست را اصلاح و نسل تازه انتخاب کنید. فایلهای قبلی میتوانند عادی منقضی شوند.
محتوای فایل؛ در فایل مشخصشده ذخیره شود، نه در پوسته.
# In the PHP location, replace WORDPRESS with off:
fastcgi_cache off;
وردپرس از PHP کار میکند؛ کش خاموش و همهٔ دادهها حفظ شدهاند.
قدم بعدی
پشتیبانگیری پیش از نگهداری
مرحلهٔ اختیاری نگهداری: ابتدا از روند موجود برای توقف ویرایش محتوا، افزونه، تغییر ساختار و uploads استفاده کنید. dump برای InnoDB سازگاری تراکنشی دارد، اما فایل بارگذاری و جدول غیرتراکنشی افزونه را همزمان نمیکند. تغییر درخت فایل، مقایسه را با خطا متوقف میکند. این پشتیبان اتمی آنلاین کل سایت نیست؛ پنجرهٔ نگهداری یا روند سازگار موجود لازم است. اصل فایل و داده باقی میماند. checksum و خوانایی و مقایسهٔ محلی، قابلیت بازیابی SQL را اثبات نمیکند. پیش از بازنشستگی یا مهاجرت مخرب، در محیط بازیابی جدا restore و ورود و محتوا و uploads را بررسی و نسخهٔ رمزگذاریشدهٔ خارج از سرور نگه دارید. آزمون restore را روی دیتابیس زنده انجام ندهید. بهروزرسانی مدیریتی هسته و افزونه از منابع رسمی منظم باشد و پس از آن آزمون حریم خصوصی تکرار شود.
ترمینال Bash سرور وردپرس، حساب مدیر دارای sudo.
sudo sh -eu <<'BACKUP'
umask 077
install -d -m 0700 /root/academy-backups
backup=$(mktemp -d /root/academy-backups/wordpress-XXXXXXXX)
mariadb-dump --single-transaction --quick --databases wordpress > "$backup/wordpress.sql"
test -s "$backup/wordpress.sql"
tar -C / -cpf "$backup/wordpress-files.tar" var/www/wordpress etc/nginx/sites-available/wordpress etc/nginx/conf.d/wordpress-cache.conf etc/php/8.5/fpm/pool.d/wordpress.conf
cd "$backup"
sha256sum wordpress.sql wordpress-files.tar > SHA256SUMS
sha256sum -c SHA256SUMS
tar -tf wordpress-files.tar >/dev/null
tar -C / -df wordpress-files.tar
printf 'Verified local files and dump: %s\n' "$backup"
BACKUP
آرشیو و dump خصوصی از کنترل محلی عبور میکنند و اصل داده حفظ میشود؛ آزمون restore جدا لازم است.
عیبیابی در مرز خطا
گزارش خصوصی و کوکی محلی بماند. هر بخش، پنل تشخیصی اجرایی جدا دارد.
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
PHP پاسخ ۵۰۲ میدهد
سوکت واقعی، سرویس نسخهٔ انتخابی و مجوز را مقایسه کنید؛ restart مسیر اشتباه را درست نمیکند.
sudo nginx -t
sudo systemctl status php8.5-fpm --no-pager
sudo journalctl -u php8.5-fpm -n 50 --no-pager
sudo stat /run/php/wordpress.sock
sudo -u www-data test -w /run/php/wordpress.sockاتصال دیتابیس ناموفق است
ورود محلی، مجوز دیتابیس و خوانایی فایل را بدون چاپ رمز بررسی کنید.
sudo systemctl status mariadb --no-pager
sudo journalctl -u mariadb -n 50 --no-pager
mariadb -u wp_site -p wordpress -e 'SELECT 1;'
sudo -u wp-php test -r /var/www/wordpress/wp-config.phpنبود HIT یا بدنهٔ اشتباه
برای بدنهٔ غلط ابتدا کش را خاموش کنید. کوکی، پارامتر یا هدر خصوصی میتواند بهدرستی مانع ذخیره شود. حجم و inode را ببینید؛ برای HIT هدر را حذف نکنید. درخواست ممکن است URL عمومی را گرم کند.
sudo nginx -t
sudo df -h /var/cache/nginx/wordpress
sudo df -i /var/cache/nginx/wordpress
sudo du -sh /var/cache/nginx/wordpress
curl -sS --connect-timeout 5 --max-time 20 -D - -o /dev/null https://blog.example.com/sample-page/خطای TLS یا تمدید
DNS، دسترسی چالش و تطبیق گواهی را بررسی کنید؛ علت را اصلاح کنید و کنترل گواهی را دور نزنید.
getent ahosts blog.example.com
sudo nginx -t
sudo certbot certificates
sudo journalctl -u nginx -n 50 --no-pagerحفظ محدودهٔ روشن بهرهبرداری
ظرفیت PHP، فضای کش و inode و بازیابی تأییدشده را پایش کنید و فهرست مجاز کوچک بماند. object cache، CDN، چندسایتی، اشتراک و WooCommerce طراحی و آزمون گردش واقعی جدا میخواهند. HIT عمومی، صحت خرید یا امنیت ورود را ثابت نمیکند.
بررسی موفق است؛ در صورت خطا، پیش از ادامه علت را برطرف کنید.
پشتوانهٔ این آموزش
منابع رسمی
وضعیت بررسی هر محیط بالای صفحه مشخص است؛ بررسی مستندات به معنی اجرای عملی همهٔ نسخهها نیست.
- WordPress release archive
- WordPress requirements
- WordPress installation
- WordPress hardening
- WordPress Nginx guide
- Nginx FastCGI module
- Nginx releases
- PHP support dates
- PHP-FPM configuration
- MariaDB maintenance policy
- MariaDB grants
- WooCommerce cache exclusions
- Certbot webroot and renewal hooks
- Ubuntu 26.10 release notes
- Debian LTS coverage
- WordPress updates
ادامهٔ مسیر