Skip to main content

208.1 Implementando um Web Server (Apache)


Servidor Web com Apache 2


Neste capítulo vamos implementar um servidor web usando o Apache 2. Antes de começar, é importante entender que Apache também é o nome da fundação responsável por vários projetos de software. O servidor web que normalmente chamamos apenas de Apache é, na verdade, o Apache HTTP Server, também conhecido como Servidor HTTP Apache.


Esse serviço é responsável por receber requisições HTTP/HTTPS e entregar páginas, arquivos e aplicações web para os clientes. A instalação pode ser feita com os comandos abaixo:

## Redhat like:
$ sudo dnf install httpd

## Debian like:
$ sudo apt install apache2

Em sistemas Debian-like, os processos e o serviço geralmente usam o nome apache2. Já em sistemas Red Hat-like, o nome usado normalmente é httpd.


ATENÇÃO

Muitas vezes vou usar o termo Red Hat-like para me referir a distribuições baseadas no padrão da Red Hat. Porém, algumas versões e distribuições dessa família podem ter diferenças entre si. Neste material, quando necessário, o CentOS 7 será usado como referência.


O comando usado para gerenciar o Apache é o apachectl no padrão Red Hat-like e o apache2ctl no padrão Debian-like. Mesmo assim, em sistemas Debian-like também costuma existir um link simbólico chamado apachectl, apontando para o apache2ctl, como no exemplo abaixo:

ls -l /usr/sbin/apachectl
lrwxrwxrwx 1 root root 10 Jun 14 13:30 /usr/sbin/apachectl -> apache2ctl

Esse comando serve para trabalhar com certas funcionalidades do servidor Web Apache, uma dessas é a verificação dos arquivos de configuração, verificar o status do serviço, reiniciar o serviço de modo a não impactar a disponibilidade do servidor Web e alguns outros.

Em vez de usar apachectl, também é possível chamar diretamente o binário do servidor web, usando apache2 em sistemas Debian-like ou httpd em sistemas Red Hat-like. Porém, para tarefas administrativas do dia a dia, o uso do apachectl ou apache2ctl costuma ser mais adequado.



Processos do Apache


Quando o Apache é iniciado, ele não trabalha com apenas um único processo fazendo tudo. Normalmente existe um processo principal, também chamado de processo pai, responsável por controlar o serviço. Esse processo principal cria outros processos, chamados de processos filhos, que ficam responsáveis por atender as conexões e requisições que chegam ao servidor web.


Essa organização permite que o Apache consiga atender várias conexões ao mesmo tempo. Enquanto o processo pai cuida do gerenciamento geral, os processos filhos ficam encarregados de lidar com o trabalho prático, como receber uma requisição HTTP, processar essa requisição e entregar a resposta ao cliente.


Esse comportamento é controlado por um componente chamado MPM, sigla para Multi-Processing Module. O MPM define a forma como o Apache vai criar processos, usar threads e distribuir as requisições recebidas. Segundo a documentação do próprio Apache HTTP Server, os MPMs são responsáveis por tarefas básicas do servidor, como escutar portas de rede, aceitar requisições e encaminhar essas requisições para processos ou threads de atendimento.


O processo pai não costuma atender diretamente as requisições dos clientes. A função dele é manter o serviço funcionando e controlar os processos filhos. Ele pode criar novos processos, encerrar processos antigos e ajustar a quantidade de processos disponíveis conforme a configuração do Apache.


Já a thread pode ser entendida como uma linha de execução dentro de um processo. No modo prefork, o Apache trabalha de forma mais tradicional, usando vários processos filhos. Cada processo filho atende uma requisição por vez.


Nos modos worker e event, o Apache continua tendo processos filhos, mas esses processos também criam threads. Nesse caso, o processo filho não precisa fazer todo o trabalho sozinho. Ele possui várias threads internas, e essas threads podem atender requisições.


De forma simplificada fica assim:

Prefork
Processo pai
Processo filho
Processo filho
Processo filho

Worker/Event
Processo pai
Processo filho
Thread
Thread
Thread
Processo filho
Thread
Thread
Thread

O prefork é o modelo mais tradicional, com ele, o Apache usa um processo pai e vários processos filhos de modo normal comum mesmo, esse é um modo mais simplificado. Cada processo filho atende uma requisição por vez. Como ele não usa múltiplas threads dentro do processo filho, esse modelo costuma ser mais simples de entender e pode ser útil quando existe alguma aplicação ou biblioteca que não trabalha bem com threads.


A desvantagem desse modelo é que ele tende a consumir mais memória, já que precisa de mais processos para atender muitas conexões ao mesmo tempo.


Já o worker usa uma abordagem híbrida. Ele ainda possui um processo pai e processos filhos, mas cada processo filho cria várias threads. Com isso, um único processo filho consegue atender várias requisições por meio dessas threads. Esse modelo costuma ser mais eficiente que o prefork em consumo de recursos, porque não depende apenas da criação de vários processos separados. Em vez disso, ele combina processos e threads.


O event é parecido com o worker, pois também usa processos filhos com várias threads. A diferença é que ele foi criado para lidar melhor com conexões persistentes, como conexões HTTP com KeepAlive. Em conexões KeepAlive, o cliente pode manter a conexão aberta por um tempo para reutilizá-la em novas requisições.


