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.
- Acceso al Portal: Acceda a la plataforma oficial en duckdns.org.
- 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).
- Límites del Plan Gratuito: Una única cuenta permite gestionar hasta 5 subdominios gratuitos de nivel superior (.duckdns.org).
- 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).
- 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).
mkdir ~/duckdns && cd ~/duckdns
nano duck.sh
chmod 700 duck.sh
crontab -e
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.
~/duckdns/duck.sh
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:
- Compruebe que el Token sea exacto y no contenga espacios ni saltos de línea accidentalmente copiados.
- Asegúrese de que los subdominios (
domains=...) estén separados estrictamente por comas sin espacios intermedios.
- Confirme que el binario
curl está instalado y dispone de conectividad de salida por el puerto 443.
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.
<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.
<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.
<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.
sudo a2ensite odoo-docker.conf api-spring.conf
sudo systemctl reload apache2
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).
sudo chown -R $USER:www-data /var/www/html
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.