Erro 403 no Apache: o servidor achou a pasta e recusou a porta
Leia o log de erro para separar as três causas do 403 no Apache, permissão no disco, pasta sem index e regra de acesso, e corrija cada uma sem abrir permissão demais.
A URL está certa, o arquivo existe e o Apache responde "403 Forbidden". Reiniciar de novo não muda nada, porque o servidor entendeu o pedido e decidiu não entregar. A resposta curta: abra o log de erro do Apache, não a página genérica. A linha correspondente diz qual das três causas é a sua: o usuário do Apache não consegue ler o arquivo ou atravessar uma pasta do caminho, o endereço aponta para um diretório sem arquivo index e a listagem está desligada, ou uma regra de acesso na configuração nega aquele caminho ou aquele cliente.
Cada causa tem uma frase própria no log e um conserto próprio. Nenhum deles é chmod 777.
Por que o Apache responde 403
404 é "não achei". 403 é "achei e não vou entregar". Para chegar no 403, o Apache já resolveu o endereço para um caminho no disco ou para uma regra da configuração. A recusa acontece depois, em uma de três barreiras.
A barreira do sistema de arquivos
O processo do Apache roda com um usuário sem privilégios, www-data no Debian e no Ubuntu, apache no RHEL e derivados. Para ler /var/www/loja/public/index.html, esse usuário precisa de permissão de leitura no arquivo e de permissão de execução, que em diretório significa "atravessar", em cada pasta do caminho: /var, /var/www, /var/www/loja e /var/www/loja/public. Uma única pasta fechada no meio já basta. O caso clássico é o projeto dentro de /home/usuario, que em várias distribuições vem com permissão 750 ou 700.
Em sistemas com SELinux ativo, como RHEL, Rocky e Fedora, existe uma quarta camada: mesmo com as permissões certas, o arquivo precisa ter o rótulo que o Apache pode ler. Arquivo copiado de outro lugar costuma vir com o rótulo errado.
A barreira do diretório sem index
Quando a URL aponta para uma pasta, o Apache procura os arquivos listados em DirectoryIndex, normalmente index.html e, com PHP configurado, index.php. Se nenhum existe e Options -Indexes está em vigor, não há o que mostrar, e a resposta é 403. Isso é proteção, não defeito: listar o conteúdo da pasta para qualquer visitante expõe arquivo que ninguém deveria ver.
A barreira das regras de acesso
No Apache 2.4, quem decide é a diretiva Require, em blocos como <Directory> e <Location> ou em arquivos .htaccess. A configuração padrão do Debian nega acesso à raiz do disco e libera /var/www. Um site com DocumentRoot em outra pasta, como /srv/loja, herda a negação até ganhar um Require all granted próprio. No WampServer e em ambientes locais parecidos, a regra costuma ser Require local: funciona no próprio computador e dá 403 para quem acessa pela rede.
Como diagnosticar e corrigir o 403
- Reproduza o erro e leia a linha correspondente no log de erro do site.
- Identifique a causa pela frase do log.
- Corrija só a barreira apontada, com o mínimo de permissão necessário.
- Confira a sintaxe, recarregue e teste de novo com curl.
# Debian e Ubuntu
sudo tail -f /var/log/apache2/error.log
# RHEL, Rocky, Alma
sudo tail -f /var/log/httpd/error_log
# em outro terminal
curl -I http://loja.exemplo.com.br/
Se o site tem ErrorLog próprio no VirtualHost, olhe esse arquivo. As frases mudam um pouco entre versões, mas o padrão é este:
- "Permission denied" ou "search permissions are missing on a component of the path": barreira do sistema de arquivos.
- "No matching DirectoryIndex" e "forbidden by Options directive": diretório sem index com listagem desligada.
- "client denied by server configuration": regra de acesso.
Corrigindo permissão no disco
O namei mostra a permissão de cada componente do caminho, e o teste com sudo -u confirma o que o Apache enxerga:
namei -l /var/www/loja/public/index.html
sudo -u www-data test -r /var/www/loja/public/index.html && echo legivel
# dono: o usuário de deploy; grupo: o do Apache
sudo chown -R deploy:www-data /var/www/loja
sudo find /var/www/loja -type d -exec chmod 755 {} +
sudo find /var/www/loja -type f -exec chmod 644 {} +
Pastas com 755 e arquivos com 644 deixam o Apache ler sem permitir que ele escreva. Se a aplicação precisa gravar uploads ou cache, dê escrita ao grupo só nessa pasta específica. Com SELinux, confira o rótulo com ls -Z e restaure o padrão com sudo restorecon -Rv /var/www/loja. Desligar o SELinux para fazer o 403 sumir troca um erro visível por um risco invisível.
Corrigindo index e regra de acesso
Para a pasta sem index, coloque o arquivo index que a aplicação espera, ou confira se o PHP está configurado para que index.php seja reconhecido. Não ligue Options +Indexes só para o erro sumir. Para a regra de acesso, procure o bloco que cobre o caminho:
<Directory /srv/loja/public>
Options -Indexes
AllowOverride None
Require all granted
</Directory>
Se a configuração ainda tem Order allow,deny e Allow from all, é sintaxe do Apache 2.2. Ela só funciona com o módulo de compatibilidade e, misturada com Require, gera resultados difíceis de prever. Migre tudo para Require. Depois de mexer, rode sudo apache2ctl configtest e sudo systemctl reload apache2. A configuração dos blocos por site está detalhada em vários sites no mesmo Apache.
Erros comuns
- Aplicar
chmod -R 777. O 403 some e qualquer processo da máquina passa a poder alterar o seu site, inclusive um script invadido. - Olhar só a página do navegador. Ela é igual para as três causas. Sem o log, você troca configuração no escuro.
- Corrigir o arquivo e esquecer a pasta do meio. O
index.htmltem 644, mas/home/usuariotem 700, e o Apache continua sem atravessar. - Ligar a listagem de diretório para resolver. O erro some e a pasta passa a exibir backups e arquivos de configuração.
- Desligar o SELinux. Resolve o sintoma, remove uma proteção do servidor inteiro e o próximo arquivo copiado volta a dar problema quando alguém religar.
- Editar o
.htaccesscomAllowOverride Noneativo. O arquivo é ignorado, e você testa regras que o Apache nem lê.
Checklist
- A linha do log de erro correspondente ao pedido foi encontrada.
namei -lmostra permissão de travessia em todas as pastas do caminho.- O teste com
sudo -u www-data, ou o usuário do Apache na sua distribuição, consegue ler o arquivo. - Pastas estão com 755 e arquivos com 644, e escrita só onde a aplicação precisa.
- Existe um arquivo index na pasta pública, e a listagem continua desligada.
- O bloco
<Directory>do site temRequire all grantede nada da sintaxe 2.2. - Com SELinux, o rótulo dos arquivos foi restaurado com
restorecon.
Abra o log de erro do seu Apache e procure a última linha com "denied". Ela fala de permissão no disco ou de uma regra que você mesmo escreveu e esqueceu?
Referência: http://forum.wampserver.com/read.php?2,151925