No modelo event, o Apache tenta evitar que uma thread de trabalho fique presa apenas esperando uma nova requisição chegar nessa conexão. Para isso, parte desse controle é passado para threads de escuta, liberando as threads de trabalho para atender novas requisições. Por isso, em ambientes modernos, o event costuma ser uma escolha comum para servidores Apache que precisam lidar com muitas conexões simultâneas.


É comum encontrar exemplos dizendo que sistemas baseados em Debian usam event e sistemas baseados em Red Hat usam prefork. Isso até pode se concretizar em alguns ambientes, mas sempre verifique qual modelos está configurado por padrão e altere se necessário.



Arquivos de configuração


Os arquivos de configuração mudam de acordo com o Sistema Operacional, em Debian like ficam em /etc/apache2. Já em Redhat like ficam em /etc/httpd.


Dentro desses diretórios temos o arquivo principal da configuração, seu nome também muda de acordo com o sistema. Para Debian like ele fica em /etc/apache2/apache2.conf e para Redhat like está em /etc/httpd/conf/httpd.conf.


Porém, nem tudo se concentra nesse diretório principal, isso também varia de acordo com distribuição.

# Em Redhat like:
$ ls -lh /etc/httpd/
total 0
drwxr-xr-x. 2 root root 37 Nov 16 20:41 conf
drwxr-xr-x. 2 root root 82 Nov 16 20:41 conf.d
drwxr-xr-x. 2 root root 146 Nov 16 20:41 conf.modules.d
lrwxrwxrwx. 1 root root 19 Nov 16 20:41 logs -> ../../var/log/httpd
lrwxrwxrwx. 1 root root 29 Nov 16 20:41 modules -> ../../usr/lib64/httpd/modules
lrwxrwxrwx. 1 root root 10 Nov 16 20:41 run -> /run/httpd

# Em Debian like:
$ ls -l /etc/apache2/
total 80
-rw-r--r-- 1 root root 7224 Jun 14 13:30 apache2.conf
drwxr-xr-x 2 root root 4096 Nov 16 19:08 conf-available
drwxr-xr-x 2 root root 4096 Nov 16 19:08 conf-enabled
-rw-r--r-- 1 root root 1782 Feb 23 2021 envvars
-rw-r--r-- 1 root root 31063 Feb 23 2021 magic
drwxr-xr-x 2 root root 12288 Nov 16 19:08 mods-available
drwxr-xr-x 2 root root 4096 Nov 16 19:08 mods-enabled
-rw-r--r-- 1 root root 320 Feb 23 2021 ports.conf
drwxr-xr-x 2 root root 4096 Nov 16 19:08 sites-available
drwxr-xr-x 2 root root 4096 Nov 16 19:08 sites-enabled

Com esse resultado acima, podemos ver a diferença entre os dois sistemas operacionais. Além disso, podemos ver também que existe uma parte do nome em pastas com o descritivo de modules ou mods (para Debian).


Isso acontece porque o Apache possui uma arquitetura modular, ou seja, podemos adicionar, remover, ativar ou desativar módulos conforme a necessidade do servidor. Tanto em distribuições baseadas em Red Hat quanto em distribuições baseadas em Debian, o Apache trabalha com módulos.


A diferença está mais na forma como cada distribuição organiza e habilita esses módulos. No Debian, essa separação costuma ser mais evidente, com comandos próprios para ativar e desativar módulos. Já no Red Hat, a organização também é modular, mas normalmente aparece de forma menos fragmentada para o administrador.


Segue uma breve descrição sobre as pastas no padrão Redhat:

Arquivo/DiretórioDescrição
confFicam os arquivos de configuração principais, não é recomendado adicionar nenhum arquivo aqui.
httpdArquivo de configuração principal.
conf.dAqui ficam outros arquivos de configuração que são complementos ao arquivo principal. Aqui sim podemos adicionar novos arquivos.
conf.modules.dAqui temos arquivos de configuração específicos para os módulos ativos.

Segue uma breve descrição sobre as pastas no padrão Debian:

Arquivo/DiretórioDescrição
apache2.confArquivo de configuração principal.
conf-availableArquivos de configuração que temos disponíveis para uso.
conf-enableArquivos de configuração que estão em uso.
mods-availableMódulos que temos disponíveis para uso.
mods-enableMódulos que estão para uso.
sites-availableSites que temos disponíveis para usar, são arquivos de configuração de sites que vão ser acessados.
sites-enableSites que estão em uso, são arquivos de configuração de sites que vão ser acessados.

Com isso o padrão Debian like trás consigo um utilitário chamado a2en alguma coisa, esse utilitário é usado para ativar/desativar algum módulo/configuração.

UtilitárioDescrição
a2enconf / a2disconfUsado para ativar/desativar configurações.
a2enmod / a2dismodUsado para ativar/desativar módulos.
a2ensite / a2dissiteUsado para ativar/desativar sites.

Acontece que esses utilitários basicamente criam link simbólicos de arquivos de configuração que estão em pastas que tem no nome available para pastas que tem no nome enable:

# Sites:
$ ls -l /etc/apache2/sites-enabled/
total 0
lrwxrwxrwx 1 root root 35 Nov 16 19:08 000-default.conf -> ../sites-available/000-default.conf

