Seguridad
Configuraciones básicas de seguridad
Ocultar información del servidor
# En httpd.conf o apache2.conf
ServerTokens Prod
ServerSignature Off
Deshabilitar listado de directorios
<Directory "/var/www/html">
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
Configurar permisos de archivos
# Linux: Configurar permisos correctos
sudo find /var/www/html -type d -exec chmod 755 {} \;
sudo find /var/www/html -type f -exec chmod 644 {} \;
# Asegurar que Apache sea el propietario
sudo chown -R www-data:www-data /var/www/html # Ubuntu/Debian
sudo chown -R apache:apache /var/www/html # CentOS/RHEL
Restricciones de acceso por IP
<Directory "/var/www/html/admin">
Require ip 192.168.1.0/24
Require ip 10.0.0.0/8
# Denegar acceso desde otras IPs
</Directory>
Protección contra ataques comunes
<IfModule mod_rewrite.c>
RewriteEngine On
# Bloquear acceso a archivos sensibles
RewriteRule ^(.*/)?\.git/ - [F,L]
RewriteRule ^(.*/)?\.env$ - [F,L]
RewriteRule ^(.*/)?composer\.(json|lock)$ - [F,L]
# Proteger contra inyección SQL básica
RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
RewriteCond %{QUERY_STRING} GLOBALS(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} _REQUEST(=|\[|\%[0-9A-Z]{0,2}) [OR]
RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>|ê|"|;|\?|\*|=$).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(\'|%27|%25|%09|%22).* [NC]
RewriteRule ^(.*)$ - [F,L]
</IfModule>
SSL/TLS: Habilitar SSL
Ubuntu/Debian
# Habilitar módulo SSL
sudo a2enmod ssl
# Habilitar sitio SSL por defecto
sudo a2ensite default-ssl
# Reiniciar Apache
sudo systemctl restart apache2
CentOS/RHEL
# Instalar módulo SSL
sudo dnf install mod_ssl -y # CentOS 8+
sudo yum install mod_ssl -y # CentOS 7
# Reiniciar Apache
sudo systemctl restart httpd
Generar certificado autofirmado (desarrollo)
# Crear certificado autofirmado
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout /etc/ssl/private/apache-selfsigned.key \
-out /etc/ssl/certs/apache-selfsigned.crt
# Durante la generación, completar información:
# Country Name: ES
# State: Madrid
# City: Madrid
# Organization: Mi Empresa
# Unit: IT Department
# Common Name: midominio.com (IMPORTANTE)
# Email: admin@midominio.com
Configurar Virtual Host SSL
Ubuntu/Debian
sudo nano /etc/apache2/sites-available/midominio-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName midominio.com
ServerAlias www.midominio.com
DocumentRoot /var/www/midominio.com/public_html
SSLEngine on
SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt
SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key
# Configuración SSL moderna
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
<Directory /var/www/midominio.com/public_html>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/midominio.com_ssl_error.log
CustomLog ${APACHE_LOG_DIR}/midominio.com_ssl_access.log combined
</VirtualHost>
</IfModule>
# Habilitar sitio SSL
sudo a2ensite midominio-ssl.conf
sudo systemctl restart apache2
Let's Encrypt (certificado gratuito)
Instalar Certbot
# Ubuntu/Debian
sudo apt install certbot python3-certbot-apache -y
# CentOS/RHEL
sudo dnf install certbot python3-certbot-apache -y
Obtener certificado
# Obtener certificado para un dominio
sudo certbot --apache -d midominio.com -d www.midominio.com
# Renovación automática
sudo certbot renew --dry-run
# Configurar renovación automática
sudo crontab -e
# Agregar línea:
0 12 * * * /usr/bin/certbot renew --quiet
Optimización de Rendimiento
Configuración de MPM (Multi-Processing Module)
MPM Prefork (para aplicaciones que no son thread-safe)
<IfModule mpm_prefork_module>
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 256
MaxRequestWorkers 256
MaxConnectionsPerChild 0
</IfModule>
MPM Worker (mejor rendimiento, thread-safe)
<IfModule mpm_worker_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
MPM Event (mejor para contenido estático)
<IfModule mpm_event_module>
StartServers 3
MinSpareThreads 75
MaxSpareThreads 250
ThreadsPerChild 25
MaxRequestWorkers 400
MaxConnectionsPerChild 0
</IfModule>
Habilitar compresión
<IfModule mod_deflate.c>
# Comprimir contenido de texto
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/json
# No comprimir imágenes
SetEnvIfNoCase Request_URI \
\.(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI \
\.(?:exe|t?gz|zip|bz2|sit|rar)$ no-gzip dont-vary
</IfModule>
MPM y PHP (muy importante !)
Si vas a usar Apache como servidor PHP, el MPM que elijas afecta cómo se integra PHP con Apache. Hay dos enfoques principales:
1. Usando PHP como módulo (mod_php)
- Solo funciona con MPM prefork.
- Porque
mod_php
no es seguro para hilos, yprefork
es el único MPM sin hilos.
- Es simple y rápido para proyectos más pequeños o legacy.
2. Usando PHP-FPM (FastCGI Process Manager)
- Funciona con MPM worker o MPM event, que son más eficientes en memoria y rendimiento para muchas peticiones simultáneas.
- Más moderno, más seguro y escalable.
- Requiere configuración adicional para que Apache se comunique con PHP-FPM usando
proxy_fcgi
.
Si buscas simplicidad y compatibilidad amplia, mod_php + prefork está bien y mas que suficiente para tu servidor local. Pero si quieres mejor rendimiento y escalabilidad, te conviene usar PHP-FPM + event o worker.
Otras optimizaciones: Configurar caché con mod_expires
<IfModule mod_expires.c>
ExpiresActive on
# Imágenes
ExpiresByType image/jpg "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
ExpiresByType image/gif "access plus 1 month"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType image/x-icon "access plus 1 year"
# CSS y JavaScript
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
# Fuentes
ExpiresByType font/ttf "access plus 1 year"
ExpiresByType font/otf "access plus 1 year"
ExpiresByType font/woff "access plus 1 year"
ExpiresByType font/woff2 "access plus 1 year"
ExpiresByType application/font-woff "access plus 1 year"
# HTML y otros
ExpiresByType text/html "access plus 1 hour"
ExpiresByType application/pdf "access plus 1 month"
# Por defecto
ExpiresDefault "access plus 1 week"
</IfModule>
Configurar KeepAlive
# Mantener conexiones activas para múltiples requests
KeepAlive On
MaxKeepAliveRequests 100
KeepAliveTimeout 5
Optimizar límites de servidor
# Timeout para requests
Timeout 300
# Límite de tamaño de request
LimitRequestBody 10485760 # 10MB
# Límites de headers
LimitRequestFields 100
LimitRequestFieldSize 8190
LimitRequestLine 4094