Установка LAMP на Ubuntu 24.04 с PHP-FPM
Пошаговая настройка Apache, MariaDB с unix_socket и PHP 8.3 на Ubuntu 24.04. Узнайте, как настроить vhost и получить бесплатный HTTPS через Certbot.
Что вы создаете
LAMP stack состоит из четырех компонентов на одном сервере Ubuntu 24.04: ядро Linux, Apache для обработки HTTP, MariaDB для хранения данных и PHP 8.3 для выполнения кода. В итоге у вас будет виртуальный хост на основе доменного имени, обслуживающий директорию приложения, база данных с пользователем с минимальными привилегиями, PHP, подключенный к Apache через PHP-FPM, и бесплатный сертификат Let's Encrypt.
Процесс установки состоит из четырех команд apt. Основная часть этого руководства посвящена настройке связей между компонентами и разбору типичных ошибок. Ошибки могут привести к отображению пустой страницы, загрузке исходного кода вместо сайта или невозможности входа в только что установленную базу данных. У каждой такой ошибки есть характерные признаки, которые перечислены ниже с точным текстом сообщений.
Предварительные требования и известные нюансы
Предположим, что у вас есть чистая Ubuntu 24.04 KVM VPS с пользователем sudo или root и публильным IPv4-адресом. Минимальный стек потребляет 1 GB RAM. Выделите 2 GB перед развертыванием приложения с полноценной базой данных, так как стандартные буферы MariaDB и несколько процессов PHP-FPM быстро заполнят первый гигабайт.
Для корректной работы Certbot в конце процесса должны быть выполнены два условия. Сначала настройте их. Вам необходим доменное имя с A-записью, указывающей на публичный IP-адрес VPS. Let's Encrypt выполняет проверку через HTTP по этому имени; получить сертификат только по IP-адресу невозможно. Также порты 80 и 443 должны быть доступны из интернета. У многих провайдеров это означает необходимость открытия портов как в сетевом экране в панели управления, так и в ufw на самом сервере. Изменения DNS могут распространяться до одного часа, поэтому сначала настройте A-запись; она станет активной к моменту, когда она вам потребуется.
Шаг 1 — Установка Apache и проверка стандартной страницы
sudo apt update
sudo apt install -y apache2apt запускает и включает службу автоматически. Проверьте состояние:
systemctl status apache2В выводе должна быть строка active (running). Теперь откройте http://YOUR_SERVER_IP/ в браузере. Apache2 Ubuntu Default Page с баннером "It works!" — это верный результат. Это подтверждает работу Apache, а не является ошибкой. Данная страница доступна по адресу /var/www/html/index.html и обслуживается стандартным виртуальным хостом 000-default.conf. Позже вы отключите оба компонента; на данном этапе их наличие необходимо.
Если страница не загружается, но systemctl сообщает, что процесс запущен, значит, доступ блокирует firewall. Это будет следующим шагом.
Шаг 2 — Откройте firewall для HTTP и HTTPS
Пакет apache2 регистрирует три профиля приложений ufw. Выведите их список:
sudo ufw app listВы увидите Apache, Apache Full и Apache Secure. Apache открывает только порт 80, Apache Secure открывает только порт 443, а Apache Full открывает оба порта. Вам нужен именно этот профиль, так как в дальнейшем вы добавите TLS.
sudo ufw allow OpenSSH
sudo ufw allow "Apache Full"
sudo ufw enableРазрешите OpenSSH перед запуском ufw enable. По умолчанию ufw запрещает весь входящий трафик. Если включить его без правила для SSH, текущая сессия сохранится, но вы не сможете подключиться повторно после активации правила. Проверьте настройки с помощью sudo ufw status; значения OpenSSH, Apache Full и их v6-эквиваленты должны иметь статус ALLOW.
Шаг 3 — Установка и защита MariaDB
sudo apt install -y mariadb-server
systemctl status mariadbВ Ubuntu 24.04 поставляется MariaDB 10.11 (версия с долгосрочной поддержкой), поэтому внешние репозитории не требуются. После запуска службы выполните ее настройку безопасности:
sudo mysql_secure_installationРекомендуется внимательно читать запросы, а не просто нажимать Enter. Когда система запросит текущий пароль root, нажмите Enter — пароль еще не установлен. На вопрос "Switch to unix_socket authentication?" ответ не влияет, так как эта функция уже включена в данном пакете, поэтому нажмите n. На вопрос "Change the root password?" ответьте n (причина указана в следующем абзаце), а на остальные вопросы ответьте Y: удалите анонимных пользователей, запретите удаленный вход для root, удалите тестовую базу данных и перезагрузите таблицы привилегий.
Этот момент часто вызывает путаницу. В MariaDB на Ubuntu учетная запись базы данных root использует аутентификацию unix_socket, а не пароль. Это означает, что база данных доверяет пользователю операционной системы, под которым вы уже авторизованы. Таким образом, команда сработает из оболочки root:
sudo mysql...и вы попадете в командную строку MariaDB [(none)]> без запроса пароля. При запуске той же команды от имени непривилегированного пользователя доступ будет отклонен. В этом и заключается суть: доступ к root базы данных привязан к sudo в системе, и пароля, который можно украсть, перехватить или подобрать методом перебора, не существует. Это более безопасный метод, чем использование пароля, поэтому не меняйте настройки. Из этого следует правило: никогда не используйте учетную запись root для приложений. Создавайте отдельного пользователя для каждого приложения (Шаг 7), так как приложение, подключающееся через TCP с именем пользователя и паролем, не может использовать socket auth, и вам необходимо ограничить каждое приложение только его собственной базой данных.
Шаг 4 — Установка PHP 8.3 с PHP-FPM
В Ubuntu 24.04 по умолчанию используется PHP 8.3. Установите менеджер процессов FPM и расширения, необходимые типичному приложению:
sudo apt install -y php8.3-fpm php8.3-mysql php8.3-cli \
php8.3-curl php8.3-xml php8.3-mbstring php8.3-zipОбратите внимание на то, чего нет в этом списке: libapache2-mod-php. Этот устаревший пакет встраивает интерпретатор PHP в каждый процесс Apache. Это простое решение, но каждый рабочий процесс несет в себе копию PHP, даже если он обрабатывает статический файл. У них общий жизненный цикл, и этот метод работает только с Apache prefork MPM — самым неэффективным модулем. Вместо этого PHP-FPM запускает PHP как отдельный пул процессов, с которым Apache взаимодействует через сокет. Apache может использовать потоковый event MPM для статических файлов и передавать только PHP-запросы. Пул настраивается независимо от веб-сервера, и та же конфигурация FPM будет работать, если вы позже установите nginx перед Apache. Это стандарт де-факто по веским причинам.
Apache подключается к FPM через модуль proxy_fcgi. Включите его, включите конфигурационный файл, установленный пакетом FPM, и перезапустите сервис:
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.3-fpm
sudo systemctl restart apache2a2enconf php8.3-fpm активирует /etc/apache2/conf-available/php8.3-fpm.conf, который содержит правило маршрутизации PHP-файлов на сокет FPM. Основная часть правила находит любой файл .php и перенаправляет его на сокет по адресу /run/php/php8.3-fpm.sock:
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler "proxy:unix:/run/php/php8.3-fpm.sock|fcgi://localhost"
</FilesMatch>Этот файл не нужно редактировать; он настроен верно. Однако знание пути к сокету поможет вам позже диагностировать ошибки «PHP скачивается вместо выполнения» и «Primary script unknown». Обе ошибки возникают из-за несоответствия настроек сокета или файлов в Apache и FPM.
Шаг 5 — Виртуальный хост на основе имени для вашего приложения
Виртуальный хостинг на основе имени позволяет одному IP-адресу обслуживать множество сайтов; Apache определяет нужный сайт по заголовку Host: в запросе. Создайте директорию для приложения в месте, отличном от стандартной /var/www/html:
sudo mkdir -p /var/www/testapp
sudo chown -R www-data:www-data /var/www/testapp
sudo chmod -R 755 /var/www/testappВажно правильно настроить владельца файлов. В Ubuntu Apache и PHP-FPM работают от имени пользователя www-data, поэтому файлы, которые должен читать веб-сервер, и директории, в которые приложение должно записывать данные (например, папка для загрузок), должны принадлежать пользователю www-data. Если вы планируете редактировать файлы под своей учетной записью, часто файлы принадлежат вам, а ваш пользователь добавляется в группу www-data; для простой установки наиболее предсказуемым вариантом является использование www-data:www-data.
Создайте конфигурацию виртуального хоста в /etc/apache2/sites-available/testapp.conf:
<VirtualHost *:80>
ServerName app.example.com
DocumentRoot /var/www/testapp
<Directory /var/www/testapp>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/testapp-error.log
CustomLog ${APACHE_LOG_DIR}/testapp-access.log combined
</VirtualHost>Укажите ваш реальный домен в параметре ServerName. Директива Options -Indexes запрещает Apache выводить список файлов в директории при отсутствии индексного файла; без неё посетители смогут просматривать ваше дерево исходного кода. Директива AllowOverride All позволяет использовать файл .htaccess, который необходим большинству PHP-приложений для работы «красивых» URL; если ваше приложение его не использует, удалите его в None для небольшого прироста производительности. Включите этот сайт, отключите стандартный, проверьте конфигурацию и перезагрузите сервис:
sudo a2ensite testapp
sudo a2dissite 000-default
sudo apache2ctl configtest
sudo systemctl reload apache2Команда apache2ctl configtest должна вывести Syntax OK. Строка a2dissite 000-default — это параметр, который часто забывают, из-за чего стандартная страница может продолжать отображаться — подробности описаны в разделе с ошибками.
Шаг 6 — Проверка работы PHP и удаление файла проверки
Создайте однострочный PHP-файл в корневом каталоге приложения:
echo "<?php phpinfo();" | sudo tee /var/www/testapp/info.phpПерейдите по адресу http://app.example.com/info.php. Верным результатом является длинная фиолетово-серая таблица PHP Version 8.3.x со списком загруженных модулей, где в строке Server API указано FPM/FastCGI. Эта строка подтверждает, что запросы обрабатываются через PHP-FPM, а не через mod_php.
Сразу после этого удалите файл:
sudo rm /var/www/testapp/info.phpphpinfo() раскрывает точную версию PHP, все загруженные расширения, пути к файлам и детали окружения. Это предоставляет избыточную информацию любому, кто ищет сервер с известными уязвимостями. Данный файл предназначен только для тестирования. Удалите его сразу после просмотра страницы. Если вместо таблицы браузер предложил скачать info.php, значит, PHP не связан с Apache; прежде чем предпринимать дальнейшие действия, перейдите в раздел устранения неисправностей.
Step 7 - Create the app database and a least-privilege user
Open the database as the socket-authenticated root:
sudo mysqlThen create one database and one user scoped to exactly that database:
CREATE DATABASE appdb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON appdb.* TO 'appuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;Three deliberate choices here. utf8mb4 is real four-byte UTF-8 — the old utf8 alias silently truncates emoji and some CJK characters, so always use utf8mb4. The grant is on appdb.*, not *.*: this user can touch its own database and nothing else, so a SQL-injection hole in the app cannot read every other site's tables. And 'appuser'@'localhost' restricts the account to connections originating on the box itself.
Test it as that user:
mysql -u appuser -p appdbIt asks for the password and drops you at a MariaDB [appdb]> prompt. Notice there is no -h flag — leave it off and the client connects over the local Unix socket, which is exactly what MariaDB counts as localhost. One gotcha worth knowing: to MySQL and MariaDB, localhost means the Unix socket and 127.0.0.1 means a TCP connection. On a stock Ubuntu 24.04 MariaDB the server still resolves a TCP connection from 127.0.0.1 back to localhost, so both match the account — but on servers with skip-name-resolve enabled (a common performance tweak, and the norm in many container images), the two are matched as different hosts, and an app that dials 127.0.0.1 is refused with ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' (using password: YES) even when the password is correct.
So point your application at host localhost, user appuser, database appdb — never at root. PHP's mysqli and PDO both switch to the Unix socket when the host is the literal string localhost, matching the account you just created. If a framework insists on a numeric TCP host, create the user to match how it actually connects — 'appuser'@'127.0.0.1', or @'%' (paired with a firewall rule) only if it must reach the database from another machine.
Шаг 8 — Добавление HTTPS с помощью Certbot
Передача формы входа через HTTP отправляет пароли в открытом виде. Современные браузеры помечают такие страницы как «Не защищено». Certbot решает эту проблему одной командой. Установите его вместе с плагином для Apache:
sudo apt install -y certbot python3-certbot-apache
sudo certbot --apacheCertbot использует здесь два плагина. apache authenticator подтверждает ваше владение доменом, временно размещая проверочный файл через работающий Apache. Затем apache installer переписывает конфигурацию вашего virtual host: добавляет блок 443, указывает путь к новому сертификату и настраивает автоматический редирект с HTTP на HTTPS. Начиная с версии Certbot 2.0, вопрос о редиректе не задается; используйте флаг --no-redirect, если вам необходимо оставить поддержку HTTP. Поскольку на шаге 5 вы настроили реальный ServerName, Certbot автоматически определит домен. Срок действия сертификатов составляет 90 дней. Пакет устанавливает таймер systemd для их автоматического обновления; проверить таймер можно с помощью команды sudo certbot renew --dry-run, которая должна завершаться на Congratulations, all simulated renewals succeeded.
Для получения подробной информации о процессе проверки, таймере обновления, а также требованиях к DNS и firewall обратитесь к руководству выпуск бесплатных TLS-сертификатов Let's Encrypt с помощью Certbot на Apache.
Резервное копирование, обновление и защита
Создайте резервные копии двух компонентов, хранящих состояние системы: базы данных и корневой каталог веб-сервера (web root). Самый простой и надежный метод — ежедневный логический дамп: выполните sudo sh -c 'mysqldump --all-databases --single-transaction | gzip > /root/db-$(date +%F).sql.gz', затем скопируйте результат на другой сервер. Важно использовать sudo sh -c для всего процесса: без этого оболочка выполнит перенаправление > /root/... от имени вашего пользователя и завершится ошибкой Permission denied, так как только mysqldump имеет доступ к sudo. --single-transaction позволяет сделать согласованный снимок таблиц InnoDB без блокировки. Используйте этот метод вместе с tar для /var/www и /etc/apache2/sites-available, чтобы вы могли восстановить весь стек на новом VPS из этих файлов.
Обновления системы являются стандартным процессом sudo apt update && sudo apt upgrade. Наиболее сложным этапом является обновление версии PHP. Когда в будущих версиях Ubuntu версия PHP по умолчанию изменится на 8.4, apt может установить php8.4-fpm параллельно с 8.3, сокет изменится на /run/php/php8.4-fpm.sock, а конфигурация Apache по-прежнему будет указывать на сокет 8.3. Включите новый конфигурационный файл (sudo a2enconf php8.4-fpm) и отключите старый, иначе после обычного обновления ваш сайт начнет возвращать ошибку Primary script unknown. Поскольку версии PHP выходят чаще, чем обновления LTS-дистрибутивов, проверяйте актуальные примечания к выпуску PHP вместо фиксации конкретной версии патча.
В первый день работы рекомендуется выполнить два шага по защите системы. Во-первых, установите Fail2Ban для мониторинга SSH — публичные VPS получают автоматизированные попытки входа в течение нескольких минут; небольшая тюрьма (jail) сократит тысячи попыток до нескольких перед блокировкой. Во-вторых, если вы предпочитаете управлять виртуальными хостами Apache, базами данных MariaDB и пользователями через браузер, а не путем ручного редактирования файлов, используйте панель управления Webmin. Она работает с тем же стеком технологий и использует те же конфигурационные файлы, которые вы только что создали. Эти инструменты не заменяют понимание работы компонентов, но упрощают повседневное администрирование.
Режимы сбоев и сообщения об ошибках
Стандартная страница не исчезает. Вы отредактировали virtual host, перезагрузили конфигурацию, но браузер по-прежнему отображает "Apache2 Ubuntu Default Page" и баннер "It works!". Apache отдает первый подходящий virtual host. Если ни один ServerName не соответствует запросу, побеждает первый по алфавиту конфиг — 000-default.conf идет перед testapp.conf. Либо имя хоста в запросе не совпадает с вашим ServerName, либо вы не выполнили sudo a2dissite 000-default. Отключите стандартный конфиг, sudo systemctl reload apache2, и проверьте результат с помощью apache2ctl -S; эта команда выведет карту vhost и покажет, какой конфиг отвечает за дефолтный хост. Также очистите кэш браузера; кэшированный ответ 200 от старой страницы может сохраняться.
.php файл скачивается вместо выполнения. Вы открываете info.php, и браузер скачивает файл с исходным кодом <?php или отображает его как обычный текст вместо выполнения. Apache отдает файл как статический ресурс, потому что обработчик PHP не подключен. Вы пропустили sudo a2enmod proxy_fcgi, sudo a2enconf php8.3-fpm или не перезапустили Apache после этого. Выполните все три шага (Step 4) и перезагрузите страницу. Проверьте, загружен ли модуль с помощью apache2ctl -M | grep fcgi, в списке должен быть proxy_fcgi_module. Это утечка исходного кода, а не косметический баг, поэтому исправьте это перед размещением реальных данных на сервере.
ERROR 1698 (28000): Access denied for user 'root'@'localhost'. Вы запустили mysql -u root или mariadb -u root без sudo. Учетная запись root использует аутентификацию unix_socket, поэтому она принимает вас только если ваш пользователь ОС — это root. Решение — sudo mysql: без -u root и без пароля. Это сообщение является ожидаемым поведением при корректной работе socket auth, а не признаком неисправной установки.
ERROR 1045 (28000): Access denied for user 'appuser'@'127.0.0.1' от приложения при правильном пароле. Учетная запись существует как 'appuser'@'localhost', но ваше приложение подключается по TCP к 127.0.0.1 на сервере, где разрешение имен отключено (skip-name-resolve). Поэтому MariaDB считает их разными хостами: localhost — это Unix socket, а 127.0.0.1 — это TCP. Настройте приложение на хост localhost, чтобы оно использовало сокет и совпадало с учетной записью, либо создайте вторую учетную запись 'appuser'@'127.0.0.1', если фреймворк поддерживает только TCP.
AH01071: Got error 'Primary script unknown' в /var/log/apache2/testapp-error.log, при этом браузер показывает File not found.. Apache передал запрос в PHP-FPM, но FPM не смог найти скрипт по пути, указанному Apache. Две частые причины: сокет FPM в вашей конфигурации указывает на версию PHP, которая не установлена (например, сокет php8.4 после обновления, когда запущена только 8.3), или файла действительно не существует, так как DocumentRoot и реальный каталог не совпадают. Проверьте наличие сокета с помощью ls -l /run/php/, убедитесь, что DocumentRoot соответствует пути к файлу, и перезапустите php8.3-fpm и apache2.
AH00558: apache2: Could not reliably determine the server's fully qualified domain name при каждом перезапуске. Это безобидное предупреждение, а не ошибка — Apache сообщает, что глобальный ServerName не установлен. Отключите его, записав ServerName your.domain в /etc/apache2/conf-available/servername.conf и выполнив sudo a2enconf servername.
(98)Address already in use: AH00072: make_sock: could not bind to address 0.0.0.0:80 при запуске Apache. Другой веб-сервер уже занимает порт 80 — часто это запущенный nginx от предыдущих экспериментов. Найдите его с помощью sudo ss -ltnp | grep :80, затем остановите и отключите другой сервис перед запуском Apache.
FAQ
mod_php или PHP-FPM — что выбрать?
Используйте PHP-FPM. mod_php внедряет интерпретатор в каждый процесс Apache и заставляет использовать медленный prefork MPM. Из-за этого Apache несет нагрузку PHP даже при отдаче статических изображений. PHP-FPM запускает PHP как отдельный пул с независимой настройкой. Apache взаимодействует с ним через сокет, использует более быстрый потоковый event MPM и легко переносится на nginx. Это современный стандарт; mod_php имеет смысл только для устаревших приложений, требующих специфического поведения внутри процесса.
Почему браузер скачивает PHP-файл вместо его выполнения?
Apache обрабатывает .php файл как статический объект для скачивания, так как к нему не привязан обработчик PHP. В Ubuntu 24.04 с FPM это означает, что вы пропустили один из шагов: sudo a2enmod proxy_fcgi, sudo a2enconf php8.3-fpm или перезапуск Apache. Выполните все три действия и перезагрузите сервис, затем проверьте с помощью apache2ctl -M | grep fcgi, что proxy_fcgi_module указан в списке. Пока проблема не решена, сервер раскрывает исходный код, поэтому действуйте незамедлительно.
Почему доступ root в MariaDB запрещен, даже если пароль верный?
Пароль не требуется — MariaDB в Ubuntu аутентифицирует учетную запись root через unix_socket, привязывая ее к пользователю root операционной системы. Команда mysql -u root из обычной оболочки возвращает ERROR 1698 (28000): Access denied for user 'root'@'localhost' по умолчанию. Вместо этого подключайтесь через sudo mysql и создавайте отдельного пользователя с паролем для каждого приложения вместо использования root.
Как добавить HTTPS на сайт LAMP?
Установите certbot и python3-certbot-apache, направьте A-запись домена на сервер, затем запустите sudo certbot --apache. Аутентификатор Apache подтверждает владение доменом через работающий Apache, после чего установщик перенастраивает virtual host для порта 443 и настраивает автоматическое продление. Полное руководство по Certbot и Apache содержит описание процесса, таймера продления и типичных ошибок.