# Confs:
$ ls -l /etc/apache2/conf-enabled/
total 0
lrwxrwxrwx 1 root root 30 Nov 16 19:08 charset.conf -> ../conf-available/charset.conf
lrwxrwxrwx 1 root root 44 Nov 16 19:08 localized-error-pages.conf -> ../conf-available/localized-error-pages.conf
lrwxrwxrwx 1 root root 46 Nov 16 19:08 other-vhosts-access-log.conf -> ../conf-available/other-vhosts-access-log.conf
lrwxrwxrwx 1 root root 31 Nov 16 19:08 security.conf -> ../conf-available/security.conf
lrwxrwxrwx 1 root root 36 Nov 16 19:08 serve-cgi-bin.conf -> ../conf-available/serve-cgi-bin.conf

# Módulos:
$ ls -l /etc/apache2/mods-enabled/ | head -n5
total 0
lrwxrwxrwx 1 root root 36 Nov 16 19:08 access_compat.load -> ../mods-available/access_compat.load
lrwxrwxrwx 1 root root 28 Nov 16 19:08 alias.conf -> ../mods-available/alias.conf
lrwxrwxrwx 1 root root 28 Nov 16 19:08 alias.load -> ../mods-available/alias.load
lrwxrwxrwx 1 root root 33 Nov 16 19:08 auth_basic.load -> ../mods-available/auth_basic.load

Sendo assim podemos usar ou não esses utilitários.



Principais Configurações


As principais configurações ficam no arquivo chamado apache2.conf ou httpd.conf (dependendo do sistema usado). Esse arquivo carrega a maior parte das configurações do servidor Web.

OpçãoDescrição
ServerRootLocalização dos arquivos de configuração.
ListenPermite especificar a porta ou as portas e IP em que o servidor web vai ficar escutando.
IncludeUsado para incluir a configuração de algum arquivo.
UserUsuário que vai ser usado para executar os processos do servidor Web.
GroupGrupo que vai ser usado para executar os processos do servidor Web.
ServerAdminEspecífica o e-mail do administrador do servidor Web. Normalmente isso fica comentado e é específicado no arquivo de cada site quando usamos Virtual Hosts.
ServerNameNome padrão do servidor Web. Normalmente isso fica comentado e é específicado no arquivo de cada site quando usamos Virtual Hosts.
<Directory DIR_NAME>Quando vir isto, é uma forma de fazer com que o servidor Web consiga fornecer o conteúdo desse diretório.
DocumentRootLocalização dos arquivos que vão ser servidos pelo servidor Web. Existe uma configuração padrão, mas normalmente é específicado no arquivo de cada site quando usamos Virtual Hosts e essa configuração "padrão" pode ser comentada.
<IfModule MODULE_NAME>É um IF para o Apache, se determinado módulo estiver ativo, faça alguma coisa.
Configurações do MPM As configurações abaixo podem ser adicionadas ao arquivo principal do Apache, mas normalmente ficam no arquivo de configuração do MPM que está em uso.
MaxClients NQuantos clientes o servidor Web vai tratar simultaneamente.
ThreadsPerChildQuantas Threads que vamos ter em cada processo filho. Serve apenas nos MPM: Event, Worker e Winnt.
MaxRequestsPerChild ou MaxConnectionsPerChildQual é o número máximo de requisições que um processo filho vai poder tratar, após esse limite o processo é eliminado.
Definir um valor diferente de zero limita a quantidade de memória que um processo pode consumir por vazamento de memória (algo acidental).
Serve nos MPM: Event, Worker e Prefork. O nome MaxRequestsPerChild é antigo, mas ainda é suportado.

Sobre a opção Listen, no padrão Debian não fica localizado no arquivo principal, o arquivo principal carrega um outro arquivo contendo essas configurações:

# Include list of ports to listen on
Include ports.conf

Portanto, a configuração de portas fica no arquivo /etc/apache2/ports.conf.


No Debian você pode ver algumas das configurações acimas no arquivo mods-available/mpm_event.conf ou específicar o MPM que estiver usando.


Vejamos algumas configurações que têm funções semelhantes e existem em diferentes tipos de MPM, às vezes com nomes diferentes. Vale ressaltar que os valores padrão podem variar em relação ao que está na documentação oficial.


Por isso, é importante verificar os arquivos em /etc/apache2/mods-available/. Nesse diretório existem arquivos que começam com mpm_, referentes aos principais MPMs: event, worker e prefork.

  • StartServers

    Especifica quantos processos filhos serão iniciados quando o servidor Web for iniciado.

    Essa mesma diretiva é usada nos MPMs: event, worker e prefork.


  • MinSpareServers

    Define o número mínimo de processos filhos ociosos que devem permanecer disponíveis. Se houver menos processos filhos ociosos do que o valor especificado, o processo pai criará novos filhos.

    Ele criará um processo, aguardará um segundo, depois criará dois, aguardará mais um segundo, depois criará quatro, e continuará aumentando exponencialmente até o limite de 32 processos por segundo.

    Esse crescimento será interrompido assim que o valor configurado em MinSpareServers for satisfeito.

    Essa diretiva é usada no MPM prefork.

    Nos MPMs worker e event, a diretiva equivalente é: MinSpareThreads.


  • MaxSpareServers

    Define o número máximo de processos filhos ociosos que podem permanecer ativos.. O servidor ainda poderá criar mais processos filhos do que o valor especificado nessa diretiva. Porém, quando esses processos excedentes ficarem ociosos, o servidor irá encerrá-los mais rapidamente até que o número de processos ociosos volte para dentro do limite configurado.

    Essa diretiva é usada no MPM prefork.

    Nos MPMs worker e event, a diretiva equivalente é: MaxSpareThreads.



