Programação Por Equipe DevBras

Capa do artigo: Vários sites no mesmo Apache: o VirtualHost que responde pelo nome certo

Vários sites no mesmo Apache: o VirtualHost que responde pelo nome certo

Configure um VirtualHost por domínio, com pasta pública e log próprios, defina o site padrão de propósito e confira com apache2ctl -S e curl antes de apontar o DNS.

Você sobe o segundo projeto na mesma máquina e os dois domínios abrem a mesma pasta. A resposta curta: o Apache compara o domínio do pedido com o ServerName e o ServerAlias de cada VirtualHost que escuta naquele IP e porta. Se nenhum combina, ele entrega o primeiro VirtualHost da lista, que quase nunca é o que você queria mostrar. Um bloco por site, com o nome certo, e um site padrão escolhido de propósito resolvem o problema.

O resto dos casos é arquivo no lugar errado: configuração criada e não ativada, pasta pública apontando para o código inteiro ou reinício feito sem conferir a sintaxe.

Como o Apache escolhe o VirtualHost

O Apache 2.4 faz a escolha em duas etapas. Primeiro filtra pelo endereço e porta onde a conexão chegou. Se existe algum VirtualHost declarado com aquele IP exato, só esses entram na disputa. Se não existe, entram os declarados com *:80 ou *:443. Depois, dentro do grupo, ele compara o cabeçalho Host com o ServerName e o ServerAlias de cada bloco, na ordem em que foram carregados. O primeiro que casa responde.

Quando nenhum nome casa, responde o primeiro VirtualHost do grupo. No Debian e no Ubuntu, os arquivos de sites-enabled são carregados em ordem alfabética, e é por isso que o site que vem com a instalação se chama 000-default.conf: o nome garante que ele seja o primeiro. Se você apaga esse arquivo sem pensar, o padrão passa a ser o primeiro site do cliente em ordem alfabética.

O ServerAlias aceita curingas como *.exemplo.com.br. Use com cuidado, pelo mesmo motivo que vale no nginx: qualquer subdomínio, inclusive os digitados errado, cai nesse site. A comparação completa entre os dois servidores está em como o nginx escolhe o site pelo nome do host.

Como criar um VirtualHost por site no Debian e no Ubuntu

  1. Crie a pasta pública de cada site. Pasta pública é a que contém o index, como /var/www/loja/public, não a raiz do projeto.
  2. Crie um arquivo em /etc/apache2/sites-available/ para cada domínio.
  3. Ative com a2ensite. O arquivo em sites-available não vale nada até ganhar o link em sites-enabled.
  4. Confira a sintaxe com apache2ctl configtest. A resposta esperada é "Syntax OK".
  5. Veja quem responde por quê com apache2ctl -S.
  6. Recarregue com systemctl reload apache2 e teste com curl antes de mexer no DNS.

Um arquivo /etc/apache2/sites-available/loja.conf completo para HTTP:

<VirtualHost *:80>
    ServerName loja.exemplo.com.br
    ServerAlias www.loja.exemplo.com.br
    DocumentRoot /var/www/loja/public

    ErrorLog ${APACHE_LOG_DIR}/loja-error.log
    CustomLog ${APACHE_LOG_DIR}/loja-access.log combined

    <Directory /var/www/loja/public>
        Options -Indexes +FollowSymLinks
        AllowOverride None
        Require all granted
    </Directory>
</VirtualHost>

O segundo site segue o mesmo modelo, com outro nome, outra pasta e outros arquivos de log. Log separado parece frescura até o erro de um cliente se misturar com o do outro e você passar a tarde lendo o arquivo errado. O AllowOverride None desliga o .htaccess, o que deixa a configuração toda num lugar só. Se o seu projeto depende de .htaccess, como muitos sistemas em PHP, troque por AllowOverride All conscientemente.

Ative e confira:

sudo mkdir -p /var/www/loja/public /var/www/blog/public
sudo a2ensite loja.conf blog.conf
sudo apache2ctl configtest
sudo apache2ctl -S
sudo systemctl reload apache2

A saída de apache2ctl -S lista, para cada porta, qual é o "default server" e quais nomes cada arquivo atende, com o número da linha. É o jeito mais rápido de descobrir um nome duplicado ou um site que nem foi carregado. No Rocky, Alma e outros derivados do RHEL, os arquivos ficam em /etc/httpd/conf.d/, terminados em .conf, o comando é apachectl e o serviço se chama httpd.

O site padrão escolhido de propósito

Mantenha um primeiro VirtualHost neutro para os nomes desconhecidos, com uma pasta própria e uma página simples sem conteúdo do cliente:

<VirtualHost *:80>
    ServerName padrao.invalid
    DocumentRoot /var/www/padrao
    <Directory /var/www/padrao>
        Require all granted
    </Directory>
</VirtualHost>

Salve como 000-default.conf, ou outro nome que venha antes dos sites na ordem alfabética, e confirme no apache2ctl -S que ele aparece como padrão.

Testar e ligar o HTTPS

curl -I -H "Host: loja.exemplo.com.br" http://203.0.113.10/
curl -I -H "Host: blog.exemplo.com.br" http://203.0.113.10/
curl -I -H "Host: nao-existe.exemplo.org" http://203.0.113.10/

Cada um precisa cair num site diferente. Com os nomes certos e o DNS apontado, o Certbot gera o certificado e cria o VirtualHost da 443 com sudo certbot --apache -d loja.exemplo.com.br -d www.loja.exemplo.com.br. Peça o certificado para todos os nomes que o site atende. Se o www também precisa existir, decida se ele redireciona para o domínio sem www com 301, como explica redirecionar URL do jeito certo, em vez de servir o mesmo conteúdo em dois endereços.

Erros comuns

  • Apontar o DocumentRoot para a raiz do projeto. O .env, a pasta .git e os backups ficam acessíveis por URL.
  • Esquecer o ServerAlias do www. O endereço com www cai no site padrão, e o cliente jura que o site está fora do ar.
  • Editar em sites-available e não ativar. O arquivo está certo e nunca foi carregado. O apache2ctl -S mostra isso em um segundo.
  • Reiniciar sem configtest. Um erro de sintaxe no site novo impede o Apache de subir e derruba todos os sites da máquina.
  • Misturar <VirtualHost 203.0.113.10:80> com *:80. Os blocos com IP exato vencem, e os blocos com asterisco nunca respondem naquele endereço.
  • Servir www e sem www com o mesmo conteúdo. A busca vê duas cópias e você divide a relevância entre elas.

Checklist

  • Cada domínio tem um arquivo próprio, com ServerName e, se preciso, ServerAlias.
  • O DocumentRoot aponta para a pasta pública, não para o projeto.
  • Cada site grava em arquivos de log próprios.
  • O site padrão é neutro e aparece como "default server" no apache2ctl -S.
  • apache2ctl configtest responde "Syntax OK" antes de cada reload.
  • O curl com um Host inventado não abre nenhum site de cliente.
  • O certificado cobre todos os nomes atendidos pela 443.

Rode apache2ctl -S no seu servidor agora. Qual arquivo aparece como "default server" na porta 443, e o que ele mostra para um domínio que não existe?

Avalie este artigo

Referência: http://verticis.com.br/blog/tutoriais/como-configurar-multiplos-virtualhosts-no-apache/