Виртуальные хосты позволяют одному экземпляру Apache обслуживать несколько сайтов, различая их по имени в заголовке Host. В связке с Let’s Encrypt это даёт бесплатный HTTPS, который обновляется автоматически. Ниже — рабочая схема для Debian и Ubuntu: отдельные каталоги сайтов, два виртуальных хоста, выпуск сертификата, включение HTTP/2 и проверка конфигурации. Для RHEL и Fedora пути отличаются, но логика та же.
Как Apache выбирает сайт
Name-based виртуальные хосты появились ещё в HTTP/1.1 и остаются основным способом хостинга. Apache сравнивает значение ServerName и ServerAlias с именем, которое прислал клиент, и берёт первый подходящий блок. Если совпадений нет, отвечает виртуальный хост по умолчанию — тот, что включён первым. Именно поэтому стандартный 000-default.conf часто перехватывает запросы к «неправильному» домену.
ServerName— основное имя сайта.ServerAlias— дополнительные имена, включаяwww.DocumentRoot— каталог с файлами сайта.ErrorLogиCustomLog— журналы конкретного хоста.
Проверить, какой хост достанется домену, можно командой apache2ctl -S. Она печатает карту виртуальных хостов и порядок, в котором они просматриваются. Это первое, что стоит смотреть при жалобе «открывается не тот сайт».
sudo apache2ctl -S
ls /etc/apache2/sites-available
systemctl status apache2 --no-pager
Подготовка каталогов
Для каждого сайта создают отдельный каталог вне /var/www/html, чтобы обновление пакета не затронуло файлы. Владельцем удобно сделать пользователя, который раскладывает файлы, а группу оставить www-data.
sudo mkdir -p /var/www/example.com/public_html
sudo chown -R "$USER":www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com
echo '<h1>example.com</h1>' | sudo tee /var/www/example.com/public_html/index.html
Права 755 на каталоги и 644 на файлы — достаточный минимум. Не стоит выдавать 777 «чтобы работало»: Apache отдаёт статику от имени www-data, и лишние права лишь расширяют поверхность атаки. Если сайт пишет в каталог, например загружает файлы, права дают точечно на конкретную папку.
HTTP-хост и перенаправление
Конфигурацию кладут в /etc/apache2/sites-available/example.com.conf. Сначала создают блок на порту 80, который сразу перенаправляет на HTTPS: так пользователь не попадёт на незашифрованную версию и не сохранит её в закладки.
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
После правки файл включают командой a2ensite, проверяют синтаксис через apache2ctl configtest и перезагружают службу. reload предпочтительнее restart: он не рвёт активные соединения.
sudo a2ensite example.com.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
Если configtest пишет Syntax OK, но сайт не открывается, проверяют DNS: запись A должна указывать на этот сервер, а запись AAAA — не вести на чужой адрес. Ошибка в AAAA встречается часто и выглядит как «сайт открывается через раз».
HTTPS и сертификат
Самый короткий путь — Certbot с плагином Apache. Он сам добавит блок на порту 443, пропишет пути к сертификату и настроит перенаправление. Перед запуском убеждаются, что порт 80 доступен снаружи: проверка домена идёт по HTTP.
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d example.com -d www.example.com
sudo certbot renew --dry-run
Certbot создаёт отдельный файл example.com-le-ssl.conf и подключает options-ssl-apache.conf с разумными параметрами TLS. Если сертификат нужно выпустить вручную, блок на 443 описывают самостоятельно: модуль ssl включают через a2enmod, а пути указывают на live-каталог, который обновляется сам.
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/public_html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
ErrorLog ${APACHE_LOG_DIR}/example.com-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-access.log combined
</VirtualHost>
Ссылаться на archive вместо live нельзя: при обновлении сертификата там появляются новые файлы с суффиксом версии, и Apache продолжит отдавать старый. Каталог live содержит символические ссылки, которые Certbot переключает автоматически.
Заголовки безопасности и HTTP/2
После включения HTTPS имеет смысл добавить HSTS — заголовок, который заставляет браузер обращаться к сайту только по защищённому протоколу. Начинают с небольшого max-age, чтобы можно было откатиться, и только потом увеличивают до года.
sudo a2enmod headers http2
sudo a2enconf security
В конфигурации хоста добавляют заголовки и включают протокол:
Header always set Strict-Transport-Security "max-age=300; includeSubDomains"
Header always set X-Content-Type-Options "nosniff"
Protocols h2 http/1.1
includeSubDomains действует на все поддомены, поэтому включать его стоит только тогда, когда все они уже работают по HTTPS. HTTP/2 даёт мультиплексирование и меньшее число соединений; проверить его можно через curl, который покажет версию протокола в выводе.
curl -sI https://example.com | head -n 5
curl -sI --http2 https://example.com | grep -i "HTTP/2"
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates -subject
Вывод openssl показывает даты действия и имя, на которое выписан сертификат. Если имя не совпадает с доменом, браузер выдаст предупреждение, даже когда сам сертификат валиден. Для проверки цепочки полезно добавить -showcerts и посмотреть, не оборвана ли она на промежуточном сертификате.
Диагностика
Основные причины проблем: синтаксис конфигурации, права на файлы, занятый порт и неверный DNS. Порядок проверки простой — синтаксис, затем порты, затем журналы.
sudo apache2ctl configtest
sudo ss -tlnp | grep -E ':(80|443)'
sudo tail -n 50 /var/log/apache2/example.com-error.log
sudo journalctl -u apache2 -n 50 --no-pager
Ошибка 403 почти всегда означает права или отсутствие Require all granted в блоке <Directory>. Ошибка 404 — неверный DocumentRoot или опечатка в имени файла. Если сайт открывается по IP, но не по домену, смотрят apache2ctl -S и порядок включённых сайтов: возможно, запрос забирает другой хост.
На системах с SELinux, например в Fedora, файлы вне стандартных каталогов требуют отдельного контекста. Его выставляют через semanage fcontext и restorecon, а проверяют по audit.log. Без этого Apache получает отказ в доступе, хотя обычные права выставлены верно.
Итог
Схема с отдельным файлом на сайт, a2ensite и Certbot остаётся самой предсказуемой для небольших проектов. Ключевые привычки: проверять конфигурацию перед перезагрузкой, не трогать live-каталог Certbot вручную и смотреть журналы конкретного хоста, а не общий. После базовой настройки стоит добавить HSTS, HTTP/2 и регулярную проверку срока сертификата.