Módulos (php/perl)


Como vimos anteriormente, o Apache trabalha com módulos. Portanto, quando precisamos de determinada funcionalidade, devemos ativar o módulo correspondente, caso ele já esteja instalado ou tenha sido compilado como parte do próprio Apache.


Se o módulo não estiver disponível, será necessário instalar o pacote que fornece esse suporte e, em seguida, ativá-lo. Alguns exemplos são os módulos relacionados a linguagens como PHP e Perl, que permitem ao Apache interpretar ou encaminhar requisições para aplicações escritas nessas linguagens.


Em distribuições Debian/Ubuntu, os módulos disponíveis geralmente ficam em:

/etc/apache2/mods-available/

Para instalar um módulo, podemos fazer via gerenciador de pacotes ou compilar, caso não tenha a opção via pacotes.

## Redhat like:
$ sudo yum install php

## Debian like:
$ sudo apt install php

Ao instalar o pacote php, será instalada a versão padrão disponível no repositório da distribuição.

$ apt-cache depends php
php
Depends: php7.4

$ apt-cache depends php7.4
php7.4
|Depends: libapache2-mod-php7.4
|Depends: php7.4-fpm
Depends: php7.4-cgi
Depends: php7.4-common

Nesse exemplo, o pacote php é um metapacote que depende da versão padrão do PHP disponível no repositório. Além de instalar o PHP no servidor, ele pode instalar também o módulo que fornece integração entre o PHP e o Apache, como o pacote libapache2-mod-php7.4.


Outros módulos que normalmente podem ser instalados:

############
### Perl ###
############

## Red Hat-like:
# Primeiro instale o repositório EPEL, caso necessário:
$ sudo yum install epel-release

# Agora instale o módulo Perl para o Apache:
$ sudo yum install mod_perl


## Debian-like:
$ sudo apt install libapache2-mod-perl2

Após a instalação, o servidor Web passa a reconhecer os arquivos de configuração relacionados ao módulo instalado. No caso do PHP, podemos verificar os arquivos criados da seguinte forma:

# Debian-like:
$ ls -l /etc/apache2/mods-available/{php7.4.conf,php7.4.load}
-rw-r--r-- 1 root root 855 Nov 2 09:53 /etc/apache2/mods-available/php7.4.conf
-rw-r--r-- 1 root root 102 Nov 2 09:53 /etc/apache2/mods-available/php7.4.load

No Debian/Ubuntu, o arquivo .load é responsável por carregar o módulo, enquanto o arquivo .conf contém configurações adicionais relacionadas a ele.

# Red Hat-like:
# Arquivo de configuração:
$ ls /etc/httpd/conf.d/php.conf
/etc/httpd/conf.d/php.conf

# Arquivo responsável por carregar o módulo:
$ ls /etc/httpd/conf.modules.d/10-php.conf
/etc/httpd/conf.modules.d/10-php.conf

Em distribuições Red Hat-like, os arquivos de configuração do Apache geralmente ficam em /etc/httpd/, enquanto em distribuições Debian-like ficam em /etc/apache2/.



Analisando o php.conf


Vamos analisar o arquivo de configuração do módulo PHP para entender algumas diretivas importantes. Vou separar por partes:

## Red Hat-like:
<FilesMatch \.php$>
SetHandler application/x-httpd-php
</FilesMatch>

## Debian-like:
<FilesMatch ".+\.ph(ar|p|tml)$">
SetHandler application/x-httpd-php
</FilesMatch>
  • FilesMatch

    A diretiva FilesMatch é usada para aplicar configurações a arquivos cujo nome corresponda a uma expressão regular. No exemplo do Red Hat-like, a configuração será aplicada a arquivos terminados em .php.

    No exemplo do Debian-like, a configuração será aplicada a arquivos com as extensões: .phar, .php e .phtml. Caso o nome do arquivo corresponda ao padrão definido, as diretivas dentro do bloco FilesMatch serão aplicadas.

  • SetHandler application/x-httpd-php

    A diretiva SetHandler define qual handler interno do Apache será usado para processar os arquivos correspondentes. Nesse caso, arquivos PHP serão associados ao handler application/x-httpd-php.

    Isso indica ao Apache que esses arquivos devem ser processados pelo módulo PHP, como mod_php, em vez de serem entregues diretamente como arquivos estáticos.

    Importante: SetHandler application/x-httpd-php não significa que o arquivo PHP será enviado ao navegador com esse tipo MIME. Na prática, o Apache usa esse handler internamente para processar o arquivo PHP no servidor. O navegador normalmente recebe apenas a saída gerada pelo PHP, geralmente como text/html.

  • AddType

    A diretiva AddType associa uma extensão de arquivo a um tipo MIME. Nesse exemplo, arquivos com a extensão .php são associados ao tipo MIME text/html, ou seja, a resposta gerada para arquivos PHP será tratada como conteúdo HTML.

    Em outras palavras, após o PHP ser processado no servidor, o conteúdo retornado ao navegador normalmente será interpretado como HTML.

  • DirectoryIndex

    A diretiva DirectoryIndex define qual arquivo será procurado automaticamente quando um cliente acessar um diretório sem especificar um arquivo. Por exemplo, ao acessar:

    http://site.com/

    O Apache pode procurar automaticamente por arquivos como:

    index.html
    index.php

    A função do DirectoryIndex é informar o arquivo padrão de índice para aquele diretório. Arquivos de índice são aqueles carregados automaticamente quando acessamos um diretório sem informar o nome do arquivo. Por exemplo, em sites HTML, normalmente o arquivo padrão se chama index.html.



