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 desde cero cómo registrar dominios gratuitos, automatizar la actualización de la IP pública sin depender del router, y enrutar correctamente el tráfico web hacia contenedores Docker independientes utilizando Apache como Proxy Inverso.
1. Registro de Dominios en DuckDNS
DuckDNS es un servicio de DNS Dinámico (DDNS) gratuito y sin caducidad mensual. Para empezar, necesitamos vincular nuestra IP pública a nombres de dominio legibles.
- Acceso: Entra en duckdns.org.
- Autenticación Segura: Inicia sesión utilizando un proveedor OAuth. Recomendamos encarecidamente usar GitHub para mantener tu infraestructura vinculada a tu perfil de desarrollador y garantizar un acceso seguro con autenticación en dos pasos (2FA).
- Límites: Una cuenta gratuita te permite registrar hasta 5 dominios (subdominios de .duckdns.org).
- Creación: En la casilla "sub domain", escribe el nombre deseado y pulsa "add domain". Para esta arquitectura crearemos tres:
pi5appserver.duckdns.org (Para nuestro Dashboard web HTML).
pi5odoo.duckdns.org (Para nuestro contenedor de Odoo).
levelup42.duckdns.org (Para nuestra futura API de Spring Boot).
- El Token de Seguridad: En la parte superior de la página principal, verás un campo llamado Token (una cadena larga de números y letras, ej.
a1b2c3d4...). Cópialo; es la clave maestra que usará nuestro servidor para identificarse.
2. Entendiendo el Proxy Inverso y los Puertos (Localhost)
¿Por qué usamos direcciones como localhost:8069 en nuestra configuración? La respuesta está en la contenedorización (Docker).
Concepto Clave: Cuando desplegamos una aplicación en Docker, esta se ejecuta de forma aislada. Odoo, por defecto, escucha en el puerto 8069 dentro de su contenedor. Spring Boot escucha en el 8080.
A través de Docker, "mapeamos" esos puertos internos hacia nuestra Raspberry Pi host (localhost). Como no es seguro ni estético obligar al usuario final a escribir números de puerto en su navegador, colocamos un Proxy Inverso (Apache) en la puerta principal (puertos 80/443). Apache recibe el tráfico de los dominios limpios y lo redirige internamente al puerto de localhost correspondiente.
graph LR
User((Cliente Web)) -- HTTPS/443 --> Apache[Apache Reverse Proxy]
subgraph "Raspberry Pi 5 Server"
Apache -- pi5appserver.duckdns.org --> HTML[Directorio Web /var/www/html]
Apache -- pi5odoo.duckdns.org --> Odoo[Docker Odoo :8069]
Apache -- levelup42.duckdns.org --> Java[Docker 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 la IP (Script Cron)
Dado que muchos routers bloquean o no incluyen DuckDNS, configuraremos la propia Raspberry Pi para que actualice la IP pública automáticamente cada 5 minutos.
mkdir ~/duckdns && cd ~/duckdns
nano duck.sh
chmod 700 duck.sh
crontab -e
3.1. Verificación de Conexión (Logs)
Una vez creado el script y programada la tarea, es fundamental realizar una prueba manual para comprobar que nuestra Raspberry Pi se está comunicando correctamente con los servidores de DuckDNS.
~/duckdns/duck.sh
cat ~/duckdns/duck.log
✅ Si el log responde "OK": ¡Éxito absoluto! Tu IP pública se ha sincronizado correctamente. La Raspberry Pi ya es autónoma y mantendrá tus dominios actualizados en segundo plano sin que tengas que volver a preocuparte por tu router.
❌ Si el log responde "KO": La petición ha sido rechazada por DuckDNS. Pasos para solucionarlo:
- Abre tu script (
nano ~/duckdns/duck.sh) y verifica que el Token sea exactamente igual al de tu cuenta (sin espacios extra).
- Comprueba que los nombres de los dominios (
domains=...) estén separados únicamente por comas y sin espacios.
- Asegúrate de que no te falte ninguna comilla (
") en la estructura del comando echo.
4. Configuración de VirtualHosts en Apache
Debemos crear un archivo de configuración para cada servicio en /etc/apache2/sites-available/.
4.1. Dashboard Principal (Página Estática HTML)
<VirtualHost *:80>
ServerName pi5appserver.duckdns.org
DocumentRoot /var/www/html
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
4.2. Contenedor de Odoo
<VirtualHost *:80>
ServerName pi5odoo.duckdns.org
ProxyPreserveHost On
ProxyRequests Off
# Redirección al puerto local expuesto por Docker
ProxyPass / http://localhost:8069/
ProxyPassReverse / http://localhost:8069/
RequestHeader set "X-Forwarded-Proto" "https"
</VirtualHost>
4.3. Contenedor de Spring Boot (API Java)
<VirtualHost *:80>
ServerName levelup42.duckdns.org
ProxyPreserveHost On
ProxyRequests Off
# Redirección al puerto local expuesto por Docker
ProxyPass / http://localhost:8080/
ProxyPassReverse / http://localhost:8080/
RequestHeader set "X-Forwarded-Proto" "https"
</VirtualHost>
5. Activación y Seguridad SSL (HTTPS)
Finalmente, activamos los sitios y utilizamos Let's Encrypt mediante Certbot para generar certificados de seguridad gratuitos, forzando la redirección de todo el tráfico a HTTPS.
sudo a2ensite odoo-docker.conf api-spring.conf
sudo systemctl reload apache2
sudo certbot --apache -d pi5appserver.duckdns.org
sudo certbot --apache -d pi5odoo.duckdns.org
sudo certbot --apache -d levelup42.duckdns.org
6. Preparación del Entorno (VS Code Remote SSH)
Para poder editar el código de nuestro Dashboard directamente desde Visual Studio Code sin problemas de permisos (evitando usar sudo), ajustamos la propiedad de la carpeta web.
sudo chown -R $USER:www-data /var/www/html
sudo chmod -R 775 /var/www/html