Qué es un Virtual Host (vhost) basado en nombre
Un Virtual Host basado en nombre permite servir múltiples sitios web desde la misma IP/puerto (por ejemplo, *:80), diferenciándolos por el nombre de dominio que el cliente solicita. Apache decide qué sitio entregar leyendo el encabezado HTTP Host y comparándolo con la configuración de los bloques <VirtualHost>.
Flujo de resolución: DNS/hosts → Host header → selección de vhost
- DNS o /etc/hosts: el nombre (p. ej.
site1.local) se resuelve a una IP (p. ej.127.0.0.1o la IP del servidor). - Cliente envía HTTP: al conectarse a esa IP, el navegador/curl envía el encabezado
Host: site1.local. - Apache hace matching: busca un
<VirtualHost IP:PUERTO>que coincida con la IP/puerto de la conexión y, dentro de esos, el que coincida conServerName/ServerAlias. Si no hay coincidencia, usa el vhost por defecto (normalmente el primero cargado para ese IP:puerto).
Estructura del bloque <VirtualHost>
Un vhost típico incluye: identidad del sitio (ServerName/ServerAlias), raíz de documentos (DocumentRoot), permisos/directivas por directorio y logs separados para facilitar diagnóstico.
<VirtualHost *:80> ServerName ejemplo.local ServerAlias www.ejemplo.local DocumentRoot /var/www/ejemplo/public ErrorLog ${APACHE_LOG_DIR}/ejemplo_error.log CustomLog ${APACHE_LOG_DIR}/ejemplo_access.log combined <Directory /var/www/ejemplo/public> Require all granted </Directory></VirtualHost>ServerName y ServerAlias
ServerName: nombre principal del sitio (debe ser único por IP:puerto).ServerAlias: nombres alternativos que deben servir el mismo sitio (p. ej.www, subdominios, etc.).
DocumentRoot por sitio
Cada vhost debe apuntar a su propio directorio de contenido. Esto evita mezclar archivos y permite despliegues independientes. Mantén una estructura consistente, por ejemplo:
/var/www/site1/public/ /var/www/site2/public/Logs separados por sitio
Separar logs por vhost acelera el troubleshooting. Usa ErrorLog y CustomLog con nombres distintos por sitio. En Debian/Ubuntu suele existir ${APACHE_LOG_DIR} (normalmente /var/log/apache2).
Práctica guiada: dos sitios en el mismo servidor (name-based)
Objetivo: servir site1.local y site2.local desde el mismo Apache en el puerto 80, con DocumentRoot y logs separados, simulando DNS con /etc/hosts y validando con curl.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
Paso 1: crear directorios y contenido mínimo
sudo mkdir -p /var/www/site1/public sudo mkdir -p /var/www/site2/publicecho 'SITE 1 OK' | sudo tee /var/www/site1/public/index.html echo 'SITE 2 OK' | sudo tee /var/www/site2/public/index.htmlVerifica permisos/propietario según tu política del sistema (lo importante es que Apache pueda leer esos archivos).
Paso 2: crear los archivos de sitio (vhosts)
En Debian/Ubuntu, lo habitual es crear archivos en /etc/apache2/sites-available/. Crea dos archivos: site1.conf y site2.conf.
sudo nano /etc/apache2/sites-available/site1.conf<VirtualHost *:80> ServerName site1.local ServerAlias www.site1.local DocumentRoot /var/www/site1/public ErrorLog ${APACHE_LOG_DIR}/site1_error.log CustomLog ${APACHE_LOG_DIR}/site1_access.log combined <Directory /var/www/site1/public> Require all granted </Directory></VirtualHost>sudo nano /etc/apache2/sites-available/site2.conf<VirtualHost *:80> ServerName site2.local ServerAlias www.site2.local DocumentRoot /var/www/site2/public ErrorLog ${APACHE_LOG_DIR}/site2_error.log CustomLog ${APACHE_LOG_DIR}/site2_access.log combined <Directory /var/www/site2/public> Require all granted </Directory></VirtualHost>Nota: si tu Apache está escuchando en otra IP/puerto, ajusta *:80 a la combinación correcta (por ejemplo, 192.168.1.10:80).
Paso 3: habilitar sitios y deshabilitar el sitio por defecto
En Debian/Ubuntu, se usan a2ensite y a2dissite para gestionar enlaces en sites-enabled.
sudo a2ensite site1.conf sudo a2ensite site2.confSi existe el sitio por defecto (000-default.conf) y no lo quieres, desactívalo:
sudo a2dissite 000-default.confPaso 4: validar sintaxis y recargar sin cortar conexiones
Antes de aplicar cambios, valida la configuración:
sudo apachectl configtestPara aplicar cambios sin cortar conexiones, usa reload (recarga graciosa):
sudo systemctl reload apache2Alternativa equivalente (según distro):
sudo apachectl gracefulDiferencia práctica: reload/graceful recarga configuración manteniendo procesos/hilos atendiendo conexiones existentes; restart reinicia el servicio y puede interrumpir conexiones.
Paso 5: simular DNS con /etc/hosts
En tu máquina cliente (o en el mismo servidor si pruebas local), agrega entradas a /etc/hosts apuntando a la IP del servidor. Si pruebas en la misma máquina, puedes usar 127.0.0.1.
sudo nano /etc/hosts127.0.0.1 site1.local 127.0.0.1 site2.localPaso 6: validar con curl (incluyendo -H 'Host:')
Prueba por nombre (si /etc/hosts ya resuelve):
curl -i http://site1.local/ curl -i http://site2.local/Prueba forzando el encabezado Host (útil si apuntas a una IP directamente o si quieres verificar el matching):
curl -i http://127.0.0.1/ -H 'Host: site1.local' curl -i http://127.0.0.1/ -H 'Host: site2.local'Debes ver en el cuerpo SITE 1 OK o SITE 2 OK según el Host enviado.
Cómo Apache decide el vhost: reglas prácticas de matching
1) Coincidencia por IP:puerto del bloque <VirtualHost>
Apache primero agrupa vhosts por el par IP:PUERTO (por ejemplo, todos los *:80). Si tu conexión entra por :80, solo compiten los vhosts definidos para :80.
2) Coincidencia por ServerName/ServerAlias vs Host header
Dentro del grupo, compara el valor del encabezado Host con ServerName y ServerAlias. Si coincide, ese vhost se usa para servir la petición.
3) Sitio por defecto (default vhost)
Si no hay coincidencia por nombre, Apache usa el primer vhost cargado para ese IP:PUERTO. Por eso el orden de carga importa.
Detectar cuál es el sitio por defecto y el orden de carga
Para ver qué vhosts están activos y cuál actúa como default, usa:
sudo apachectl -SEste comando muestra los vhosts por puerto, el archivo donde se definen y marca el default para cada IP:PUERTO. Si al pedir un dominio inexistente te responde un sitio “equivocado”, normalmente estás cayendo en el vhost por defecto.
Procedimientos de administración: habilitar, deshabilitar y aplicar cambios
Habilitar un sitio
sudo a2ensite site1.conf sudo apachectl configtest sudo systemctl reload apache2Deshabilitar un sitio
sudo a2dissite site2.conf sudo apachectl configtest sudo systemctl reload apache2Errores comunes al habilitar/deshabilitar
- Olvidar recargar: habilitar/deshabilitar no aplica hasta
reload. - Conflicto de ServerName: dos vhosts con el mismo
ServerNameen el mismoIP:PUERTOgeneran comportamiento inesperado. - DocumentRoot incorrecto: si apunta a un directorio inexistente, verás errores en el
ErrorLogdel vhost (si está bien separado) o en el log general.
Verificación con logs separados (diagnóstico rápido)
Tras hacer peticiones con curl, revisa accesos y errores por sitio:
sudo tail -n 50 /var/log/apache2/site1_access.log sudo tail -n 50 /var/log/apache2/site1_error.log sudo tail -n 50 /var/log/apache2/site2_access.log sudo tail -n 50 /var/log/apache2/site2_error.logSi envías Host: site1.local y el acceso aparece en site2_access.log, el matching no está funcionando como esperas (revisa ServerName/ServerAlias, el puerto, y el orden/default con apachectl -S).
Ejercicios prácticos recomendados
Ejercicio A: comprobar el vhost por defecto
- Deja habilitados
site1ysite2. - Haz una petición con un host inexistente:
curl -i http://127.0.0.1/ -H 'Host: noexiste.local'- Identifica qué sitio respondió y confirma con
sudo apachectl -Scuál es el default para*:80.
Ejercicio B: probar ServerAlias
- Agrega en
/etc/hosts:
127.0.0.1 www.site1.local- Valida:
curl -i http://127.0.0.1/ -H 'Host: www.site1.local'Ejercicio C: deshabilitar un sitio y observar el fallback
- Deshabilita
site2:
sudo a2dissite site2.conf sudo apachectl configtest sudo systemctl reload apache2- Vuelve a pedir
site2.local:
curl -i http://127.0.0.1/ -H 'Host: site2.local'- Observa qué sitio responde ahora (probablemente el default) y verifica el motivo con
apachectl -S.