Analisando o load.conf


O método usado para carregar um módulo no Apache é semelhante entre as distribuições. O que muda é a forma como os arquivos de configuração são organizados e, em alguns casos, se o carregamento será feito diretamente ou dentro de alguma condição.


Basicamente, a diretiva usada para carregar um módulo segue esta estrutura:

LoadModule nome_do_modulo caminho_do_modulo

Um exemplo real seria assim:

LoadModule php7_module /usr/lib/apache2/modules/libphp7.4.so

Em distribuições Red Hat-like, o carregamento dos módulos normalmente fica em arquivos dentro de:

/etc/httpd/conf.modules.d/

Já em distribuições Debian-like, os módulos disponíveis ficam em:

/etc/apache2/mods-available/

E os módulos habilitados ficam no diretório abaixo (em Debian-like):

/etc/apache2/mods-enabled/

No Debian/Ubuntu, normalmente não editamos esses links manualmente. O recomendado é usar os comandos próprios do Apache:

sudo a2enmod nome_do_modulo
sudo a2dismod nome_do_modulo


Exemplo com módulo WSGI para Python - Não cai na LPIC-2


O mod_wsgi é um módulo do Apache usado para hospedar aplicações Python que seguem o padrão WSGI. Em distribuições Debian atuais, o pacote usado para Python 3 é geralmente libapache2-mod-wsgi-py3, que fornece o módulo WSGI para Apache com suporte a Python 3.


Vamos instalar o módulo:

sudo apt install libapache2-mod-wsgi-py3

Depois da instalação, podemos ativar o módulo com o comando abaixo:

sudo a2enmod wsgi

Também seria possível habilitar manualmente criando links simbólicos em mods-enabled:

# Entre no diretório dos módulos disponíveis:
cd /etc/apache2/mods-available/

# Crie os links simbólicos manualmente:
sudo ln -s /etc/apache2/mods-available/wsgi.conf ../mods-enabled/
sudo ln -s /etc/apache2/mods-available/wsgi.load ../mods-enabled/

Após ativar o módulo, recarregue ou reinicie o Apache:

sudo systemctl restart apache2

Observação: em sistemas Red Hat-like/Fedora, o pacote pode aparecer como python3-mod_wsgi ou mod_wsgi, dependendo da distribuição e versão. O Fedora lista python3-mod_wsgi como o módulo WSGI para hospedar aplicações Python no Apache.



Arquivos de Log


Vamos começar verificando onde o Apache armazena os logs:

# Debian-like:
$ grep -i errorlog /etc/apache2/apache2.conf
ErrorLog ${APACHE_LOG_DIR}/error.log

# Red Hat-like:
$ grep -i errorlog /etc/httpd/conf/httpd.conf
ErrorLog "logs/error_log"

Em distribuições Debian-like, a variável ${APACHE_LOG_DIR} normalmente aponta para:

/var/log/apache2

Portanto, o arquivo de erro padrão costuma ser:

/var/log/apache2/error.log

Em distribuições Red Hat-like, quando o ErrorLog é configurado como logs/error_log, o caminho é relativo ao ServerRoot, que normalmente é /etc/httpd.


Então, logicamente, o caminho fica:

/etc/httpd/logs/error_log

Porém, em sistemas Red Hat-like, /etc/httpd/logs geralmente é um link simbólico para:

/var/log/httpd

Assim, o arquivo real normalmente fica em:

/var/log/httpd/error_log

Podemos confirmar isso com um simples ls:

$ ls -lhd /etc/httpd/logs
lrwxrwxrwx. 1 root root 19 Jun 9 21:58 /etc/httpd/logs -> ../../var/log/httpd

Essa configuração será usada caso não exista uma configuração específica de log dentro de um VirtualHost. Tanto em Debian-like quanto em Red Hat-like, os VirtualHosts podem definir seus próprios arquivos de log usando diretivas como ErrorLog e CustomLog.


Além disso, temos a diretiva LogLevel, que controla o nível de detalhes registrados nos logs. Também podemos usar LogFormat para definir o formato das mensagens de log, e CustomLog para indicar onde os logs de acesso serão gravados e qual formato será usado.


Exemplo:

LogLevel warn
LogFormat "%h %l %u %t \"%r\" %>s %b" common
CustomLog /var/log/apache2/access.log common

Se você vir uma configuração de log começando com pipe |, isso indica que o Apache enviará as mensagens de log para um comando externo.

Exemplo:

CustomLog "|/usr/sbin/rotatelogs /var/log/apache2/access.%Y%m%d.log 86400" combined

Nesse exemplo, o Apache envia os logs para o comando rotatelogs, que faz a rotação dos arquivos de log automaticamente.



Controle de Acesso – Usuário


