Подготовка сервера
sudo apt update && sudo apt -y upgrade
sudo apt install -y ufw ca-certificates curl lsb-release
sudo ufw allow OpenSSH
sudo ufw allow "Apache Full" 2>/dev/null || true
sudo 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 expires
PHPVER=$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')
# На Ubuntu/Debian есть готовый конфиг вида php8.x-fpmsudo a2enconf php${PHPVER}-fpm
sudo 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.com
sudo mkdir -p /var/www/${DOMAIN}/public
echo "<!doctype html><title>OK</title>OK" | sudo tee /var/www/${DOMAIN}/public/index.html >/dev/null
sudo 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 All
Require all granted
</Directory>
# Отдача статики и кэш-заголовки
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType 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.log
CustomLog \${APACHE_LOG_DIR}/${DOMAIN}_access.log combined
</VirtualHost>
APACHE
sudo a2ensite ${DOMAIN}.conf
sudo a2dissite 000-default.conf 2>/dev/null || true
sudo 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=512M
upload_max_filesize=64M
post_max_size=64M
max_execution_time=120
opcache.enable=1
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=100000
opcache.validate_timestamps=0
INI
sudo 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