Apache HTTP Server
Introducció a Apache
La història d'Apache HTTP Server comença al febrer de 1995, però les seves arrels es remunten a un projecte anterior: el servidor web NCSA HTTPd. Aquest servidor havia estat desenvolupat per Rob McCool al National Center for Supercomputing Applications (NCSA) de la Universitat d'Illinois, i a principis de 1995 era el servidor web més popular d'Internet.
A dia d'avui és un dels servidors web més utilitzats (quasi un 20% de tots els servidors web l'utilitzen)
Instal·lació i Configuració Bàsica en Ubuntu/Debian
# Actualitzar repositoris
sudo apt update
# Instal·lar Apache
sudo apt install apache2
# Verificar estat
sudo systemctl status apache2
# Habilitar a l'arrencada
sudo systemctl enable apache2
Estructura de Directoris Ubuntu/Debian
/etc/apache2/
├── apache2.conf # Configuració principal
├── ports.conf # Ports d'escolta
├── mods-available/ # Mòduls disponibles
├── mods-enabled/ # Mòduls habilitats
├── sites-available/ # Llocs disponibles
├── sites-enabled/ # Llocs habilitats
├── conf-available/ # Configuracions disponibles
└── conf-enabled/ # Configuracions habilitades
Mòduls d'Apache
Apache és un servidor modular on només la funcionalitat bàsica està inclosa al nucli. Les funcions esteses estan disponibles a través de mòduls que es poden carregar dinàmicament.
Gestió de Mòduls en Debian/Ubuntu
# Llistar mòduls disponibles
ls /etc/apache2/mods-available/
# Habilitar mòdul
sudo a2enmod nom_modul
# Deshabilitar mòdul
sudo a2dismod nom_modul
# Exemples comuns
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod headers
sudo a2enmod proxy proxy_http
# Reiniciar per aplicar canvis
sudo systemctl restart apache2
Mòduls Essencials
mod_rewrite El mòdul mod_rewrite permet reescriure URLs basant-se en regles utilitzant expressions regulars.
# Habilitar mod_rewrite
RewriteEngine On
# Redirigir HTTP a HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# URL amigables
RewriteRule ^producte/([0-9]+)/([a-z-]+)$ producte.php?id=$1&nom=$2 [L]
mod_ssl
# Configuració SSL bàsica
<VirtualHost *:443>
SSLEngine on
SSLCertificateFile /etc/ssl/certs/cert.pem
SSLCertificateKeyFile /etc/ssl/private/key.pem
SSLCertificateChainFile /etc/ssl/certs/chain.pem
# Protocols segurs
SSLProtocol -all +TLSv1.2 +TLSv1.3
# Xifratge fort
SSLCipherSuite HIGH:!aNULL:!MD5
</VirtualHost>
Virtual Hosts
Els Virtual Hosts permeten allotjar múltiples llocs web en un sol servidor.
Configuració de Virtual Host
# /etc/apache2/sites-available/exemple.conf
<VirtualHost *:80>
ServerName www.exemple.cat
ServerAlias exemple.cat
ServerAdmin admin@exemple.cat
DocumentRoot /var/www/exemple
<Directory /var/www/exemple>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/exemple-error.log
CustomLog ${APACHE_LOG_DIR}/exemple-access.log combined
# PHP-FPM (si s'utilitza)
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
</FilesMatch>
</VirtualHost>
Activar Virtual Host
# Habilitar lloc
sudo a2ensite exemple.conf
# Deshabilitar lloc per defecte
sudo a2dissite 000-default.conf
# Reiniciar Apache
sudo systemctl reload apache2
AC0375/03/03 — Miniactivitat
RA3 · CA3b, CA3c, CA3d, CA3e
Instal·la Apache en una màquina virtual o contenidor Linux i configura dos Virtual Hosts per noms diferents (per exemple www.empresa1.local i www.empresa2.local), cadascun amb el seu propi DocumentRoot. Comprova amb curl -H "Host: ..." o editant el fitxer hosts del client que cada nom respon amb el contingut correcte.
Control d'Accés i Autenticació
Autenticació Bàsica
<Directory /var/www/privat>
AuthType Basic
AuthName "Àrea Restringida"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user
</Directory>
# Crear fitxer de contrasenyes
sudo htpasswd -c /etc/apache2/.htpasswd usuari1
sudo htpasswd /etc/apache2/.htpasswd usuari2
Control d'Accés per IP
<Directory /var/www/admin>
# Denegar accés per defecte
Require all denied
# Permetre IPs específiques
Require ip 192.168.1.0/24
Require ip 10.0.0.5
</Directory>
Configuració Bàsica de Proxy Invers
mod_proxy permet a Apache funcionar com a servidor proxy/gateway, redirigint connexions a altres servidors.
# Habilitar mòduls necessaris
sudo a2enmod proxy proxy_http proxy_balancer lbmethod_byrequests
# Configuració del proxy
<VirtualHost *:80>
ServerName app.exemple.cat
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# Opcions addicionals
<Proxy *>
Order allow,deny
Allow from all
</Proxy>
</VirtualHost>
Balanceig de Càrrega
<Proxy balancer://mycluster>
BalancerMember http://backend1.local:8080
BalancerMember http://backend2.local:8080
BalancerMember http://backend3.local:8080
# Mètode de balanceig
ProxySet lbmethod=byrequests
</Proxy>
ProxyPass / balancer://mycluster/
ProxyPassReverse / balancer://mycluster/
Configuració de PHP
Apache pot integrar PHP utilitzant mod_php o PHP-FPM, essent PHP-FPM la opció recomanada per a millor rendiment.
Configuració amb mod_php
Configuració amb PHP-FPM (Recomanat)
# Instal·lar PHP-FPM
sudo apt install php8.1-fpm php8.1-common php8.1-mysql
# Habilitar mòduls necessaris
sudo a2enmod proxy_fcgi setenvif
sudo a2enconf php8.1-fpm
# Deshabilitar mod_php si està instal·lat
sudo a2dismod php8.1
# Canviar MPM a event (millor rendiment)
sudo a2dismod mpm_prefork
sudo a2enmod mpm_event
sudo systemctl restart apache2
Configuració de PHP-FPM Pool
# /etc/php/8.1/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data
listen = /run/php/php8.1-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35
pm.max_requests = 500
Fitxer .htaccess
El fitxer .htaccess permet configurar Apache a nivell de directori sense accedir a la configuració principal.
Exemples d'ús de .htaccess
Redireccions i Reescriptura
# Activar mod_rewrite
RewriteEngine On
# Redirigir www a no-www
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# Eliminar extensió .php
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.php -f
RewriteRule ^(.*)$ $1.php [L]
# Pàgina d'error personalitzada
ErrorDocument 404 /errors/404.html
ErrorDocument 500 /errors/500.html
# Prevenir hotlinking d'imatges
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?exemple\.cat [NC]
RewriteRule \.(jpg|jpeg|png|gif|bmp)$ - [F,NC]
Seguretat
# Denegar accés a fitxers sensibles
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
# Protegir contra injeccions
Options -Indexes
Options -ExecCGI
# Headers de seguretat
Header set X-Frame-Options "SAMEORIGIN"
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Optimització
# Compressió GZIP
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/plain text/xml
AddOutputFilterByType DEFLATE text/css text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
</IfModule>
# Cache del navegador
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
</IfModule>
Seguretat i Certificats SSL/TLS
Certificats amb Let's Encrypt
Let's Encrypt és una Autoritat de Certificació que facilita l'obtenció i instal·lació de certificats TLS/SSL gratuïts.
Apache amb Let's Encrypt (Certbot)
# Instal·lar Certbot
sudo apt update
sudo apt install certbot python3-certbot-apache
# Obtenir certificat
sudo certbot --apache -d exemple.cat -d www.exemple.cat
# Renovació automàtica
sudo certbot renew --dry-run
# Configurar cron per renovació
sudo crontab -e
# Afegir:
0 2 * * * /usr/bin/certbot renew --quiet
AC0375/03/05 — Miniactivitat
RA3 · CA3f, CA3g
Genera un certificat (autosignat o amb Let's Encrypt si el servidor és accessible des d'Internet) per a un dels teus Virtual Hosts, configura'l amb SSLEngine on i restringeix els protocols a TLS 1.2/1.3. Verifica'n la validesa amb openssl s_client -connect <host>:443 i comprova que la redirecció HTTP→HTTPS funciona.
Configuració SSL/TLS Segura
Apache - Configuració SSL Avançada
<VirtualHost *:443>
SSLEngine on
# Certificats
SSLCertificateFile /etc/letsencrypt/live/exemple.cat/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/exemple.cat/privkey.pem
# Protocols (només TLS 1.2 i 1.3)
SSLProtocol -all +TLSv1.2 +TLSv1.3
# Cipher Suites segures
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
# Preferència del servidor
SSLHonorCipherOrder off
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# Headers de seguretat
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
</VirtualHost>
Hardening de Seguretat
Apache - Ocultació d'Informació
# Ocultar versió d'Apache
ServerTokens Prod
ServerSignature Off
# Deshabilitar mètodes HTTP no necessaris
<Directory /var/www>
<LimitExcept GET POST HEAD>
Require all denied
</LimitExcept>
</Directory>
# Timeout i límits
Timeout 60
KeepAliveTimeout 5
MaxKeepAliveRequests 100
LimitRequestBody 10485760
LimitRequestFields 50
LimitRequestFieldSize 8190
LimitRequestLine 8190
Monitoratge i optimització
Registres (Logs)
Apache - Configuració de Logs
# Format personalitzat
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" custom
# Logs separats per Virtual Host
<VirtualHost *:80>
ErrorLog ${APACHE_LOG_DIR}/exemple-error.log
CustomLog ${APACHE_LOG_DIR}/exemple-access.log custom
# Nivell de log (debug, info, notice, warn, error, crit, alert, emerg)
LogLevel warn
</VirtualHost>
# Rotació de logs amb logrotate
# /etc/logrotate.d/apache2
/var/log/apache2/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 640 www-data adm
sharedscripts
postrotate
systemctl reload apache2 > /dev/null
endscript
}
5.2 Monitoratge del Rendiment
Apache - mod_status
# Habilitar mod_status
sudo a2enmod status
# Configuració
<Location /server-status>
SetHandler server-status
Require ip 127.0.0.1
Require ip 192.168.1.0/24
</Location>
# Accedir a: http://servidor/server-status
# Format màquina: http://servidor/server-status?auto
Optimització del Rendiment
Apache - Tuning MPM
# MPM Event (recomanat per alta concurrència)
<IfModule mpm_event_module>
StartServers 4
MinSpareThreads 25
MaxSpareThreads 75
ThreadLimit 64
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 10000
KeepAlive On
KeepAliveTimeout 5
MaxKeepAliveRequests 100
</IfModule>
Casos pràctics i escenaris avançats
Escenari 1: Multidomini amb SSL i Proxy Invers
Apache
# Domini principal amb aplicació PHP
<VirtualHost *:443>
ServerName www.empresa.cat
DocumentRoot /var/www/empresa
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/empresa.cat/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/empresa.cat/privkey.pem
<FilesMatch \.php$>
SetHandler "proxy:unix:/run/php/php8.1-fpm.sock|fcgi://localhost/"
</FilesMatch>
</VirtualHost>
# Subdomini API amb proxy a Node.js
<VirtualHost *:443>
ServerName api.empresa.cat
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/api.empresa.cat/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/api.empresa.cat/privkey.pem
ProxyPreserveHost On
ProxyPass / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/
# WebSocket support
RewriteEngine On
RewriteCond %{HTTP:Upgrade} websocket [NC]
RewriteCond %{HTTP:Connection} upgrade [NC]
RewriteRule ^/?(.*) "ws://localhost:3000/$1" [P,L]
</VirtualHost>
# Subdomini estàtic amb CDN
<VirtualHost *:443>
ServerName static.empresa.cat
DocumentRoot /var/www/static
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/static.empresa.cat/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/static.empresa.cat/privkey.pem
# Cache agressiu per recursos estàtics
<Directory /var/www/static>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
Header set Cache-Control "public, immutable"
Header unset ETag
FileETag None
</IfModule>
</Directory>
</VirtualHost>
Escenari 2: Alta Disponibilitat amb Balanceig
Apache - Configuració HA
# Balanceig amb health checks
<Proxy balancer://backend>
BalancerMember http://server1:8080 route=s1 connectiontimeout=5 timeout=30 retry=60
BalancerMember http://server2:8080 route=s2 connectiontimeout=5 timeout=30 retry=60
BalancerMember http://server3:8080 route=s3 connectiontimeout=5 timeout=30 retry=60 status=+H
ProxySet lbmethod=byrequests
ProxySet stickysession=ROUTEID
ProxySet nofailover=On
</Proxy>
# Health check endpoint
<Location /balancer-manager>
SetHandler balancer-manager
Require ip 192.168.1.0/24
</Location>
ProxyPass /static !
ProxyPass / balancer://backend/
ProxyPassReverse / balancer://backend/
# Session affinity amb cookies
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
IIS - ARR amb Health Monitoring
<configuration>
<webFarms>
<webFarm name="ProductionFarm" enabled="true">
<server address="192.168.1.10" enabled="true" />
<server address="192.168.1.11" enabled="true" />
<server address="192.168.1.12" enabled="true" />
<applicationRequestRouting>
<loadBalancing algorithm="WeightedRoundRobin" />
<affinity useCookie="true" cookieName="ARRAffinity" />
<healthCheck url="http://{SERVER}/health"
interval="00:00:30"
timeout="00:00:10"
responseMatch="200" />
</applicationRequestRouting>
</webFarm>
</webFarms>
<rewrite>
<rules>
<rule name="ARR_ProductionFarm">
<match url=".*" />
<action type="Rewrite" url="http://ProductionFarm/{R:0}" />
</rule>
</rules>
</rewrite>
</configuration>
Escenari 3: Migració Zero-Downtime
#!/bin/bash
# Script de migració Apache amb zero downtime
# 1. Preparar nova configuració
cp /etc/apache2/sites-available/old.conf /etc/apache2/sites-available/new.conf
# 2. Modificar nova configuració
sed -i 's/DocumentRoot \/var\/www\/old/DocumentRoot \/var\/www\/new/g' /etc/apache2/sites-available/new.conf
# 3. Verificar configuració
apache2ctl configtest
if [ $? -eq 0 ]; then
# 4. Reload gradual
echo "Iniciant migració..."
# Habilitar nova configuració
a2ensite new.conf
# Reload suau (manté connexions existents)
systemctl reload apache2
# Esperar que acabin connexions antigues
sleep 30
# Deshabilitar antiga configuració
a2dissite old.conf
systemctl reload apache2
echo "Migració completada"
else
echo "Error en la configuració"
exit 1
fi