- Автор темы
- Администратор
- Модер.
- Команда форума
- #1
Ubuntu 24.04/22.04 + Nginx + PHP 8.3 + MySQL 8.4.
Для MySQL 8.4 лучше использовать официальный MySQL APT repository — Oracle прямо рекомендует его как preferred method для Debian/Ubuntu. Для PHP 8.3 на Ubuntu обычно используют репозиторий Ondřej Surý с актуальными пакетами для текущих Ubuntu LTS.
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg2 lsb-release unzip software-properties-common
sudo apt install -y nginx
sudo systemctl enable --now nginx
sudo add-apt-repository ppa
ndrej/php -y
sudo apt update
sudo apt install -y \
php8.3-fpm php8.3-cli php8.3-common \
php8.3-mysql php8.3-curl php8.3-mbstring php8.3-xml \
php8.3-zip php8.3-gd php8.3-intl php8.3-bcmath \
php8.3-opcache php8.3-readline
Проверка:
php -v
systemctl status php8.3-fpm --no-pager
С official repo:
cd /tmp
curl -LO https://dev.mysql.com/get/mysql-apt-config_0.8.36-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.36-1_all.deb
sudo apt update
sudo apt install -y mysql-server
Проверка:
mysql --version
sudo systemctl enable --now mysql
MySQL APT repository — официальный способ для Ubuntu/Debian, а сам репозиторий обновляет информацию о доступных сериях MySQL, включая актуальные LTS-ветки.
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
sudo systemctl disable --now apache2 2>/dev/null || true
Открой:
sudo nano /etc/php/8.3/fpm/php.ini
Поставь разумный baseline:
expose_php = Off
memory_limit = 256M
max_execution_time = 60
max_input_time = 60
post_max_size = 32M
upload_max_filesize = 32M
cgi.fix_pathinfo = 0
date.timezone = Europe/Kyiv
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
Для production opcache.validate_timestamps=0 ускоряет работу, но после деплоя нужен reload/restart PHP-FPM. Это уместно только если у тебя нормальный процесс выката.
Дальше настрой пул:
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Рекомендуемый быстрый вариант для 2–4 GB RAM:
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 30
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
Потом:
sudo systemctl restart php8.3-fpm
NGINX документирует стандартную работу с конфигами, FastCGI и HTTPS; для TLS у них есть отдельные рекомендации по ssl_session_cache и worker_processes auto.
sudo nano /etc/nginx/nginx.conf
Минимально хороший шаблон:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
client_max_body_size 32m;
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_types
text/plain
text/css
text/xml
application/json
application/javascript
application/xml+rss
application/xml
image/svg+xml;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Проверка:
sudo nginx -t
sudo systemctl reload nginx
Пример для сайта /var/www/app/public:
sudo mkdir -p /var/www/app/public
sudo chown -R www-data:www-data /var/www/app
Создай конфиг:
sudo nano /etc/nginx/sites-available/app.conf
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/app/public;
index index.php index.html;
access_log /var/log/nginx/app.access.log;
error_log /var/log/nginx/app.error.log warn;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\.(?!well-known).* {
deny all;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_buffering on;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp|woff|woff2)$ {
expires 30d;
access_log off;
add_header Cache-Control "public, immutable";
}
}
Активируй:
sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Проверка таймера:
systemctl status certbot.timer --no-pager
После выпуска сертификата добавь/проверь HSTS только если уверен, что HTTPS везде работает стабильно:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
У NGINX в TLS-примерах фигурируют ssl_session_cache shared:SSL:10m; и настройка timeout; это нормальный production baseline.
Запусти:
sudo mysql_secure_installation
Потом войди:
sudo mysql
Создай БД и отдельного пользователя:
CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'appuser'@'127.0.0.1' IDENTIFIED BY 'Strong_Long_Random_Password';
GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'127.0.0.1';
FLUSH PRIVILEGES;
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Хороший старт для 4–8 GB RAM:
[mysqld]
bind-address = 127.0.0.1
mysqlx = 0
max_connections = 150
thread_cache_size = 50
table_open_cache = 4000
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_log_file_size = 512M
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
tmp_table_size = 64M
max_heap_table_size = 64M
character-set-server = utf8mb4
collation-server = utf8mb4_0900_ai_ci
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
Перезапуск:
sudo systemctl restart mysql
Проверь:
sudo mysql -e "SHOW VARIABLES LIKE 'version';"
sudo mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
Для типового PHP-приложения:
sudo chown -R www-data:www-data /var/www/app
sudo find /var/www/app -type d -exec chmod 755 {} \;
sudo find /var/www/app -type f -exec chmod 644 {} \;
Никогда не держи .env, дампы БД и приватные ключи внутри public/.
echo '<?php phpinfo();' | sudo tee /var/www/app/public/info.php
Открой http://example.com/info.php, убедись, что работает, потом сразу удали:
sudo rm /var/www/app/public/info.php
sudo nano /var/www/app/public/db.php
<?php
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=app;charset=utf8mb4',
'appuser',
'Strong_Long_Random_Password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
echo 'DB OK';
Для MySQL 8.4 лучше использовать официальный MySQL APT repository — Oracle прямо рекомендует его как preferred method для Debian/Ubuntu. Для PHP 8.3 на Ubuntu обычно используют репозиторий Ondřej Surý с актуальными пакетами для текущих Ubuntu LTS.
1) Установка пакетов
sudo apt update
sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg2 lsb-release unzip software-properties-common
Nginx
sudo apt install -y nginx
sudo systemctl enable --now nginx
PHP 8.3
sudo add-apt-repository ppa
sudo apt update
sudo apt install -y \
php8.3-fpm php8.3-cli php8.3-common \
php8.3-mysql php8.3-curl php8.3-mbstring php8.3-xml \
php8.3-zip php8.3-gd php8.3-intl php8.3-bcmath \
php8.3-opcache php8.3-readline
Проверка:
php -v
systemctl status php8.3-fpm --no-pager
MySQL 8.4
С official repo:
cd /tmp
curl -LO https://dev.mysql.com/get/mysql-apt-config_0.8.36-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.36-1_all.deb
sudo apt update
sudo apt install -y mysql-server
Проверка:
mysql --version
sudo systemctl enable --now mysql
MySQL APT repository — официальный способ для Ubuntu/Debian, а сам репозиторий обновляет информацию о доступных сериях MySQL, включая актуальные LTS-ветки.
2) Быстрая защита сервера
Firewall
sudo apt install -y ufw
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
Отключить лишнее
sudo systemctl disable --now apache2 2>/dev/null || true
3) PHP-FPM: production-настройка
Открой:
sudo nano /etc/php/8.3/fpm/php.ini
Поставь разумный baseline:
expose_php = Off
memory_limit = 256M
max_execution_time = 60
max_input_time = 60
post_max_size = 32M
upload_max_filesize = 32M
cgi.fix_pathinfo = 0
date.timezone = Europe/Kyiv
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=192
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.save_comments=1
Для production opcache.validate_timestamps=0 ускоряет работу, но после деплоя нужен reload/restart PHP-FPM. Это уместно только если у тебя нормальный процесс выката.
Дальше настрой пул:
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Рекомендуемый быстрый вариант для 2–4 GB RAM:
user = www-data
group = www-data
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
pm = dynamic
pm.max_children = 30
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
Потом:
sudo systemctl restart php8.3-fpm
4) Nginx: быстрый production baseline
NGINX документирует стандартную работу с конфигами, FastCGI и HTTPS; для TLS у них есть отдельные рекомендации по ssl_session_cache и worker_processes auto.
Основной nginx.conf
sudo nano /etc/nginx/nginx.conf
Минимально хороший шаблон:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 4096;
multi_accept on;
}
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 15;
types_hash_max_size 2048;
server_tokens off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
error_log /var/log/nginx/error.log warn;
client_max_body_size 32m;
gzip on;
gzip_comp_level 5;
gzip_min_length 256;
gzip_proxied any;
gzip_types
text/plain
text/css
text/xml
application/json
application/javascript
application/xml+rss
application/xml
image/svg+xml;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Проверка:
sudo nginx -t
sudo systemctl reload nginx
5) Правильный server block под PHP
Пример для сайта /var/www/app/public:
sudo mkdir -p /var/www/app/public
sudo chown -R www-data:www-data /var/www/app
Создай конфиг:
sudo nano /etc/nginx/sites-available/app.conf
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/app/public;
index index.php index.html;
access_log /var/log/nginx/app.access.log;
error_log /var/log/nginx/app.error.log warn;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
location ~ /\.(?!well-known).* {
deny all;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_connect_timeout 10s;
fastcgi_send_timeout 60s;
fastcgi_read_timeout 60s;
fastcgi_buffering on;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|webp|woff|woff2)$ {
expires 30d;
access_log off;
add_header Cache-Control "public, immutable";
}
}
Активируй:
sudo ln -s /etc/nginx/sites-available/app.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
6) HTTPS через Let’s Encrypt
sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d example.com -d www.example.com
Проверка таймера:
systemctl status certbot.timer --no-pager
После выпуска сертификата добавь/проверь HSTS только если уверен, что HTTPS везде работает стабильно:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
У NGINX в TLS-примерах фигурируют ssl_session_cache shared:SSL:10m; и настройка timeout; это нормальный production baseline.
7) MySQL 8.4: быстрая безопасная настройка
Запусти:
sudo mysql_secure_installation
Потом войди:
sudo mysql
Создай БД и отдельного пользователя:
CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;
CREATE USER 'appuser'@'127.0.0.1' IDENTIFIED BY 'Strong_Long_Random_Password';
GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'127.0.0.1';
FLUSH PRIVILEGES;
Базовый my.cnf
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Хороший старт для 4–8 GB RAM:
[mysqld]
bind-address = 127.0.0.1
mysqlx = 0
max_connections = 150
thread_cache_size = 50
table_open_cache = 4000
innodb_buffer_pool_size = 2G
innodb_buffer_pool_instances = 2
innodb_log_file_size = 512M
innodb_flush_method = O_DIRECT
innodb_flush_log_at_trx_commit = 1
innodb_file_per_table = 1
tmp_table_size = 64M
max_heap_table_size = 64M
character-set-server = utf8mb4
collation-server = utf8mb4_0900_ai_ci
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
Перезапуск:
sudo systemctl restart mysql
Проверь:
sudo mysql -e "SHOW VARIABLES LIKE 'version';"
sudo mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
8) Права и deploy-гигиена
Для типового PHP-приложения:
sudo chown -R www-data:www-data /var/www/app
sudo find /var/www/app -type d -exec chmod 755 {} \;
sudo find /var/www/app -type f -exec chmod 644 {} \;
Никогда не держи .env, дампы БД и приватные ключи внутри public/.
9) Проверка всей связки
Тест PHP
echo '<?php phpinfo();' | sudo tee /var/www/app/public/info.php
Открой http://example.com/info.php, убедись, что работает, потом сразу удали:
sudo rm /var/www/app/public/info.php
Тест PDO MySQL
sudo nano /var/www/app/public/db.php
<?php
$pdo = new PDO(
'mysql:host=127.0.0.1;dbname=app;charset=utf8mb4',
'appuser',
'Strong_Long_Random_Password',
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
]
);
echo 'DB OK';
