Salta el contingut

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

# Instal·lar mod_php
sudo apt install libapache2-mod-php8.1

# Verificar mòdul
php -v

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