Голый HTTP в 2026 году - это путь к плашке Not secure в браузере и отказу любого современного клиента. Задача администратора - научить Apache отдавать сайт по TLS: подключить ключ и сертификат, собрать корректную цепочку, разрешить только безопасные протоколы, развести несколько сайтов на одном IP через SNI и автоматически выпускать сертификаты через Let's Encrypt. В этом уроке разбираем mod_ssl от приватного ключа до certbot, с акцентом на то, что именно происходит при рукопожатии.

Как это работает
TLS решает три вещи: шифрование канала, целостность данных и подтверждение, что вы говорите именно с тем хостом, чьё имя в адресной строке. Подтверждение строится на паре ключей. Приватный ключ хранится только на сервере и никогда не покидает его. Публичный ключ зашит в сертификат, который подписан удостоверяющим центром (CA). Браузер доверяет CA, поэтому доверяет и подписанному им сертификату.
Сертификат сервера почти никогда не подписан корневым CA напрямую. Между ними стоят промежуточные сертификаты. Чтобы клиент смог построить путь доверия от вашего сертификата до корня в своём хранилище, сервер обязан прислать всю цепочку промежуточных звеньев. Корень слать не нужно - он уже есть у клиента. Если промежуточное звено забыть, часть клиентов (особенно мобильные и curl без системных CA) выдадут ошибку доверия, хотя в браузере на десктопе всё может казаться рабочим.
Рукопожатие начинается с ClientHello, где клиент в расширении SNI открытым текстом сообщает имя хоста, к которому подключается. Это ключевой момент: до SNI один IP мог обслуживать только один HTTPS-сайт, потому что сервер не знал, какой сертификат показать, пока не расшифрует запрос - а расшифровать нельзя без правильного сертификата. SNI разрывает этот замкнутый круг: имя приходит до выбора сертификата, и Apache по нему выбирает нужный VirtualHost ещё до согласования ключей.
Протокол и набор шифров стороны выбирают в начале рукопожатия. Актуальны TLS 1.2 и TLS 1.3, всё что ниже - выключено и небезопасно. TLS 1.3 сам по себе использует только сильные шифронаборы, так что тонкая настройка ciphers касается в основном TLS 1.2. В Apache за это отвечают SSLProtocol и SSLCipherSuite.
Команды и примеры
Имена модуля и пакетов различаются. В Debian и Ubuntu сервис называется apache2, модуль включается через a2enmod. В RHEL и Fedora сервис httpd, mod_ssl ставится отдельным пакетом.
Код: Выделить всё
# Debian 13 / Ubuntu 24.04
apt install apache2
a2enmod ssl
a2ensite default-ssl
systemctl reload apache2
# RHEL 10 / Fedora 41+
dnf install httpd mod_ssl
systemctl enable --now httpd
Код: Выделить всё
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout /etc/ssl/private/site.key \
-out /etc/ssl/certs/site.crt \
-days 365 -subj "/CN=example.org"
Код: Выделить всё
<VirtualHost *:443>
ServerName example.org
DocumentRoot /var/www/example
SSLEngine on
SSLCertificateFile /etc/ssl/certs/site.crt
SSLCertificateKeyFile /etc/ssl/private/site.key
SSLCertificateChainFile /etc/ssl/certs/intermediate.crt
SSLProtocol -all +TLSv1.2 +TLSv1.3
SSLCipherSuite HIGH:!aNULL:!MD5:!3DES
SSLHonorCipherOrder on
</VirtualHost>
SNI работает прозрачно: достаточно нескольких VirtualHost на *:443 с разными ServerName и своими сертификатами. Apache сам сопоставит имя из ClientHello с нужным блоком.
Перенаправление HTTP на HTTPS делается в отдельном виртуалхосте на 80 порту. Через mod_rewrite или, чище, через Redirect:
Код: Выделить всё
<VirtualHost *:80>
ServerName example.org
Redirect permanent / https://example.org/
</VirtualHost>
Код: Выделить всё
# Debian / Ubuntu
apt install certbot python3-certbot-apache
certbot --apache -d example.org -d www.example.org
# RHEL / Fedora
dnf install certbot python3-certbot-apache
certbot --apache -d example.org
Код: Выделить всё
systemctl list-timers certbot.timer
certbot renew --dry-run
Код: Выделить всё
openssl s_client -connect example.org:443 -servername example.org
apachectl configtest
Частые грабли
- Забыта цепочка промежуточных сертификатов. В десктопном браузере всё зелёное, а curl, мобильные приложения и платёжные шлюзы ругаются на untrusted. Всегда проверяйте через openssl s_client с чистой машины.
- Перепутаны местами ключ и сертификат в директивах, либо ключ не соответствует сертификату. Apache не стартует с key values mismatch. Сверьте модули: openssl x509 -noout -modulus -in cert и openssl rsa -noout -modulus -in key должны совпадать.
- Listen 443 не объявлен или модуль ssl не включён - VirtualHost на 443 просто игнорируется, сайт открывается по 80.
- NameVirtualHost и SNI: на старых конфигах люди до сих пор тащат директиву NameVirtualHost, в Apache 2.4 она удалена и вызывает предупреждение.
- Слишком агрессивный SSLCipherSuite режет старые клиенты, слишком мягкий оставляет дыры. Не копируйте древние строки шифров из интернета - они часто включают уязвимые наборы.
- Certbot не может пройти HTTP-01, потому что редирект 80 на 443 ловит и запрос на /.well-known/. Исключайте этот путь из редиректа либо используйте webroot-плагин.
- Права на приватный ключ. Файл в /etc/ssl/private должен быть 0600 и принадлежать root, иначе либо утечка, либо Apache не сможет его прочитать.
- Поднимите Apache (apache2 или httpd) и включите mod_ssl.
- Сгенерируйте самоподписанный сертификат и ключ командой openssl req выше.
- Опишите два VirtualHost на *:443 с разными ServerName (например a.test и b.test через /etc/hosts) и разными сертификатами.
- Проверьте, что SNI работает: openssl s_client -connect 127.0.0.1:443 -servername a.test и -servername b.test должны вернуть разные CN.
- Добавьте VirtualHost на *:80 с Redirect permanent на https.
- Ограничьте SSLProtocol только TLSv1.2 и TLSv1.3, перезагрузите конфиг через apachectl configtest и reload.
- По желанию: на публичном домене выпустите реальный сертификат через certbot --apache и прогоните certbot renew --dry-run.
- Зачем сервер обязан отдавать промежуточные сертификаты и почему корневой слать не нужно?
- Какое расширение TLS позволяет держать несколько HTTPS-сайтов на одном IP и в какой момент рукопожатия оно передаётся?
- Чем SSLCertificateChainFile отличается от объединённого PEM в SSLCertificateFile и какой способ современный?
- Как директивами Apache разрешить только TLS 1.2 и 1.3 и отключить всё остальное?
- Какой плагин certbot правит конфиг Apache автоматически и как проверить обновление без реального перевыпуска?
- Почему редирект всего трафика с 80 на 443 может сломать выпуск сертификата по HTTP-01?