Подготовка сервера
sudo apt update && sudo apt -y upgradesudo apt install -y ufw ca-certificates curl lsb-releasesudo ufw allow OpenSSHsudo ufw allow "Apache Full" 2>/dev/null || truesudo ufw --force enable
Установка Apache, MariaDB и PHP-FPM
Используем PHP-FPM (а не mod_php): быстрее и безопаснее.
# Apache + MariaDB + PHP-FPM с ключевыми модулямиsudo apt install -y apache2 mariadb-server php-fpm php-cli php-mysql php-xml php-curl \php-zip php-gd php-mbstring php-intl php-bcmath php-gmp
# Включаем нужные модули Apache и PHP-FPMsudo a2enmod proxy proxy_fcgi setenvif rewrite headers expiresPHPVER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
# На Ubuntu/Debian есть готовый конфиг вида php8.x-fpmsudo a2enconf php${PHPVER}-fpmsudo systemctl restart php${PHPVER}-fpm apache2
Базовая защита MariaDB и создание базы
# Быстрая базовая защита (пароль root, удаление тестовой БД и анонимных)sudo mysql_secure_installation
# Пример: создаём БД/пользователя для проектаmysql -uroot -p <<'SQL'CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'Strong_db_pass_123';GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';FLUSH PRIVILEGES;SQL
Разворачиваем сайт: виртуальный хост + права
Задайте домен единожды — и используйте его в конфиге.
DOMAIN=example.comsudo mkdir -p /var/www/${DOMAIN}/publicecho "<!doctype html><title>OK</title>OK" | sudo tee /var/www/${DOMAIN}/public/index.html >/dev/nullsudo chown -R www-data:www-data /var/www/${DOMAIN}
Виртуальный хост Apache:
sudo tee /etc/apache2/sites-available/${DOMAIN}.conf >/dev/null <<APACHE<VirtualHost *:80>ServerName ${DOMAIN}ServerAlias www.${DOMAIN}DocumentRoot /var/www/${DOMAIN}/public
<Directory /var/www/${DOMAIN}/public>AllowOverride AllRequire all granted</Directory>
# Отдача статики и кэш-заголовки<IfModule mod_expires.c>ExpiresActive OnExpiresByType text/css "access plus 7 days"ExpiresByType application/javascript "access plus 7 days"ExpiresByType image/svg+xml "access plus 7 days"ExpiresByType image/avif "access plus 7 days"ExpiresByType image/webp "access plus 7 days"ExpiresDefault "access plus 1 day"</IfModule>
# Передача .php в php-fpm (универсально)<FilesMatch "\.php$">SetHandler "proxy:unix:/run/php/php${PHPVER}-fpm.sock|fcgi://localhost/"</FilesMatch>
ErrorLog \${APACHE_LOG_DIR}/${DOMAIN}_error.logCustomLog \${APACHE_LOG_DIR}/${DOMAIN}_access.log combined</VirtualHost>APACHE
sudo a2ensite ${DOMAIN}.confsudo a2dissite 000-default.conf 2>/dev/null || truesudo apachectl configtest && sudo systemctl reload apache2
Тест PHP:
echo "<?php phpinfo();" | sudo tee /var/www/${DOMAIN}/public/info.php >/dev/null
# откройте http://example.com/info.php — затем удалите:sudo rm -f /var/www/${DOMAIN}/public/info.php
Полезные твики PHP-FPM под веб-нагрузку
sudo tee /etc/php/${PHPVER}/fpm/conf.d/90-tuning.ini >/dev/null <<'INI'memory_limit=512Mupload_max_filesize=64Mpost_max_size=64Mmax_execution_time=120opcache.enable=1opcache.memory_consumption=192opcache.interned_strings_buffer=16opcache.max_accelerated_files=100000opcache.validate_timestamps=0INIsudo systemctl reload php${PHPVER}-fpm
Безопасность и обслуживание
sudo a2enmod ssl headers
# мини-защита серверных заголовковsudo tee /etc/apache2/conf-available/security-headers.conf >/dev/null <<'CONF'<IfModule mod_headers.c>Header always set X-Content-Type-Options "nosniff"Header always set X-Frame-Options "SAMEORIGIN"Header always set Referrer-Policy "no-referrer-when-downgrade"</IfModule>CONF
sudo a2enconf security-headers && sudo systemctl reload apache2