← Volver al índice

Guía Paso a Paso: Servidor Multi-Dominio con DuckDNS y Apache

DuckDNS Apache2 Docker SSL/Let's Encrypt

Objetivo de esta guía: Explicar detalladamente cómo registrar subdominios gratuitos en DuckDNS, automatizar la actualización de IP pública residencial mediante tareas de sistema Linux y enrutar correctamente el tráfico entrante hacia múltiples microservicios en contenedores Docker mediante Apache como Proxy Inverso de Capa 7 con SSL/TLS automatizado.

1. Registro de Dominios en DuckDNS

La inmensa mayoría de las conexiones a internet residenciales disponen de direcciones IP públicas dinámicas asignadas por el proveedor de servicios (ISP). Esto significa que la IP cambia periódicamente o tras reiniciar el router. Para poder publicar servicios web o proyectos sin necesidad de contratar una IP fija comercial, utilizamos un servicio de DNS Dinámico (DDNS) como DuckDNS.

DuckDNS vincula nombres de dominio estables (ej. miproyecto.duckdns.org) a nuestra IP cambiante, respondiendo a las consultas DNS globales con la dirección de red más reciente de nuestro servidor.

  1. Acceso al Portal: Acceda a la plataforma oficial en duckdns.org.
  2. Autenticación OAuth Segura: Inicie sesión utilizando su cuenta de GitHub. Esto permite vincular su infraestructura de servidores a su perfil de desarrollador y aplicar mecanismos de doble factor (2FA).
  3. Límites del Plan Gratuito: Una única cuenta permite gestionar hasta 5 subdominios gratuitos de nivel superior (.duckdns.org).
  4. Creación de Nombres de Dominio: En la sección "sub domain", registre los subdominios que identificarán a los servicios independientes del servidor. Para esta arquitectura crearemos:
    • miproyecto-web.duckdns.org (Portal web y Dashboard HTML).
    • miproyecto-erp.duckdns.org (Instancia ERP de Odoo).
    • miproyecto-api.duckdns.org (Backend de microservicios Spring Boot).
  5. Token de Seguridad (Master Token): En la cabecera de la cuenta obtendrá su Token maestro (una cadena alfanumérica UUID). Este token actúa como credencial secreta para autenticar los scripts de actualización de la máquina host frente a los servidores de DuckDNS.

2. Arquitectura de Proxy Inverso y Enrutamiento de Puertos

Cuando desplegamos servicios aislados mediante tecnología de contenedores (Docker), cada aplicación escucha en un puerto de red interno en localhost (por ejemplo, Odoo en el puerto 8069 y Spring Boot en el 8080). Exponer estos puertos directamente a internet obligaría al usuario a escribir direcciones complejas como midominio.com:8069, lo que resulta ineficiente, poco estético y vulnerable ante escaneos de puertos directos.

Para resolverlo, colocamos un Proxy Inverso (Apache Web Server) actuando en la frontera de red (puertos estándar HTTP 80 y HTTPS 443). Apache recibe todas las peticiones públicas, examina la cabecera HTTP Host del navegador entrante y redirige el tráfico internamente hacia el contenedor Docker correspondiente.

Aislamiento de Capa 7: El Proxy Inverso permite que una única dirección IP pública y un único puerto estándar HTTPS (443) den servicio a decenas de aplicaciones independientes ejecutándose en puertos locales distintos.
graph LR User((Cliente Web / Navegador)) -- HTTPS/443 --> Apache[Apache Reverse Proxy] subgraph "Servidor Host (Linux / Raspberry Pi)" Apache -- miproyecto-web.duckdns.org --> HTML[Directorio Web /var/www/html] Apache -- miproyecto-erp.duckdns.org --> Odoo[Contenedor Odoo :8069] Apache -- miproyecto-api.duckdns.org --> Java[Contenedor Spring Boot :8080] end style Apache fill:#ffecb3,stroke:#fbc02d,stroke-width:2px style HTML fill:#c8e6c9,stroke:#388e3c,stroke-width:2px style Odoo fill:#e1bee7,stroke:#714b67,stroke-width:2px style Java fill:#ffcc80,stroke:#e65100,stroke-width:2px

3. Automatización de Actualización de IP (Script Cron)

Dado que los routers residenciales suelen carecer de clientes DDNS personalizables o bloquean proveedores externos, configuramos el propio sistema operativo Linux del servidor para que notifique a DuckDNS cualquier cambio en la IP pública cada 5 minutos mediante una tarea programada (Cron).

# 1. Crear directorio dedicado e iniciar el script bash
mkdir ~/duckdns && cd ~/duckdns
nano duck.sh
# Contenido del script (Consulta la API HTTPS de DuckDNS utilizando cURL): # echo url="https://www.duckdns.org/update?domains=miproyecto-web,miproyecto-erp,miproyecto-api&token=TU_TOKEN_SECRETO&ip=" | curl -k -o ~/duckdns/duck.log -K - # 2. Otorgar permisos de ejecución restrictivos (Solo el propietario puede leer/ejecutar)
chmod 700 duck.sh
# 3. Registrar el demonio en Crontab para ejecución en segundo plano cada 5 minutos
crontab -e
# Añadir la siguiente línea al final del fichero: # */5 * * * * ~/duckdns/duck.sh >/dev/null 2>&1

