Можно ли настроить универсальный (по умолчанию) HTTPS Vhost на Apache 2.4? В настоящее время у меня есть 4 домена, и HTTP перехватывает все, но как только я пытаюсь добавить какую-либо конфигурацию, мои другие vhosts ломаются. Вот как выглядит моя конфигурация:
<VirtualHost _default_:80>
# Default catch-all virtual host.
Redirect permanent / https://example-prod.com
</VirtualHost>
<VirtualHost _default_:80>
ServerName example-prod.com
ServerName www.example-prod.com
Include conf/sites/example-prod.com.conf
</VirtualHost>
<VirtualHost _default_:80>
ServerName example-dev.com
Include conf/sites/example-dev.com.conf
</VirtualHost>
#
# This is the virtual host I'm missing and that I cannot get to work.
#
#<VirtualHost _default_:443>
# # Default catch-all virtual host.
# ServerAlias *
# SSLEngine on
# SSLCertificateFile "C:/prod/hosts.crt.pem"
# SSLCertificateKeyFile "C:/prod/hosts.key.pem"
# SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
# Redirect permanent / https://example-prod.com
#</VirtualHost>
<VirtualHost _default_:443>
ServerName example-prod.com
ServerName www.example-prod.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Include conf/sites/example-prod.com.conf
</VirtualHost>
<VirtualHost _default_:443>
ServerName example-dev.com
SSLEngine on
SSLCertificateFile "C:/dev/hosts.crt.pem"
SSLCertificateKeyFile "C:/dev/hosts.key.pem"
SSLCertificateChainFile "C:/dev/intermediate.crt.pem"
Include conf/sites/example-dev.com.conf
</VirtualHost>
В моем httpd.conf больше нет DocumentRoot
- все есть в хосте и включает. Это тоже выделенный сервер и IP.
Как я могу решить эту проблему?
Проблема была решена, но возникли недоразумения. Действительно существует требование, чтобы HTTPS нуждался в соответствующем сертификате, но проблема, вызванная этим, заключается в том, что соединение не будет доверенным, если имя хоста не соответствует сертификатам. Распространенное имя или перечислен в Альтернативное имя субъекта:
Такое же несоответствие сохраняется даже с RewriteRule
решение, данное в другом ответе.
Если "универсальные" имена хостов являются субдоменами example.com
и у вас есть подстановочный сертификат для *.example.com
, он будет соответствовать.
С другой стороны, большинство людей, пытаясь получить доступ something.example.com
, вводит его в адресную строку браузера без http://
или https://
префикс, а браузеры по умолчанию используют HTTP. Таким образом, наличие "всеобъемлющего" перенаправления на HTTPS даже с несоответствующим сертификатом обычно не вызывает реальных проблем: лишь немногие люди когда-либо видят SSL_ERROR_BAD_CERT_DOMAIN
ошибка.
В Сопоставление виртуального хоста работает одинаково с TLS или без него.
Если у вас нет SNI:
Первый виртуальный хост на основе имени в файле конфигурации для данного
IP:port
пара важна, потому что она используется для всех запросов, полученных на этот адрес и порт, для которых нет другого виртуального хоста для этогоIP:port
пара имеет соответствиеServerName
илиServerAlias
. Он также используется для всех SSL-соединений, если сервер не поддерживает Индикация имени сервера.
Без SNI сертификат с первого VirtualHost
используется для рукопожатия:
На самом деле Apache позволит вам настраивать виртуальные хосты SSL на основе имен, но он всегда будет использовать конфигурацию виртуального хоста, указанного первым (на выбранном IP-адресе и порту), для настройки уровня шифрования.
Основная проблема с вашей первоначальной попыткой заключалась в том, что ServerAlias *
и не имея никаких ServerName
. Для универсального хоста он работал бы с все, кроме другой ServerName
s от других VirtualHost
с. Если другого совпадения нет, Apache возвращается к значениям по умолчанию VirtualHost
раздел; в зависимости от того, какой из разделов является первым (который соответствует поиску по IP, когда поиск по имени не выполняется).
Виртуальные хосты на основе имен для наиболее подходящего набора
<virtualhost>
s обрабатываются в том порядке, в котором они появляются в конфигурации. Первое совпадениеServerName
илиServerAlias
используется без разницы в приоритете для подстановочных знаков (ни дляServerName
vs.ServerAlias
).
Должно быть НЕКОТОРЫЕ ServerName
так как:
В
ServerName
Директива может появиться где угодно в определении сервера. Однако каждый внешний вид отменяет предыдущий внешний вид (на этом сервере).Если нет
ServerName
указано, сервер пытается определить видимое клиентом имя хоста, сначала запрашивая у операционной системы имя хоста системы, а если это не удается, выполняет обратный поиск по IP-адресу, присутствующему в системе.
Это приведет к такой конфигурации:
<VirtualHost *:443>
# Default catch-all (everything that won't match the following VirtualHosts)
ServerName catch-all.example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Redirect permanent / https://example.com
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Include conf/sites/example.com.conf
</VirtualHost>
<VirtualHost *:443>
ServerName dev.example.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Include conf/sites/dev.example.com.conf
</VirtualHost>
Обратите внимание на другие вещи, которые я изменил:
dev.example.com
использует тот же сертификат, что и без SNI.Использовать <VirtualHost *:443>
вместо того _default_:443
так как _default_
имеет специальное назначение:
Любой vhost, включающий магию
_default_
подстановочному знаку дается то же имя сервера, что и у основного сервера.
(Это также означает, что можно использовать _default_:443
в вашем «уловке», а не в других. Можешь попробовать!)
Домен заменяется на Зарезервированные примеры доменных имен.
Я бы предпочел иметь www.example.com
как часть "всеобъемлющего" (а не как псевдоним), чтобы иметь только один канонический адрес для вашего сайта. Поэтому я перенес его туда.
Если у тебя есть SNI, обработка имитирует то же поведение, но немного отличается в деталях:
Прежде чем произойдет даже подтверждение SSL, Apache находит наилучшее соответствие для IP-адреса и TCP-порта, на котором установлено соединение (виртуальный хостинг на основе IP)
Если есть
NameVirtualHost
директива, имеющая те же буквальные аргументы, что и эта наиболее подходящаяVirtualHost
, Apache вместо этого будет рассматривать ВСЕVirtualHost
записи с идентичными аргументами для сопоставленного VirtualHost. В противном случае обработка SNI не требует выбора.Если клиент отправляет имя хоста вместе со своим запросом подтверждения TLS, Apache сравнивает это имя хоста TLS с
ServerName
/ServerAlias
кандидатаVirtualHost
набор, определенный на предыдущих шагах.Какой бы VirtualHost ни был выбран на предыдущей основе, будет использоваться его SSL-конфигурация для продолжения подтверждения. Примечательно, что содержание сертификатов не используется ни для какого сравнения.
С SNI вы можете получить дополнительный сертификат для dev.example.com
.
Если все предпосылки для SNI соблюдены, он должен работать автоматически и error.log
покажет [warn] Init: Name-based SSL virtual hosts only work for clients with TLS server name indication support (RFC 4366)
.
Хотя можно перенаправить весь неизвестный трафик HTTPS на определенный виртуальный хост, Apache не упростил эту задачу:
ServerName
, которого у нас нет для универсального хоста. Это требование HTTPS, поскольку сертификаты обычно связаны с хостами (ServerName
или ServerAlias
).ServerName
заявления в некотором VirtualHost). Я хотел бы немного подробнее разобраться в деталях, но вопрос не в этом.Исходя из этого, есть два решения. Я предпочитаю первый, поскольку он, вероятно, более масштабируемый (нет необходимости обновлять исключения), а также производительность (нет необходимости использовать дополнительные модули).
Поймать все с использованием поддельного ServerName (предложено Эсой)
#
# Catch-all virtual hosts.
#
<VirtualHost _default_:80>
# Default catch-all virtual host.
Redirect permanent / https://example-prod.com
</VirtualHost>
<VirtualHost _default_:443>
ServerName catch-all
SSLEngine on
SSLCertificateFile "C:/dev/hosts.crt.pem"
SSLCertificateKeyFile "C:/dev/hosts.key.pem"
SSLCertificateChainFile "C:/dev/intermediate.crt.pem"
Redirect permanent / https://example-prod.com
</VirtualHost>
#
# Real virtual hosts.
#
<VirtualHost _default_:80>
ServerName example-prod.com
ServerAlias www.example-prod.com
Include conf/sites/example-prod.com.conf
</VirtualHost>
<VirtualHost _default_:80>
ServerName example-dev.com
Include conf/sites/example-dev.com.conf
</VirtualHost>
<VirtualHost _default_:443>
ServerName example-prod.com
ServerAlias www.example-prod.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Include conf/sites/example-prod.com.conf
</VirtualHost>
<VirtualHost _default_:443>
ServerName example-dev.com
SSLEngine on
SSLCertificateFile "C:/dev/hosts.crt.pem"
SSLCertificateKeyFile "C:/dev/hosts.key.pem"
SSLCertificateChainFile "C:/dev/intermediate.crt.pem"
Include conf/sites/example-dev.com.conf
</VirtualHost>
mod_rewrite (предложено Алексисом)
<VirtualHost _default_:80>
# Default catch-all virtual host.
Redirect permanent / https://example-prod.com
</VirtualHost>
<VirtualHost _default_:80>
ServerName example-prod.com
ServerName www.example-prod.com
Include conf/sites/example-prod.com.conf
</VirtualHost>
<VirtualHost _default_:80>
ServerName example-dev.com
Include conf/sites/example-dev.com.conf
</VirtualHost>
<VirtualHost _default_:443>
ServerName example-prod.com
ServerName www.example-prod.com
SSLEngine on
SSLCertificateFile "C:/prod/hosts.crt.pem"
SSLCertificateKeyFile "C:/prod/hosts.key.pem"
SSLCertificateChainFile "C:/prod/intermediate.crt.pem"
Include conf/sites/example-prod.com.conf
# Default catch-all HTTPS virtual host.
# Make sure to add all valid SSL domains on this host to avoid conflicts.
RewriteEngine on
RewriteCond %{HTTP_HOST} !^example-prod\.com$ [NC]
RewriteCond %{HTTP_HOST} !^www\.example-prod\.com$ [NC]
RewriteCond %{HTTP_HOST} !^example-dev\.com$ [NC]
RewriteRule .* https://example-prod [R=permanent,L]
</VirtualHost>
<VirtualHost _default_:443>
ServerName example-dev.com
SSLEngine on
SSLCertificateFile "C:/dev/hosts.crt.pem"
SSLCertificateKeyFile "C:/dev/hosts.key.pem"
SSLCertificateChainFile "C:/dev/intermediate.crt.pem"
Include conf/sites/example-dev.com.conf
</VirtualHost>
Теперь почему что-то настолько простое и такое сложное? Есть ли у Apache признаки возраста? По крайней мере, есть способы решить эту ситуацию.
HTTPS требует доменного имени, которое соответствует сертификату, поэтому *:443
без соответствующего ServerName
не имеет смысла.
Однако вы можете использовать перенаправление в другом <VirtualHost>
записи, с RewriteRule
.
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(something-else.example-prod.com|whatever.example-prod.com|...others...)$
RewriteRule ^/(.*) https://www.example-prod.com/$1 [R=permanent,L]
Вы хотите условие (RewriteCond
), который проверяет, что только указанные домены получают перенаправление должным образом. Вы должны знать все возможные имена, хотя, если вы динамически добавляете новые доменные имена, надеюсь, вы можете использовать регулярное выражение, которое соответствует всем этим динамическим поддоменам.