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
- 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. - Crie um arquivo em
/etc/apache2/sites-available/para cada domínio. - Ative com
a2ensite. O arquivo emsites-availablenão vale nada até ganhar o link emsites-enabled. - Confira a sintaxe com
apache2ctl configtest. A resposta esperada é "Syntax OK". - Veja quem responde por quê com
apache2ctl -S. - Recarregue com
systemctl reload apache2e 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
DocumentRootpara a raiz do projeto. O.env, a pasta.gite os backups ficam acessíveis por URL. - Esquecer o
ServerAliasdo 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-availablee não ativar. O arquivo está certo e nunca foi carregado. Oapache2ctl -Smostra 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
ServerNamee, se preciso,ServerAlias. - O
DocumentRootaponta 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 configtestresponde "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?
Referência: http://verticis.com.br/blog/tutoriais/como-configurar-multiplos-virtualhosts-no-apache/