O Apache permite vários tipos de controle de acesso por meio de módulos. Podemos ver alguns desses módulos na saída abaixo:

[root@centos7 ~]# ls -l /etc/httpd/modules/*auth*
-rwxr-xr-x. 1 root root 15336 Mar 24 2022 /etc/httpd/modules/mod_auth_basic.so
-rwxr-xr-x. 1 root root 36088 Mar 24 2022 /etc/httpd/modules/mod_auth_digest.so
-rwxr-xr-x. 1 root root 11160 Mar 24 2022 /etc/httpd/modules/mod_authn_anon.so
-rwxr-xr-x. 1 root root 15376 Mar 24 2022 /etc/httpd/modules/mod_authn_core.so
-rwxr-xr-x. 1 root root 15280 Mar 24 2022 /etc/httpd/modules/mod_authn_dbd.so
-rwxr-xr-x. 1 root root 11200 Mar 24 2022 /etc/httpd/modules/mod_authn_dbm.so
-rwxr-xr-x. 1 root root 11176 Mar 24 2022 /etc/httpd/modules/mod_authn_file.so
-rwxr-xr-x. 1 root root 19552 Mar 24 2022 /etc/httpd/modules/mod_authn_socache.so
-rwxr-xr-x. 1 root root 23752 Mar 24 2022 /etc/httpd/modules/mod_authz_core.so
-rwxr-xr-x. 1 root root 15304 Mar 24 2022 /etc/httpd/modules/mod_authz_dbd.so
-rwxr-xr-x. 1 root root 11216 Mar 24 2022 /etc/httpd/modules/mod_authz_dbm.so
-rwxr-xr-x. 1 root root 11200 Mar 24 2022 /etc/httpd/modules/mod_authz_groupfile.so
-rwxr-xr-x. 1 root root 11192 Mar 24 2022 /etc/httpd/modules/mod_authz_host.so
-rwxr-xr-x. 1 root root 11144 Mar 24 2022 /etc/httpd/modules/mod_authz_owner.so
-rwxr-xr-x. 1 root root 7040 Mar 24 2022 /etc/httpd/modules/mod_authz_user.so

O método mais comum de controle de acesso é por usuário e senha, mas o Apache também permite outros métodos, como autenticação via LDAP, liberação por IP ou rede, grupos de usuários, banco de dados e outros mecanismos.


Na saída acima, os módulos com authn estão relacionados à autenticação, enquanto os módulos com authz estão relacionados à autorização.

Autenticação verifica a identidade do usuário, ou seja, confirma se as credenciais informadas são válidas.

Autorização verifica se o usuário autenticado tem permissão para acessar determinado recurso ou conteúdo.


Vamos criar uma página no Apache e proteger o acesso usando autenticação por usuário e senha.

# Entre no diretório abaixo:
$ cd /etc/apache2/sites-available/

# Crie o arquivo de configuração:
$ sudo vim vagranthome.conf

/etc/apache2/sites-available/vagranthome.conf
<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

ErrorLog /var/log/apache2/vagranthome-error.log
CustomLog /var/log/apache2/vagranthome-access.log combined

<Directory /home>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

<Directory /home/vagrant>
AuthType Basic
AuthName "Home particular"
AuthUserFile /etc/apache2/.htpasswd
#AuthGroupFile /etc/apache2/.htgroup
#Require group suporte
Require valid-user
#Require user fulano test
</Directory>
</VirtualHost>

Explicando algumas diretivas:

  • Options Indexes FollowSymLinks

    O Indexes permite listar o conteúdo do diretório caso não exista um arquivo de índice, como index.html ou index.php. Já o FollowSymLinks permite que o Apache siga links simbólicos dentro do diretório.

  • AllowOverride All

    Define quais diretivas podem ser sobrescritas por arquivos .htaccess. Quando essa diretiva está definida como All, qualquer diretiva permitida no contexto .htaccess poderá ser usada dentro de arquivos .htaccess.

  • Require all granted

    Permite o acesso ao diretório. Essa é a sintaxe usada no Apache 2.4 ou superior. Em versões antigas do Apache, como Apache 2.2, era comum usar:

    Order allow,deny
    Allow from all

    Porém, essa sintaxe está obsoleta nas versões mais recentes.

  • AuthType Basic

    Define o tipo de autenticação. Nesse caso, será usada autenticação básica HTTP.

  • AuthName

    Define o nome da área protegida. Esse texto aparece na janela de autenticação do navegador.

  • AuthUserFile

    Define o arquivo onde ficarão armazenados os usuários e senhas usados na autenticação.

  • Require valid-user

    Permite o acesso a qualquer usuário válido presente no arquivo definido em AuthUserFile. Também poderíamos liberar apenas usuários específicos:

    Require user fulano test

Agora crie o arquivo com o usuário e a senha:

$ sudo htpasswd -c /etc/apache2/.htpasswd fulano

A opção -c deve ser usada apenas na criação inicial do arquivo. Se ela for usada novamente, o arquivo será recriado e os usuários anteriores serão perdidos.


As opções possíveis são:

  • -c: Cria o arquivo de senhas.
  • -s: Usa SHA-1 para armazenar a senha.
  • -m: Usa MD5 no formato Apache apr1.
  • -B: Usa bcrypt.

Agora habilite a configuração criada:

