Если вам нужно быстро поднять WordPress в продакшн, где страницы отдаются шустро, админка не тормозит, а нагрузка держится предсказуемо, связка Nginx + PHP-FPM + Redis это базовый “правильный” стек. В этой инструкции вы поставите WordPress на чистый сервер, настроите Nginx под PHP-FPM, подключите Redis под object cache, включите HTTPS, проверите производительность и сразу закроете типовые ошибки. Дальше покажу, как без боли масштабироваться с одного VPS до multi-node и когда пора переезжать на выделенный сервер или брать подсеть IPv4.
Что получите на выходе и почему стек именно такой
Nginx отвечает за быстрый веб и статик, PHP-FPM изолирует PHP-процессы и даёт нормальную настройку пулов, Redis снимает часть нагрузки с базы и ускоряет админку за счёт object cache. В итоге WordPress становится заметно живее уже на старте, а под нагрузкой деградирует медленнее, чем “как получилось по умолчанию”.
Практический минимум по серверу для нормальной работы одного сайта: 2 vCPU, 2–4 GB RAM, NVMe. Если у вас коммерческий сайт или несколько проектов, это тот случай, когда выгоднее сразу заказать VPS с честными vCPU/NVMe и не экономить на диске. На HSTQ обычно берут VPS в Европе (NL/DE/UK) под минимальную задержку и быстрые апгрейды, а перенос и первичную настройку можно закрыть “под ключ”, чтобы вы не тратили день на рутину.
Важные вводные перед установкой
Чтобы дальше не ловить “почему SSL не ставится” и “почему редирект крутится по кругу”, сделайте базу правильно:
-
У домена должна быть A-запись на IP сервера
-
На сервере должен быть корректный hostname
-
Порты 80 и 443 открыты наружу, SSH доступен вам
-
Система чистая, без старых Apache/Nginx и “случайных” стеков
Дальше я дам рабочий bash-скрипт, который ставит весь стек на Ubuntu 24.04. Для Debian 12 и AlmaLinux 9 ниже будут короткие отличия, но в продакшне я рекомендую именно Ubuntu 24.04 под WordPress, потому что с PHP 8.3 и пакетами всё проще и быстрее.
Быстрая установка одним скриптом Ubuntu 24.04
Скрипт сделан так, чтобы вы не ковыряли конфиги руками. Он спросит домен и email для сертификата, сам поставит пакеты, создаст базу, поставит WordPress через WP-CLI, настроит Nginx + PHP-FPM, включит Redis и активирует object cache. Показ прогресса идёт шагами, после установки выводит проверки.
Запускайте от root на чистом Ubuntu 24.04:
cat > /root/wp-nginx-phpfpm-redis.sh <<'BASH'
#!/usr/bin/env bash
set -euo pipefail
log(){ printf "\n[%s] %s\n" "$(date '+%H:%M:%S')" "$*"; }
step(){ printf "\n[%s/%s] %s\n" "$1" "$2" "$3"; }
need_root(){
if [[ "$(id -u)" -ne 0 ]]; then
echo "Run as root"; exit 1
fi
}
ask(){
read -r -p "Domain (example.com): " DOMAIN
read -r -p "Email for Let's Encrypt: " EMAIL
read -r -s -p "MySQL root password: " DB_ROOT_PASS; echo
read -r -s -p "WP admin password: " WP_ADMIN_PASS; echo
if [[ -z "${DOMAIN:-}" || -z "${EMAIL:-}" || -z "${DB_ROOT_PASS:-}" || -z "${WP_ADMIN_PASS:-}" ]]; then
echo "Empty values are not allowed"; exit 1
fi
DB_NAME="wp_${DOMAIN//./_}"
DB_USER="wp_${DOMAIN//./_}"
DB_PASS="$(openssl rand -base64 24 | tr -d '=+/')"
WP_ADMIN_USER="admin"
WP_ADMIN_EMAIL="$EMAIL"
WEBROOT="/var/www/${DOMAIN}"
}
sys_prep(){
step 1 10 "System update and base packages"
export DEBIAN_FRONTEND=noninteractive
apt-get update -y
apt-get upgrade -y
apt-get install -y ca-certificates curl unzip gnupg lsb-release ufw fail2ban openssl
step 2 10 "Firewall (UFW): allow SSH/HTTP/HTTPS"
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw allow 22/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw --force enable
}
install_stack(){
step 3 10 "Install Nginx, MariaDB, PHP-FPM 8.3, Redis, WP-CLI"
apt-get install -y nginx mariadb-server redis-server \
php8.3-fpm php8.3-cli php8.3-common php8.3-mysql php8.3-xml php8.3-gd php8.3-curl \
php8.3-mbstring php8.3-zip php8.3-intl php8.3-bcmath php8.3-imagick php-redis \
wp-cli certbot python3-certbot-nginx
systemctl enable --now nginx mariadb redis-server php8.3-fpm
}
secure_mariadb(){
step 4 10 "Secure MariaDB and create database"
mysql --protocol=socket -uroot <<SQL
ALTER USER 'root'@'localhost' IDENTIFIED BY '${DB_ROOT_PASS}';
DELETE FROM mysql.user WHERE User='';
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
SQL
mysql -uroot -p"${DB_ROOT_PASS}" <<SQL
CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASS}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SQL
}
tune_php(){
step 5 10 "Tune PHP-FPM (basic safe defaults)"
sed -i 's/^;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/' /etc/php/8.3/fpm/php.ini
sed -i 's/^memory_limit = .*/memory_limit = 256M/' /etc/php/8.3/fpm/php.ini
sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 64M/' /etc/php/8.3/fpm/php.ini
sed -i 's/^post_max_size = .*/post_max_size = 64M/' /etc/php/8.3/fpm/php.ini
sed -i 's/^max_execution_time = .*/max_execution_time = 120/' /etc/php/8.3/fpm/php.ini
systemctl restart php8.3-fpm
}
setup_redis(){
step 6 10 "Redis: unix socket + permissions (secure and fast)"
sed -i 's/^# unixsocket .*/unixsocket \/run\/redis\/redis-server.sock/' /etc/redis/redis.conf
sed -i 's/^# unixsocketperm .*/unixsocketperm 770/' /etc/redis/redis.conf
sed -i 's/^supervised .*/supervised systemd/' /etc/redis/redis.conf
systemctl restart redis-server
usermod -aG redis www-data
}
setup_nginx(){
step 7 10 "Nginx vhost for WordPress"
mkdir -p "${WEBROOT}/public"
chown -R www-data:www-data "${WEBROOT}"
chmod 0755 "${WEBROOT}"
cat > /etc/nginx/snippets/wordpress-common.conf <<'NG'
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { allow all; log_not_found off; access_log off; }
location ~* \.(css|gif|ico|jpeg|jpg|js|png|svg|webp|woff2?)$ {
expires 30d;
add_header Cache-Control "public, max-age=2592000";
access_log off;
}
location ~* \.(zip|gz|tgz|rar|bz2|7z)$ { deny all; }
location ~* /(wp-config\.php|readme\.html|license\.txt) { deny all; }
NG
cat > /etc/nginx/sites-available/"${DOMAIN}".conf <<NG
server {
listen 80;
server_name ${DOMAIN} www.${DOMAIN};
root ${WEBROOT}/public;
index index.php index.html;
access_log /var/log/nginx/${DOMAIN}.access.log;
error_log /var/log/nginx/${DOMAIN}.error.log warn;
include /etc/nginx/snippets/wordpress-common.conf;
location / {
try_files \$uri \$uri/ /index.php?\$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_read_timeout 120;
}
}
NG
ln -sf /etc/nginx/sites-available/"${DOMAIN}".conf /etc/nginx/sites-enabled/"${DOMAIN}".conf
rm -f /etc/nginx/sites-enabled/default || true
nginx -t
systemctl reload nginx
}
install_wp(){
step 8 10 "Install WordPress via WP-CLI"
sudo -u www-data wp core download --path="${WEBROOT}/public" --locale=ru_RU
sudo -u www-data wp config create --path="${WEBROOT}/public" \
--dbname="${DB_NAME}" --dbuser="${DB_USER}" --dbpass="${DB_PASS}" --dbhost=localhost \
--dbcharset=utf8mb4 --dbcollate=utf8mb4_unicode_ci
sudo -u www-data wp core install --path="${WEBROOT}/public" \
--url="https://${DOMAIN}" --title="${DOMAIN}" \
--admin_user="${WP_ADMIN_USER}" --admin_password="${WP_ADMIN_PASS}" --admin_email="${WP_ADMIN_EMAIL}"
chmod 640 "${WEBROOT}/public/wp-config.php"
}
enable_redis_wp(){
step 9 10 "Enable Redis object cache in WordPress"
sudo -u www-data wp plugin install redis-cache --activate --path="${WEBROOT}/public"
cat >> "${WEBROOT}/public/wp-config.php" <<'PHP'
define('WP_REDIS_PATH', '/run/redis/redis-server.sock');
define('WP_REDIS_SCHEME', 'unix');
define('WP_REDIS_DATABASE', 0);
define('WP_CACHE', true);
PHP
sudo -u www-data wp redis enable --path="${WEBROOT}/public" || true
}
ssl(){
step 10 10 "Issue Let's Encrypt certificate and enable HTTPS"
certbot --nginx -d "${DOMAIN}" -d "www.${DOMAIN}" --non-interactive --agree-tos -m "${EMAIL}" --redirect
systemctl reload nginx
}
checks(){
log "Checks"
echo "Domain: ${DOMAIN}"
echo "Webroot: ${WEBROOT}/public"
echo "DB: ${DB_NAME}"
echo "DB user: ${DB_USER}"
echo "DB pass: ${DB_PASS}"
echo
echo "Ports:"
ss -lntp | egrep ':80|:443|:3306|:6379' || true
echo
echo "Nginx:"
nginx -t
echo
echo "PHP-FPM:"
systemctl is-active php8.3-fpm && php -v | head -n 1
echo
echo "Redis:"
systemctl is-active redis-server && redis-cli ping
echo
echo "HTTP check:"
curl -I "http://127.0.0.1" 2>/dev/null | head -n 1 || true
echo
echo "HTTPS check:"
curl -kI "https://${DOMAIN}" 2>/dev/null | head -n 1 || true
}
need_root
ask
sys_prep
install_stack
secure_mariadb
tune_php
setup_redis
setup_nginx
install_wp
enable_redis_wp
ssl
checks
log "Done. Open https://${DOMAIN}/wp-admin"
BASH
chmod +x /root/wp-nginx-phpfpm-redis.sh
/root/wp-nginx-phpfpm-redis.sh
После выполнения вы получаете готовый WordPress на HTTPS, Redis object cache активирован, базовый firewall включён, и всё проверено командами в конце. Если хотите быстрее и без риска “что-то упустил”, проще заказать VPS с преднастройкой WordPress + Nginx + PHP-FPM + Redis, а миграцию и перенос домена мы закроем бесплатно, вы просто дадите доступы и получите готовый сайт.
Как проверить, что Redis реально работает, а не “просто установлен”
Самая частая самообманка: Redis стоит, но WordPress в него не пишет. Проверка должна быть фактической.
Зайдите в админку WordPress, откройте инструменты Redis (плагин redis-cache добавит раздел) и проверьте статус “Connected”. С сервера проверьте сокет и запросы:
ls -l /run/redis/redis-server.sock
redis-cli ping
redis-cli info stats | egrep 'keyspace_hits|keyspace_misses'
Если hits растут при навигации по админке и фронту, объектный кеш работает.
Типовые ошибки и мгновенная правка
Если при установке SSL certbot ругается, что домен не резолвится, это не “проблема сертификата”, это DNS. Сначала проверьте:
dig +short A yourdomain.com
IP должен совпадать с сервером. Пока не совпадает, HTTPS не получите.
Если Nginx отдаёт 502 Bad Gateway, это почти всегда PHP-FPM socket или не тот путь. Быстрая проверка:
systemctl status php8.3-fpm --no-pager
ls -l /run/php/php8.3-fpm.sock
nginx -t
Если сокета нет, перезапустите php-fpm и проверьте, не забилась память.
Если WordPress просит права на запись и не ставит плагины, проверьте владельца webroot:
chown -R www-data:www-data /var/www/yourdomain.com
find /var/www/yourdomain.com -type d -exec chmod 755 {} \;
find /var/www/yourdomain.com -type f -exec chmod 644 {} \;
Если Redis не подключается, причина обычно в правах на сокет. Проверьте, что www-data в группе redis:
id www-data
getfacl /run/redis/redis-server.sock 2>/dev/null || true
И убедитесь, что в redis.conf включён unixsocket и unixsocketperm 770, после чего перезапустите redis-server.
Debian 12 и AlmaLinux 9: что меняется по шагам
На Debian 12 стек такой же, но PHP по умолчанию 8.2. Логика установки и конфиги идентичны, меняются пакеты и путь сокета php-fpm. Если вы не хотите сторонние репозитории, оставляйте PHP 8.2, для WordPress это нормально.
На AlmaLinux 9 чаще всего ставят Nginx из официальных репозиториев и PHP через Remi, чтобы получить актуальную 8.3. Если вы делаете продакшн на AlmaLinux и хотите тот же результат, лучше делать установку как управляемую услугу, потому что сочетание SELinux, firewalld и репозиториев обычно съедает время. В таких случаях проще арендовать VPS под Linux-стек там, где всё ставится быстро и предсказуемо, а AlmaLinux оставить для тех задач, где он реально нужен.
Апгрейд-траектория: от одного VPS до multi-node и HA
Когда у вас один сайт, этот стек работает на одном VPS отлично. Дальше рост почти всегда идёт по этапам.
Первый этап: вынос бэкапов на отдельный сервер. Бэкап на том же диске это самоуспокоение. Поставьте второй маленький VPS в другой локации и делайте ежедневные снапшоты и дампы туда.
Второй этап: вынос базы. Когда MariaDB начинает быть узким местом, перенос базы на отдельный сервер даёт максимальный эффект без переписывания приложения. Nginx+PHP остаются на веб-узле, Redis можно держать рядом с PHP, чтобы не ловить сетевую задержку.
Третий этап: два веб-узла за балансировщиком. Для этого вам нужен общий storage для uploads (объектное хранилище или shared FS), общий Redis, отдельная база и нормальная схема деплоя. Тут уже появляется смысл в multi-node и продуманной сети.
Когда пора переходить на выделенный сервер: когда вы упираетесь в IOPS и CPU, а не в “настройки”. Если нагрузка стабильная и высокая, dedicated часто выгоднее по цене владения и нервам, чем бесконечные апгрейды VPS.
Когда нужна подсеть IPv4 и ASN: если вы строите вокруг проектов инфраструктуру с большим количеством IP (прокси-сервисы, отдельные витрины, сегментация по клиентам, почтовые узлы), тогда отдельная адресация начинает быть инструментом управления риском и репутацией. В этот момент полезно, когда провайдер умеет сдавать IPv4, делать PTR/WHOIS и при необходимости помогать с LIR/ASN, чтобы вы не упирались в сетевые “не можем”.
Мини-FAQ
Redis обязателен или можно без него?
Без Redis WordPress тоже работает, но под нагрузкой и в админке вы быстрее упираетесь в базу. Redis это простой способ ускорить сайт без архитектурного рефакторинга.
Что важнее для скорости: Redis или кеш страниц?
Если трафик высокий, кеш страниц может дать больше, но Redis улучшает именно внутреннюю работу WordPress и снижает нагрузку на БД. В идеале используют оба, но начинают обычно с Redis и нормальной настройки PHP-FPM.
Можно ли ставить это на Windows Server?
Этот стек под Linux. На Windows имеет смысл только заходить в админку и управлять сайтом, а сам прод держать на Linux VPS.
Почему после включения Redis ничего не ускорилось?
Потому что Redis может не быть реально активирован в WordPress. Смотрите stats hits/misses и статус Connected, а не факт установки пакета.
Что самое частое, что ломает установку?
DNS и порты. Пока домен не указывает на сервер и 80/443 не доступны, SSL и нормальные редиректы не заработают.