Usando VirtualDocumentRoot * somente * se existir uma raiz de documento adequada

8

Gostaria de criar um ambiente onde os hosts virtuais do Apache possam ser criados dinamicamente sem recarregar a configuração.

Eu posso fazer isso com mod_vhost_alias , configurei meu host virtual padrão como este

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
</VirtualHost>

Isso funciona muito bem, mas se uma solicitação for feita para um nome de host que não está configurado no momento, recebo um erro 404 Not Found.

O que eu realmente gostaria de fazer é apenas ter o VirtualHost chutando somente se a raiz do documento existir; caso contrário, tente corresponder a outro vhost (em outros palavras, fazer com que a presença do VirtualDocumentRoot funcione da mesma forma que um ServerAlias )

Eu tentei fazer deste o segundo vhost, com o primeiro vhost apenas manipulando todos os pedidos, mas isso não funcionou - pedidos de domínios onde um VirtualDocumentRoot foi configurado estavam passando para o vhost padrão.

Então, como posso ter vhosts dinamicamente configurados, mas com um fallback para outro vhost para qualquer um que ainda não esteja configurado?

    
por Paul Dixon 04.07.2011 / 13:13

4 respostas

6

Eu encontrei uma solução que funciona para mim.

Eu posso usar um ErrorDocument para pegar o erro 404 em um script PHP . No começo, isso parecia problemático. Se não há DocumentRoot, onde o roteiro vai viver?

Eu poderia usar um URL para a mensagem de erro, veiculada em um domínio diferente. No entanto, nos testes, não encontrei nenhuma maneira de saber qual era o domínio originalmente solicitado.

A resposta foi para Alias um diretório e exibir os erros, então meu vhost se parece com isso

<VirtualHost *>
  UseCanonicalName Off
  VirtualDocumentRoot /var/www/sandboxes/domains/%0
  ServerName catchall.host
  Alias /errors /var/www/default/errors/
  ErrorDocument 404 /errors/notfound.php
</VirtualHost>

Agora, quando um domínio não configurado é solicitado, o script em /var/www/default/errors/notfound.php é invocado. Esse script pode verificar $ _SERVER ['HTTP_HOST'] para ver qual domínio foi solicitado. Se estiver realmente configurado, temos um 404 normal. Se não estiver configurado, podemos exibir alguma mensagem de erro alternativa. No meu caso, é onde eu mostro uma interface do usuário para ajudar a configurar o vhost.

    
por 04.07.2011 / 14:12
3

Encontrei sua pergunta ao pesquisar no Google. Eu tive exatamente o mesmo problema e apliquei a correção conforme descrito na resposta de Paulo . No entanto, para meu aplicativo da web complexo, não fiquei satisfeito com o encaminhamento de todas as solicitações por meio de um único notfound.php .

No final, consegui corrigir o problema sem scripts externos, apenas editando a configuração do VirtualHost.

Primeiro, meu VirtualHost foi configurado assim:

<VirtualHost *:80>
    Usecanonicalname Off
    Virtualdocumentroot /mnt/ramdisk/www/cms-%-3.0-development/
</VirtualHost>

Eu tinha URLs como client1.domainname.com , client2.domainname.com e whatever.domainname.com

que foi resolvido para /mnt/ramdisk/www/cms-client1-development/ , /mnt/ramdisk/www/cms-client2-development/ e /mnt/ramdisk/www/cms-whatever-development/

No entanto, um URL como nonexistent.domainname.com me daria um 404 porque o diretório /mnt/ramdisk/www/cms-nonexistent-development/ não existia. Eu queria que esses subdomínios usassem o diretório /mnt/ramdisk/www/cms-default-development/

Corrigi isso usando ModRewrite e 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>

O que isto faz é: pegar o subdomínio (a parte antes de .domainname.com ), inserir isso no caminho (% 1) e requisições de proxy para a URL padrão somente se o diretório não funcionar. existe.

Ao usar um proxy, o processo é transparente e o usuário acha que está acessando o link , enquanto na verdade visualiza o conteúdo de link .

    
por 13.11.2014 / 16:28
3

Também encontrei essa pergunta pesquisando o apache2 dynamic vhost fallback e a resposta de Luc me ajudou muito a resolver meu problema, mas ainda quero mostrar o que fiz para atingir meus objetivos, principalmente porque envolveu alguns trabalhos extras e porque acho que pode ser útil para futuros googlers ...