$ sudo a2ensite vagranthome
Enabling site vagranthome.
To activate the new configuration, you need to run:
systemctl reload apache2

Antes de reiniciar ou recarregar o Apache, verifique se existe erro de sintaxe:

$ sudo apachectl configtest
Syntax OK

Agora recarregue ou reinicie o serviço do Apache:

$ sudo systemctl restart apache2

Depois, acesse:

http://test.com.ze

Antes disso, adicione o nome test.com.ze no arquivo hosts da máquina cliente, apontando para o IP do servidor Apache.



Controle de Acesso – IP


Vamos ver como fazer controle de acesso por endereço IP no Apache. O método abaixo é a sintaxe antiga, usada principalmente no Apache 2.2. Em versões mais recentes, como Apache 2.4, essa forma é considerada obsoleta e só funciona se o módulo de compatibilidade estiver disponível.

# Entre no diretório abaixo:
$ cd /etc/apache2/sites-available/

# Crie ou edite o arquivo:
$ sudo vim vagranthome.conf

Exemplo usando a sintaxe antiga:

<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

ErrorLog /var/log/apache2/vagranthome-error.log
CustomLog /var/log/apache2/vagranthome-access.log combined

<Directory /home>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

<Directory /home/vagrant>
Order deny,allow
Deny from all
Allow from 192.168.121.1
</Directory>
</VirtualHost>

Curiosidades, erros 4XX são erros na origem (cliente) e erros 5XX são erros no servidor.


Nesse exemplo:

  • Order deny,allow vai definir a ordem de avaliação das regras.
  • Deny from all vai bloqueiar todos os acessos.
  • Allow from 192.168.121.1 vai liberar apenas o IP 192.168.121.1.

A forma atual de fazer esse controle é usando as diretivas do Apache 2.4, principalmente com os módulos mod_authz_core e mod_authz_host.

# Entre no diretório abaixo:
$ cd /etc/apache2/sites-available/

# Crie ou edite o arquivo:
$ sudo vim vagranthome.conf

Exemplo usando Require ip:

<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

ErrorLog /var/log/apache2/vagranthome-error.log
CustomLog /var/log/apache2/vagranthome-access.log combined

<Directory /home>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>

<Directory /home/vagrant>
Require ip 192.168.121.1
Require ip 192.168.121.10
#Require ip 192.168.121
#Require ip 192.168.121.0/24
</Directory>
</VirtualHost>

Nesse exemplo, apenas os IPs informados poderão acessar o diretório /home/vagrant. Quando usamos várias diretivas Require ip no mesmo bloco, o Apache permite o acesso caso qualquer uma delas seja satisfeita, ou seja, funciona como uma lógica de OU.


Também podemos liberar uma rede inteira:

Require ip 192.168.121.0/24

Antes de aplicar a configuração, teste a sintaxe:

$ sudo apachectl configtest
Syntax OK

$ sudo systemctl restart apache2


Controle usando hostname


Além do controle por IP, também podemos usar Require host:

Require host domain.exemplo.com

Dessa forma, o Apache tenta validar o acesso com base no nome DNS associado ao IP do cliente. Na prática, o servidor faz uma verificação reversa do IP para obter o nome e depois valida se esse nome corresponde ao domínio informado.

Esse método pode impactar desempenho, pois depende de consultas DNS. Por isso, em ambientes de produção, o controle por IP costuma ser mais direto e previsível.



Liberar todos, exceto alguns IPs


Também podemos criar uma regra permitindo todos os acessos, exceto determinados IPs, exemplo:

<RequireAll>
Require all granted
Require not ip 192.168.200.110
</RequireAll>

Nesse caso:

  • Require all granted libera o acesso para todos.
  • Require not ip 192.168.200.110 nega o acesso ao IP 192.168.200.110.
  • <RequireAll> exige que todas as condições sejam avaliadas em conjunto.

Essa estrutura é útil quando queremos bloquear apenas alguns endereços específicos, mantendo o restante liberado.



VirtualHost


O VirtualHost é uma técnica usada para hospedar mais de um site no mesmo servidor Web. Existem duas formas principais de trabalhar com VirtualHosts:

  • VirtualHost baseado em IP
  • VirtualHost baseado em nome de domínio

No VirtualHost baseado em IP, o servidor precisa ter mais de um endereço IP, ou utilizar combinações diferentes de IP e porta.


Já usamos VirtualHost nos exemplos anteriores, portanto, não colocarei novos exemplos completos aqui.


Caso seja necessário utilizar mais de um nome para o mesmo VirtualHost, isso não deve ser feito com várias diretivas ServerName. Dentro de um VirtualHost, o ServerName deve representar o nome principal do site.


Para nomes adicionais, devemos usar a diretiva ServerAlias, como no exemplo abaixo:

<VirtualHost *:80>
ServerName www.example.com
ServerAlias example.com example.com.br example.br
DocumentRoot "/www/domain"
</VirtualHost>

Mais detalhes podem ser consultados na documentação oficial do Apache sobre VirtualHosts baseados em nome:

https://httpd.apache.org/docs/2.4/vhosts/name-based.html



UserDir e Redirecionamentos


O UserDir permite que o Apache crie uma área Web individual para cada usuário do sistema. Com isso, cada usuário pode publicar arquivos em um diretório específico dentro da sua própria home.