3.1. Verificación de Trazabilidad y Logs

Tras la puesta en marcha del script, realizamos una llamada manual de control para certificar que las peticiones cURL son aceptadas por los servidores de DuckDNS y que no existen bloqueos por parte del cortafuegos de salida.

# 1. Ejecutar el script manualmente
~/duckdns/duck.sh
# 2. Inspeccionar la respuesta escrita en el fichero de log
cat ~/duckdns/duck.log
✅ Respuesta esperada ("OK"): Indica que la actualización DNS ha sido procesada con éxito. La IP pública actual del servidor se ha asociado a todos los subdominios listados.
❌ Respuesta de error ("KO"): La solicitud ha sido rechazada por el API de DuckDNS. Verifique los siguientes puntos técnicos:

4. Configuración de VirtualHosts en Apache

Para cada subdominio registrado, debemos definir un fichero de VirtualHost en Apache (/etc/apache2/sites-available/). Esto instruye al servidor web sobre cómo procesar las solicitudes entrantes dependiendo de la cabecera HTTP ServerName.

4.1. Dashboard Principal (Página Estática HTML)

Servicio web directo apuntando al sistema de ficheros local donde residen la portada y las guías de esta biblioteca técnica.

📄 /etc/apache2/sites-available/000-default.conf
<VirtualHost *:80> ServerName miproyecto-web.duckdns.org DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined </VirtualHost>

4.2. Contenedor de ERP Odoo

Redirección mediante ProxyPass hacia el puerto 8069 expuesto por el contenedor Docker de Odoo. La directiva ProxyPreserveHost On es fundamental para mantener el dominio original en la sesión del cliente.

📄 /etc/apache2/sites-available/odoo-docker.conf
<VirtualHost *:80> ServerName miproyecto-erp.duckdns.org ProxyPreserveHost On ProxyRequests Off # ProxyPass hacia el puerto local expuesto por Docker ProxyPass / http://localhost:8069/ ProxyPassReverse / http://localhost:8069/ RequestHeader set "X-Forwarded-Proto" "https" </VirtualHost>

4.3. Contenedor de Backend Spring Boot (API Java)

Enrutamiento hacia el puerto 8080 donde escucha la aplicación ejecutable Java contenedorizada.

📄 /etc/apache2/sites-available/api-spring.conf
<VirtualHost *:80> ServerName miproyecto-api.duckdns.org ProxyPreserveHost On ProxyRequests Off # ProxyPass hacia el puerto local expuesto por Docker ProxyPass / http://localhost:8080/ ProxyPassReverse / http://localhost:8080/ RequestHeader set "X-Forwarded-Proto" "https" </VirtualHost>

5. Activación de Sitios y Certificados SSL (Certbot / Let's Encrypt)

Una vez creados los ficheros de VirtualHost, habilitamos la configuración en Apache e invocamos el cliente de automatización de certificados Certbot. Certbot utiliza el protocolo ACME para validar la propiedad de los dominios mediante el reto HTTP-01 y genera certificados X.509 firmados por Let's Encrypt de forma automática.

# 1. Habilitar las configuraciones en Apache y recargar el servicio
sudo a2ensite odoo-docker.conf api-spring.conf
sudo systemctl reload apache2
# 2. Invocación de Certbot para generar SSL y forzar la redirección automática a HTTPS (443)
sudo certbot --apache -d miproyecto-web.duckdns.org
sudo certbot --apache -d miproyecto-erp.duckdns.org
sudo certbot --apache -d miproyecto-api.duckdns.org

6. Permisos del Sistema de Ficheros (VS Code Remote SSH)

Para poder trabajar en el desarrollo del Dashboard web en /var/www/html directamente desde Visual Studio Code mediante la extensión Remote SSH sin requerir permisos de superusuario (sudo) constantes, ajustamos la propiedad POSIX del directorio asignándolo al usuario activo y manteniendo al grupo del servidor Apache (www-data).

# 1. Transferir la propiedad del directorio al usuario activo manteniendo el grupo www-data
sudo chown -R $USER:www-data /var/www/html
# 2. Configurar permisos 775 (Lectura/Escritura/Ejecución para usuario y grupo)
sudo chmod -R 775 /var/www/html
⚠️ Consideración de Seguridad para Producción: Los permisos 775 son adecuados en entornos de laboratorio o desarrollo local. En servidores de producción expuestos a alto tráfico, se deben aplicar permisos restrictivos 755 (directorios) y 644 (ficheros) para evitar que un proceso web comprometido modifique el código fuente estático.
← Volver a la portada ↑ Volver arriba
🏠