Dia 19 - Configurar Apache para servir multiples sitios con Alias
Problema / Desafio
Preparar un servidor Apache en app server 2 para hospedar dos sitios web estaticos:
- Instalar
httpdy dependencias en app server 2 - Apache debe servir en el puerto 3004
- Copiar los backups
/home/thor/mediay/home/thor/clusterdesde el jump host al app server - Configurar Apache para que
http://localhost:3004/media/sirva el sitio media yhttp://localhost:3004/cluster/sirva el sitio cluster - Verificar con
curlque ambos sitios respondan correctamente
Conceptos clave
Directiva Alias en Apache
Alias permite mapear una URL a un directorio fuera (o dentro) del DocumentRoot. Apache sirve archivos desde esa ruta cuando el cliente accede a la URL especificada:
Sin Alias:
http://localhost/page.html → /var/www/html/page.html (DocumentRoot)
Con Alias:
http://localhost/media/ → /var/www/html/media/index.html
http://localhost/cluster/ → /var/www/html/cluster/index.html
Alias vs VirtualHost
| Metodo | Uso | Ejemplo |
|---|---|---|
Alias |
Multiples rutas en el mismo servidor/puerto | /media/, /cluster/ en :3004 |
VirtualHost |
Multiples dominios o puertos separados | site1.com:80, site2.com:80 |
Para este caso Alias es la solucion correcta porque ambos sitios comparten el mismo puerto y dominio, solo cambia la ruta.
Bloque Directory
Cada Alias necesita un bloque <Directory> que defina los permisos de acceso al directorio mapeado:
| Directiva | Funcion |
|---|---|
AllowOverride None |
No permite que archivos .htaccess sobreescriban la configuracion |
Require all granted |
Permite acceso a todos los clientes |
Require all denied |
Bloquea acceso a todos |
Require ip 192.168.1.0/24 |
Solo permite acceso desde un rango de IPs |
Sin el bloque <Directory> con Require all granted, Apache devuelve 403 Forbidden.
scp — Secure Copy
scp copia archivos entre hosts usando SSH. Es la forma mas directa de transferir archivos entre servidores:
| Flag | Funcion |
|---|---|
-r |
Copia recursiva (directorios completos) |
-P 2222 |
Puerto SSH diferente al default (22) |
-i key.pem |
Usar llave SSH especifica |
Pasos
- Conectarse al app server 2
- Instalar Apache (
httpd) - Cambiar el puerto de Apache a 3004
- Copiar los backups desde el jump host con
scp - Configurar los
Aliasen Apache para servir ambos sitios - Iniciar Apache y verificar con
curl
Comandos / Codigo
1. Instalar Apache en app server 2
2. Cambiar el puerto a 3004
sudo sed -i 's/Listen 80$/Listen 3004/' /etc/httpd/conf/httpd.conf
# Verificar
grep '^Listen' /etc/httpd/conf/httpd.conf
3. Copiar los backups desde el jump host
Desde el jump host, copiar los directorios al app server 2:
# Desde el jump host
scp -r /home/thor/media steve@stapp02:/tmp/
scp -r /home/thor/cluster steve@stapp02:/tmp/
Luego en el app server, mover a la ubicacion correcta:
Alternativa directa (si tienes permisos):
scp -r /home/thor/media steve@stapp02:/var/www/html/
scp -r /home/thor/cluster steve@stapp02:/var/www/html/
4. Configurar Apache para servir ambos sitios
Editar la configuracion de Apache:
Agregar al final del archivo los Alias y bloques Directory:
Alias /media "/var/www/html/media"
Alias /cluster "/var/www/html/cluster"
<Directory "/var/www/html/media">
AllowOverride None
Require all granted
</Directory>
<Directory "/var/www/html/cluster">
AllowOverride None
Require all granted
</Directory>
Nota: Como los directorios estan dentro de /var/www/html/ (que es el DocumentRoot por defecto), en este caso los Alias pueden no ser estrictamente necesarios ya que Apache serviria los subdirectorios automaticamente. Sin embargo, agregarlos es una buena practica porque:
- Hace explicita la configuracion
- Funciona igual si los directorios estuvieran fuera de DocumentRoot
- Los bloques <Directory> aseguran los permisos correctos
5. Iniciar Apache y verificar
6. Verificar ambos sitios
Ambos deben devolver el contenido HTML de sus respectivos index.html.
Cuando usar Alias vs DocumentRoot con subdirectorios
Caso 1: Directorios dentro de DocumentRoot
/var/www/html/media/ → http://localhost/media/ (funciona sin Alias)
/var/www/html/cluster/ → http://localhost/cluster/ (funciona sin Alias)
Caso 2: Directorios fuera de DocumentRoot (requiere Alias)
/opt/sites/media/ → Alias /media "/opt/sites/media"
/srv/apps/cluster/ → Alias /cluster "/srv/apps/cluster"
Si los archivos estan dentro de DocumentRoot, Apache los sirve automaticamente sin necesidad de Alias. Si estan fuera, Alias es obligatorio.
Otras formas de servir multiples sitios
VirtualHost por puerto
Si cada sitio necesita su propio puerto:
Listen 3004
Listen 3005
<VirtualHost *:3004>
DocumentRoot "/var/www/html/media"
</VirtualHost>
<VirtualHost *:3005>
DocumentRoot "/var/www/html/cluster"
</VirtualHost>
VirtualHost por nombre (Name-based)
Si se tienen diferentes dominios apuntando al mismo servidor:
<VirtualHost *:80>
ServerName media.example.com
DocumentRoot "/var/www/html/media"
</VirtualHost>
<VirtualHost *:80>
ServerName cluster.example.com
DocumentRoot "/var/www/html/cluster"
</VirtualHost>
Comparacion
| Metodo | Mismo puerto | Mismo dominio | Caso de uso |
|---|---|---|---|
Alias |
Si | Si | Multiples rutas bajo un dominio |
| VirtualHost por puerto | No | Si | Cada sitio en puerto diferente |
| VirtualHost por nombre | Si | No | Cada sitio con dominio propio |
Apache como Reverse Proxy
Apache puede actuar como reverse proxy usando mod_proxy, reenviando peticiones a servidores backend:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
<VirtualHost *:80>
ServerName app.example.com
ProxyPass "/" "http://localhost:8080/"
ProxyPassReverse "/" "http://localhost:8080/"
</VirtualHost>
Cliente → Apache:80 (proxy) → App Backend:8080
↑ │
└──────────────────────┘
ProxyPassReverse reescribe
headers de respuesta
| Directiva | Funcion |
|---|---|
ProxyPass |
Reenvia peticiones del cliente al backend |
ProxyPassReverse |
Reescribe headers de respuesta (Location, Content-Location) para que el cliente vea la URL del proxy, no del backend |
Excluir rutas del proxy
# No hacer proxy de archivos estaticos — servirlos directo
ProxyPass "/static/" "!"
ProxyPass "/" "http://localhost:8080/"
El "!" indica que esa ruta no se reenvia al backend. El orden importa: las exclusiones deben ir antes de la regla general.
Apache como Load Balancer
Con mod_proxy_balancer, Apache puede distribuir trafico entre multiples backends:
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
<Proxy "balancer://backend">
BalancerMember "http://stapp01:8080"
BalancerMember "http://stapp02:8080"
BalancerMember "http://stapp03:8080"
ProxySet lbmethod=byrequests
</Proxy>
<VirtualHost *:80>
ProxyPass "/" "balancer://backend/"
ProxyPassReverse "/" "balancer://backend/"
</VirtualHost>
Algoritmos de balanceo
| Algoritmo | Modulo | Comportamiento |
|---|---|---|
byrequests |
mod_lbmethod_byrequests |
Round Robin — distribuye por cantidad de peticiones |
bytraffic |
mod_lbmethod_bytraffic |
Por cantidad de bytes transferidos |
bybusyness |
mod_lbmethod_bybusyness |
Al servidor con menos peticiones activas |
heartbeat |
mod_lbmethod_heartbeat |
Basado en heartbeat reportado por el backend |
Opciones avanzadas de BalancerMember
<Proxy "balancer://backend">
BalancerMember "http://stapp01:8080" loadfactor=3
BalancerMember "http://stapp02:8080" loadfactor=1
BalancerMember "http://stapp03:8080" loadfactor=1 status=+H
</Proxy>
| Parametro | Funcion |
|---|---|
loadfactor=3 |
Peso del servidor — recibe 3x mas trafico |
status=+H |
Hot standby — solo recibe trafico si los otros caen |
retry=60 |
Segundos antes de reintentar un servidor caido |
timeout=10 |
Timeout de conexion al backend |
Comparacion Apache vs Nginx como proxy/LB
| Aspecto | Apache | Nginx |
|---|---|---|
| Configuracion | Mas verbosa (modulos explicitos) | Mas concisa (upstream + proxy_pass) |
| Rendimiento | Bueno, pero mas pesado por proceso/hilo | Mejor en conexiones concurrentes (event-driven) |
| Modulos | Dinamicos (LoadModule) |
Compilados generalmente |
| Caso de uso tipico | Ya tienes Apache y necesitas proxy | Proxy/LB dedicado |
| Hot reload | graceful restart |
nginx -s reload |
Otras configuraciones utiles de Apache
mod_rewrite — Reescritura de URLs
LoadModule rewrite_module modules/mod_rewrite.so
<VirtualHost *:80>
RewriteEngine On
# Redirigir HTTP a HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
# URL amigable: /producto/123 → /index.php?id=123
RewriteRule ^/producto/([0-9]+)$ /index.php?id=$1 [L]
</VirtualHost>
| Flag | Significado |
|---|---|
[R=301] |
Redirect con codigo 301 (permanente) |
[L] |
Last — no procesar mas reglas |
[QSA] |
Query String Append — mantener parametros existentes |
[NC] |
No Case — ignorar mayusculas/minusculas |
mod_headers — Manipulacion de headers
LoadModule headers_module modules/mod_headers.so
# Seguridad
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# Cache
Header set Cache-Control "max-age=86400, public"
# CORS
Header set Access-Control-Allow-Origin "*"
| Header | Funcion |
|---|---|
X-Frame-Options |
Previene que la pagina se cargue en un iframe (clickjacking) |
X-Content-Type-Options |
Evita que el navegador adivine el tipo MIME |
X-XSS-Protection |
Activa filtro XSS del navegador |
Strict-Transport-Security |
Fuerza HTTPS por el tiempo indicado |
mod_expires — Cache de archivos estaticos
LoadModule expires_module modules/mod_expires.so
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType text/css "access plus 7 days"
ExpiresByType application/javascript "access plus 7 days"
ExpiresByType text/html "access plus 1 hour"
</IfModule>
mod_security — WAF (Web Application Firewall)
LoadModule security2_module modules/mod_security2.so
<IfModule mod_security2.c>
SecRuleEngine On
SecRequestBodyLimit 10485760
# Bloquear SQL injection basico
SecRule ARGS "@detectSQLi" "id:1,deny,status:403,msg:'SQL Injection detected'"
# Bloquear XSS basico
SecRule ARGS "@detectXSS" "id:2,deny,status:403,msg:'XSS detected'"
</IfModule>
mod_security inspecciona las peticiones entrantes y bloquea patrones maliciosos antes de que lleguen a la aplicacion.
Autenticacion basica
# Crear archivo de passwords
# htpasswd -c /etc/httpd/.htpasswd admin
<Directory "/var/www/html/admin">
AuthType Basic
AuthName "Area Restringida"
AuthUserFile /etc/httpd/.htpasswd
Require valid-user
</Directory>
| Comando htpasswd | Funcion |
|---|---|
htpasswd -c archivo usuario |
Crear archivo y agregar primer usuario |
htpasswd archivo usuario |
Agregar usuario a archivo existente |
htpasswd -D archivo usuario |
Eliminar usuario |
Limitar metodos HTTP
<Directory "/var/www/html">
# Solo permitir GET y POST
<LimitExcept GET POST>
Require all denied
</LimitExcept>
</Directory>
Resumen de modulos de Apache
| Modulo | Funcion |
|---|---|
mod_proxy |
Reverse proxy |
mod_proxy_balancer |
Load balancing |
mod_rewrite |
Reescritura de URLs |
mod_headers |
Manipulacion de headers HTTP |
mod_expires |
Cache por tipo de contenido |
mod_security |
WAF — proteccion contra ataques web |
mod_ssl |
Soporte HTTPS/TLS |
mod_alias |
Mapeo de URLs a directorios (Alias) |
mod_auth_basic |
Autenticacion basica HTTP |
mod_deflate |
Compresion gzip de respuestas |
Troubleshooting
| Problema | Solucion |
|---|---|
403 Forbidden al acceder a /media/ o /cluster/ |
Verificar que existe el bloque <Directory> con Require all granted. Verificar permisos del directorio: ls -la /var/www/html/media/ |
404 Not Found |
Verificar que los directorios existen y contienen archivos. Verificar que el Alias apunta a la ruta correcta |
curl: (7) Failed to connect |
Apache no esta corriendo o no escucha en el puerto 3004. Verificar con systemctl status httpd y ss -tunlp \| grep 3004 |
scp: Permission denied |
Copiar a /tmp/ primero y luego mover con sudo cp -r. O usar sudo en el destino |
| Apache no inicia despues de cambiar puerto | Verificar sintaxis: httpd -t. Verificar que no haya otro proceso en el puerto 3004 |
| Archivos copiados pero sin acceso | Verificar owner: sudo chown -R apache:apache /var/www/html/media /var/www/html/cluster |