Já o redirecionamento é usado para redirecionar requisições para outro endereço, podendo ser uma URL local ou externa.


Os arquivos de configuração do UserDir normalmente ficam em:

# No CentOS/RHEL:
/etc/httpd/conf.d/userdir.conf

# No Debian/Ubuntu:
/etc/apache2/mods-available/userdir.conf

Para habilitar o UserDir, normalmente é necessário comentar a opção:

UserDir disabled

Depois, descomente ou adicione a opção abaixo:

UserDir public_html

Após aplicar a configuração e reiniciar o daemon, cada usuário poderá criar um diretório chamado public_html dentro da sua home. Esse diretório será disponibilizado pelo Apache.


No Debian/Ubuntu, habilite o módulo com:

$ sudo a2enmod userdir

Depois reinicie o Apache:

$ sudo systemctl restart apache2

Não se esqueça de criar o diretório public_html dentro da home do usuário:

$ mkdir /home/vagrant/public_html

Depois ajuste as permissões:

$ chmod 755 /home/vagrant/public_html

Também é necessário permitir que o Apache consiga atravessar o diretório home do usuário:

$ chmod 711 /home/vagrant/

Agora acesse o IP ou nome do servidor usando ~usuario, exemplo:

http://192.168.121.36/~vagrant


Alias e Redirecionamentos


Existem duas ideias parecidas, mas importantes de separar:

  • Alias não faz redirecionamento. Ele mapeia uma URL para um diretório diferente no sistema de arquivos.
  • Redirect e RedirectMatch fazem redirecionamento HTTP, enviando o cliente para outro endereço.


Usando Alias


Com Alias, podemos fazer uma URL apontar para um diretório específico do servidor, exemplo:

<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

Alias /doc /var/www

<Directory /var/www/>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
</VirtualHost>

Nesse exemplo, ao acessar http://test.com.ze/doc/, o Apache servirá o conteúdo do diretório /var/www.



Usando RedirectMatch


O RedirectMatch faz um redirecionamento usando expressão regular, exemplo:

<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

RedirectMatch "^/doc/(.*)$" "https://www.sysnetbr.eng.br/docs/Certificacao/LPIC-2/intro/$1"
</VirtualHost>

Nesse caso, uma requisição para http://test.com.ze/doc/arquivo.html, será redirecionada para https://www.sysnetbr.eng.br/docs/Certificacao/LPIC-2/intro/arquivo.html.



Usando Redirect


O Redirect é usado para redirecionamentos mais simples, sem expressão regular, exemplo:

<VirtualHost *:80>
ServerAdmin fulano@gmail.com
DocumentRoot /home/vagrant/
ServerName test.com.ze

Redirect /doc "https://www.sysnetbr.eng.br/docs/Certificacao/LPIC-2/intro"
</VirtualHost>

Também podemos redirecionar arquivos dentro do próprio site:

Redirect /index.html /index.php

Esse exemplo faz com que acessos a /index.html sejam redirecionados para /index.php.



O Arquivo .htaccess


As configurações do servidor Web também podem ser realizadas por meio do arquivo .htaccess. Esse arquivo é conhecido como arquivo de configuração distribuído e fornece uma forma de aplicar alterações específicas de configuração por diretório.


Um arquivo .htaccess contendo uma ou mais diretivas de configuração pode ser colocado dentro de um diretório do site. As diretivas definidas nele serão aplicadas ao próprio diretório e também aos seus subdiretórios.


O nome .htaccess é o padrão, mas pode ser alterado por meio da diretiva AccessFileName. Esse recurso é muito utilizado, por exemplo, em ambientes de hospedagem compartilhada, onde o administrador de um domínio não tem acesso à configuração principal do servidor Web.


As configurações que poderão ser feitas por meio de arquivos .htaccess são determinadas pela diretiva AllowOverride, por exemplo:

<Directory /var/www/html>
AllowOverride All
</Directory>

Nesse caso, o Apache permitirá que diretivas válidas para o contexto .htaccess sejam usadas dentro desse diretório. Também é possível desabilitar o uso de .htaccess:

<Directory /var/www/html>
AllowOverride None
</Directory>

Nesse caso, o Apache ignorará arquivos .htaccess nesse diretório.


Em termos de desempenho e segurança, quando possível, é recomendado colocar as configurações diretamente nos arquivos principais do Apache ou nos arquivos de VirtualHost. O .htaccess é mais útil quando o usuário não tem acesso à configuração principal do servidor.


Mais detalhes na documentação oficial.



Fontes importantes


https://httpd.apache.org/

https://w3techs.com/technologies/overview/web_server

¹https://httpd.apache.org/docs/2.4/mod/prefork.html

¹https://httpd.apache.org/docs/trunk/mod/event.html

¹https://serverfault.com/a/383634/585058

https://www.liquidweb.com/kb/apache-performance-tuning-mpm-directives/

https://httpd.apache.org/docs/2.4/misc/perf-tuning.html

https://httpd.apache.org/docs/2.4/mod/mpm_common.html#maxsparethreads

https://en.wikipedia.org/wiki/Common_Gateway_Interface

https://en.wikibooks.org/wiki/Apache/CGI

https://httpd.apache.org/docs/current/mod/mod_log_config.html

https://en.wikipedia.org/wiki/List_of_HTTP_status_codes