Можно ли настроить универсальный (по умолчанию) 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
- все находится в vhost и включает. Это тоже выделенный сервер и IP.
Как я могу решить эту проблему?
Проблема была решена, но возникли недоразумения. Действительно существует требование, чтобы HTTPS нуждался в соответствующем сертификате, но проблема, вызванная этим, заключается в том, что соединение не будет доверенным, если имя хоста не соответствует сертификату Общее имя или указано в Альтернативное имя субъекта :
Такое же несоответствие сохраняется даже с решением RewriteRule
, указанным в другом ответе.
Если «универсальные» имена хостов являются субдоменами example.com
и у вас есть подстановочный сертификат для *. Example.com
, он будет соответствовать.
С другой стороны, большинство людей при попытке доступа к something.example.com
, вводит его в адресную строку браузера без префикса http: //
или https: //
, а браузеры по умолчанию используют HTTP. Таким образом, «всеобъемлющее» перенаправление на HTTPS даже с несовпадающим сертификатом обычно не вызывает реальных проблем: лишь немногие люди когда-либо видят ошибку SSL_ERROR_BAD_CERT_DOMAIN
.
Сопоставление виртуальных хостов работает одинаково с TLS или без него.
Если у вас нет SNI :
Первый виртуальный хост на основе имени в файле конфигурации для данного Пара
IP: порт
важна, потому что она используется для всех запросов. получен на тот адрес и порт, для которых нет другого vhost для этогоIP: пара портов
имеет совпадающиеServerName
илиServerAlias
. Он также используется для всех SSL-соединений, если сервер не поддерживает Индикация имени сервера .
Без SNI сертификат из первого VirtualHost
используется для рукопожатия:
На самом деле Apache позволяет настраивать на основе имени SSL виртуальный хостов, но он всегда будет использовать конфигурацию из первых в списке виртуальный хост (на выбранном IP-адресе и порту) для настройки уровень шифрования.
Основная проблема с вашей первоначальной попыткой заключалась в наличии ServerAlias *
и отсутствии ServerName
. Для универсального хоста он работал бы с чем угодно, кроме других ServerName
из других VirtualHost
s. Если другого совпадения нет, Apache возвращается к разделу по умолчанию VirtualHost
; в зависимости от того, какой из разделов является первым (который соответствует поиску на основе IP-адреса, когда поиск на основе имени не выполняется).
Виртуальные хосты на основе имени для наилучшего -соответствующий набор из
s обрабатываются в том порядке, в котором они появляются в конфигурации. Первый используется сопоставление
ServerName
илиServerAlias
, без отличий приоритет для подстановочных знаков (ни дляServerName
по сравнению с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. Используйте
вместо _default_: 443
как _default_
имеет особое назначение:
Любой виртуальный хост, включает волшебный подстановочный знак
_default_
. ServerName в качестве основного сервера.
(Это также означает, что вы можете использовать _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: виртуальные хосты SSL на основе имени работают только для клиентов с поддержкой указания имени сервера TLS (RFC 4366)
.
Хотя можно перенаправить весь неизвестный трафик HTTPS на конкретный виртуальный хост, Apache не упростил эту задачу:
ServerName
, которое у нас нет универсального хозяина. Это требование HTTPS, поскольку сертификаты обычно связаны с хостами ( ServerName
или ServerAlias
). ServerName
операторов в некоторых VirtualHost). Мне бы хотелось подробнее разобраться в деталях, но вопрос не в этом.На основании этого есть два решения. Я предпочитаю первый, поскольку он, вероятно, более масштабируемый (нет необходимости обновлять исключения), а также производительность (нет необходимости использовать дополнительные модули).
Всеобщее использование поддельного ServerName (предложено Esa)
#
# 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
не имеет смысла.
Однако , вы можете использовать перенаправление в других своих записях
с 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
), которое проверяет только это указанные домены получают перенаправление, как ожидалось. Вы должны знать все возможные имена, хотя, если вы динамически добавляете новые доменные имена, надеюсь, вы сможете использовать регулярное выражение, которое соответствует всем этим динамическим поддоменам.