Я хотел бы создать среду, в которой виртуальные хосты Apache могут создаваться динамически без перезагрузки конфигурации.
Я могу сделать это с mod_vhost_alias, Я настроил свой виртуальный хост по умолчанию примерно так
<VirtualHost *>
UseCanonicalName Off
VirtualDocumentRoot /var/www/sandboxes/domains/%0
ServerName catchall.host
</VirtualHost>
Это работает нормально, но если делается запрос для имени хоста, которое в настоящее время не настроено, я получаю ошибку 404 Not Found.
Что бы я действительно хотел бы сделать только этот VirtualHost только если корень документа существует, в противном случае пусть он попытается сопоставить другой виртуальный хост (другими словами, сделайте наличие VirtualDocumentRoot работают так же, как при использовании ServerAlias)
Я попытался сделать это вторым виртуальным хостом, причем первый виртуальный хост просто обрабатывал все запросы, но это не сработало - запросы для доменов, для которых был настроен VirtualDocumentRoot, пропускались к виртуальному хосту по умолчанию.
Итак, как я могу динамически сконфигурировать vhosts, но с откатом на другой vhost для любого, который еще не настроен?
Я нашел обходной путь, который мне подходит.
Я могу использовать ErrorDocument чтобы обнаружить ошибку 404 в сценарии PHP. Поначалу это казалось проблематичным. Если нет DocumentRoot, где будет жить скрипт?
Я мог бы использовать URL-адрес для сообщения об ошибке, полученного из другого домена. Однако во время тестирования я не нашел способа узнать, какой домен был запрошен изначально.
Ответ был на Псевдоним каталог и обрабатывать ошибки из него, поэтому мой vhost выглядит так
<VirtualHost *>
UseCanonicalName Off
VirtualDocumentRoot /var/www/sandboxes/domains/%0
ServerName catchall.host
Alias /errors /var/www/default/errors/
ErrorDocument 404 /errors/notfound.php
</VirtualHost>
Теперь, когда запрашивается ненастроенный домен, вместо него вызывается скрипт /var/www/default/errors/notfound.php. Этот сценарий может проверить $ _SERVER ['HTTP_HOST'], чтобы узнать, какой домен был запрошен. Если он действительно настроен, то у нас есть обычный 404. Если он не настроен, мы можем отобразить другое сообщение об ошибке. В моем случае здесь я показываю пользовательский интерфейс, который помогает настроить виртуальный хост.
Я нашел ваш вопрос, когда погуглил. У меня была точно такая же проблема, и я применил исправление, как описано в Ответ Павла. Однако для моего сложного веб-приложения я не был доволен маршрутизацией всех запросов через один notfound.php
.
В конце концов, мне удалось решить проблему без внешних скриптов, только отредактировав мою конфигурацию VirtualHost.
Сначала мой VirtualHost был настроен так:
<VirtualHost *:80>
Usecanonicalname Off
Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/
</VirtualHost>
У меня были URL-адреса вроде client1.domainname.com
, client2.domainname.com
и whatever.domainname.com
который решил /mnt/ramdisk/www/cms-client1-development/
, /mnt/ramdisk/www/cms-client2-development/
и /mnt/ramdisk/www/cms-whatever-development/
Однако URL вроде nonexistent.domainname.com
даст мне 404, потому что каталог /mnt/ramdisk/www/cms-nonexistent-development/
не существует. Я хотел, чтобы эти поддомены использовали каталог /mnt/ramdisk/www/cms-default-development/
Я исправил это, используя ModRewrite
и ModProxy
:
<VirtualHost *:80>
Usecanonicalname Off
Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.domainname\.com$ [NC]
RewriteCond /mnt/ramdisk/www/cms-%1-development/ !-d
RewriteRule (.*) http://default.domainname.com/$1 [P,L]
</VirtualHost>
Что это значит: захватить поддомен (часть перед .domainname.com
), вставьте это в путь (% 1) и прокси-запросы к URL-адресу по умолчанию только если каталог не существует.
Используя прокси, процесс прозрачен, и пользователь думает, что он посещает http://nonexistent.domainname.com, в то время как он фактически просматривает контент из http://default.domainname.com/.
Я также столкнулся с этим вопросом в Google для apache2 динамический резервный хост vhost и ответ Люка очень помог мне в решении моей проблемы, но я все еще хочу показать, что я сделал для достижения своих целей, главным образом потому, что это потребовало дополнительных работ и потому, что я думаю, что это может быть полезно для любых будущих гуглеров ...
Мои цели
foo.com
должен обслуживать тот же контент, что и www.foo.com
foo.com
к www.foo.com
если только www
недоступно, вместо этого вернуться к умолчаниюDNS
У меня есть несколько доменов (и все их поддомены), указывающих на мой VPS, например:
Файловая система
У меня есть следующие каталоги, домены содержат каталоги с именами доступных поддоменов, требуется каталог www, но конфигурация должна иметь возможность справиться с ситуацией, когда его нет. Localhost используется как резервный вариант по умолчанию:
/var
/www
/localhost
/foo.com
/www
/bar
/bar.com
/foo
Тесты
Перевод моих целей в проверяемые примеры:
Решение
Это использует: mod_rewrite
, mod_proxy_http
и конечно mod_vhost_alias
.
ServerName my.domain
ServerAdmin admin@my.domain
<VirtualHost *:80>
ServerName localhost
VirtualDocumentRoot /var/www/localhost
</VirtualHost>
<VirtualHost *:80>
ServerName sub.domain
ServerAlias *.*.*
VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
RewriteCond /var/www/%2.%3 !-d
RewriteRule (.*) http://localhost/$1 [P]
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
RewriteCond /var/www/%2.%3/%1 !-d
RewriteCond /var/www/%2.%3/www !-d
RewriteRule (.*) http://localhost/$1 [P]
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
RewriteCond /var/www/%2.%3/%1 !-d
RewriteRule (.*) http://%2.%3/$1 [P]
</VirtualHost>
<VirtualHost *:80>
ServerName bare.domain
ServerAlias *.*
VirtualDocumentRoot /var/www/%-2.0.%-1.0/www
RewriteEngine on
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)$ [NC]
RewriteCond /var/www/%1.%2 !-d [OR]
RewriteCond /var/www/%1.%2/www !-d
RewriteRule (.*) http://localhost/$1 [P]
</VirtualHost>
Как это работает? Определены три виртуальных хоста:
localhost
По умолчанию используется localhost. Все неразрешимые запросы обслуживаются localhost. Настройка символической ссылки с localhost на любой из ваших доменов аналогична настройке этого сайта по умолчанию.
субдомен
Поддомен vhost принимает все запросы в виде *.*.*
. По умолчанию все запросы обслуживаются из /domain.com/sub
как определено VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
.
отступать:
Первый RewriteRule
заботится о неизвестных доменах, например. domain.com
каталог не существует, проксируя веб-сайт localhost.
Второй RewriteRule
также прокси к localhost, когда оба domain.com/sub
и domain.com/www
справочников нет.
Третий RewriteRule
прокси для domain.com
когда domain.com/sub
не существует. Мы знаем domain.com/www
существует из-за второго блока перезаписи.
bare.domain
Виртуальный хост bare.domain принимает *.*
просит и обслуживает их /domain.com/www
Здесь RewriteRule
будет прокси на localhost, когда domain.com
или domain.com/www
не существует.
^ $%. * !!!
У меня были проблемы с осознанием всех этих $
и %
знаки в RewriteCond
и RewriteRule
поэтому я объясню о них здесь:
ServerAlias *.*.*
VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
RewriteCond %{HTTP_HOST} ^(.*)\.(.*)\.(.*)$ [NC]
RewriteCond /var/www/%2.%3/%1 !-d
RewriteRule (.*) http://%2.%3/$1 [P]
*
в ServerAlias
это просто символы подстановки.%n
в VirtualDocumentRoot
из интерполяция названия документа.%n
во-вторых RewriteCond
обратитесь к выбору (.*)
от первой RewriteCond
, например. части запрашиваемого домена.%n
в RewriteRule
тоже.$1
в RewriteRule
относится к выбору (.*)
в начале RewriteRule
. Которая захватывает все, от домена до ?
в URL-адресе запроса. Любая строка запроса автоматически добавляется к URL-адресу mod_proxy
.Просто выбросив его туда, я получаю тот же результат (без перенаправления localhost), что и RemyNL, но также включаю IP-адрес при прямом подключении:
<VirtualHost _default_:80>
RewriteEngine On
RewriteCond %{HTTPS} Off [OR]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^/(.*) https://%{HTTP_HOST}/$1 [NC,R=301,L]
</VirtualHost>
<VirtualHost _default_:443>
ServerName a.b.c.d
ServerAlias *.*.*.*
VirtualDocumentRoot /var/www/%0
</VirtualHost>
<VirtualHost _default_:443>
ServerName a.b.c
ServerAlias *.*.*
VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3
</VirtualHost>
<VirtualHost _default_:443>
ServerName a.b
ServerAlias *.*
VirtualDocumentRoot /var/www/%-2.0.%-1.0/www
</VirtualHost>