Minhas metas

  • vhosting dinâmico para todos os domínios e subdomínios apontando para o meu VPS
  • foo.com deve veicular o mesmo conteúdo que www.foo.com
  • fallback de domínios desconhecidos para algum tipo de padrão
  • fallback para subdomínios desconhecidos de foo.com to www.foo.com , a menos que o www não esteja disponível, o fallback para o padrão

DNS

Eu tenho alguns domínios (e todos os seus subdomínios) apontando para o meu VPS, por exemplo:

  • foo.com
  • bar.com
  • foobar.com

Sistema de arquivos

Eu tenho os seguintes diretórios, domínios contêm diretórios com os nomes dos subdomínios disponíveis, o diretório www é necessário, mas a configuração deve ser capaz de lidar com a situação em que não está presente. Localhost é usado como fallback padrão:

/var
  /www
    /localhost
    /foo.com
       /www
       /bar
    /bar.com
       /foo

Testes

Traduzindo meus objetivos em casos testáveis:

  • foo.com deve ser veiculado em foo.com/www
  • www.foo.com deve ser veiculado em foo.com/www
  • bar.foo.com deve ser veiculado em foo.com/bar
  • foo.foo.com deve ser servido em foo.com/www (foo.com/foo não existe)
  • bar.com deve ser servido a partir de localhost (bar.com/www não existe)
  • www.bar.com deve ser servido a partir de localhost (bar.com/www não existe)
  • foo.bar.com deve ser veiculado em bar.com/foo
  • bar.bar.com deve ser servido a partir de localhost (bar.com/bar não existe)
  • foobar.com deve ser servido a partir de localhost (foobar.com não existe)
  • www.foobar.com deve ser servido a partir de localhost (foobar.com não existe)
  • foo.foobar.com deve ser servido a partir de localhost (o foobar.com não existe)

A solução

Isso usa: mod_rewrite , mod_proxy_http e ofcourse mod_vhost_alias .

ServerName my.domain
ServerAdmin [email protected]

<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>

Como isso funciona? Existem três hosts virtuais definidos:

localhost

O localhost serve como padrão. Todas as solicitações que não são resolvidas são atendidas pelo host local. Configurar um link simbólico de localhost para qualquer um dos seus domínios é como configurar esse site como padrão.

sub.domain

O vhost sub.domain está recebendo todas as solicitações na forma de *.*.* . Por padrão, todas as solicitações são atendidas a partir de /domain.com/sub , conforme definido por VirtualDocumentRoot /var/www/%-2.0.%-1.0/%-3 .

fallback:

O primeiro RewriteRule cuida de domínios desconhecidos, por exemplo. O diretório domain.com não existe, fazendo proxy no site do localhost.

O segundo RewriteRule também faz proxy para o localhost quando os diretórios domain.com/sub e domain.com/www não estão presentes.

O terceiro RewriteRule proxies para domain.com quando domain.com/sub não existe. Sabemos que domain.com/www existe devido ao segundo bloco de reescrita.

bare.domain

O vhost bare.domain está recebendo as solicitações *.* e as atende /domain.com/www

Aqui, o RewriteRule será o proxy para o localhost quando domain.com ou domain.com/www não existirem.

^ $%. * !!!

Eu tive alguns problemas em enrolar minha cabeça em todos os sinais $ e % no RewriteCond e RewriteRule , então vou explicar sobre eles aqui:

    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]
  • Os * no ServerAlias são apenas curingas.
  • Os %n no VirtualDocumentRoot são da interpolação do nome do documento .
  • O %n no segundo RewriteCond refere-se às seleções (.*) do primeiro RewriteCond , por exemplo. as partes do domínio solicitado.
  • O %n no RewriteRule também.
  • O $1 no RewriteRule refere-se à seleção (.*) no início do RewriteRule . Que captura tudo, desde o domínio até o ? no URL da solicitação. Qualquer querystring é automaticamente adicionada ao URL por mod_proxy .
por 25.04.2015 / 12:16
0

Apenas jogando isso lá fora, recebo o mesmo resultado (menos o redirecionamento de localhost) como RemyNL, mas também incluindo o endereço IP ao conectar diretamente:

<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>
    
por 03.03.2018 / 07:28