CAPÍTULO 9 · El mismo proyecto llega a Azure
El servidor recibe su configuración, no la del PC
Crear los recursos no hace que Django conozca automáticamente sus conexiones o su dominio. El proyecto solo puede utilizar las variables que su código lee. Aquí reaparece el contrato que definimos al separar entornos: mismos nombres y responsabilidades, valores distintos según el destino.
Configuramos la selección de production, la clave del servicio, los hosts y las conexiones requeridas. Si la aplicación usa MSAL, incorporamos también los valores de su registro y la URI de retorno de producción. Cada variable tiene un propósito verificable. Evitamos comprobarla mostrando secretos y distinguimos una opción propia del proyecto de una función que se activa en el portal.
El servidor ya puede recibir los datos que necesita al arrancar. Pero aún debe saber qué proceso ejecutar. El comando que utilizábamos para ver la primera página local nos sirvió durante el aprendizaje; ahora tenemos que elegir la entrada apropiada para el comportamiento HTTP o de tiempo real que construimos.
Leer esta parte dentro del relato completo →DEL RELATO A LA PRÁCTICA
Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.
LABORATORIO DE CONFIGURACIÓN
Prepara tu estación de despliegue
Cambia el entorno, el servidor y la identidad para comparar sus responsabilidades.

Simulación didáctica. Los valores son ejemplos: no crea recursos, no inicia sesión ni publica archivos. Sin JavaScript, consulta la tabla y los pasos de la lección.
MIRA · CONECTA · COMPRENDE
La caja de variables
Las flechas resumen el recorrido conceptual. Los controles y dependencias se detallan debajo.
Selecciona una pieza para destacar su responsabilidad.
Leer la explicación del mapa
- Contrato. Define nombres y tipos
- Valores. Separa secretos por entorno
- Azure. Inyecta al proceso
- Verificación. Revisa sin exponer claves
01 / EL PROBLEMA
¿Para qué sirve?
El mismo código debe recibir valores diferentes en Azure. Si el paquete lleva credenciales locales, puede conectarse a la base equivocada.
02 / COMPRENDER
El concepto, explicado
Mantén una matriz por entorno: nombre, finalidad, obligatoriedad y quién lo administra. Los nombres propios del ejemplo son ALLOWED_HOSTS, CSRF_TRUSTED_ORIGINS, SECRET_KEY y DB_*. Si tu base.py lee DJANGO_ALLOWED_HOSTS_PROD, usa ese contrato o renómbralo en ambos sitios.
En App Service, configura los valores en Variables de entorno / configuración de la aplicación. El proceso Python los recibe al iniciar. Para secretos administrados puedes usar referencias de Key Vault con permisos de lectura de la identidad administrada.
DJANGO_SETTINGS_MODULE=config.settings.production selecciona el módulo. ALLOWED_HOSTS contiene hosts sin esquema; CSRF_TRUSTED_ORIGINS contiene orígenes con https://. La clave de producción debe ser distinta a desarrollo.
Cuando uses slots, marca como propias del slot las conexiones e identidades que deben permanecer con el entorno. Un swap de código no debería trasladar la contraseña de PROD a una base DEV.
La ruta manual de este curso entrega estáticos previamente construidos. Mantén SCM_DO_BUILD_DURING_DEPLOYMENT=true para instalar dependencias Linux y DISABLE_COLLECTSTATIC=true para no volver a recolectarlos. Esta última opción solo es válida cuando verificaste que el ZIP contiene el manifiesto y todos los archivos de STATIC_ROOT.
Los nombres deben coincidir con el código que los lee: el proyecto de referencia usa DJANGO_ALLOWED_HOSTS_PROD; el ejemplo público usa ALLOWED_HOSTS. En ambos casos, DJANGO_SETTINGS_MODULE selecciona config.settings.production. Un nombre inventado en el portal no modifica settings automáticamente.
Contrato por entorno
| Nombre | Local / DEV | Azure / PROD |
|---|---|---|
| DJANGO_SETTINGS_MODULE | config.settings.development | config.settings.production |
| SECRET_KEY | Valor exclusivo local | Secreto obligatorio distinto |
| ALLOWED_HOSTS | localhost,127.0.0.1 | Host real sin https:// |
| CSRF_TRUSTED_ORIGINS | Según el origen de prueba | https://host-real si corresponde |
| DB_HOST / DB_NAME / DB_PORT | Base de práctica | Base productiva y puerto |
| DB_USER / DB_PASSWORD | Rol de laboratorio | Runtime limitado, secreto administrado |
| AZURE_TENANT_ID / AZURE_CLIENT_ID | Registro DEV si hay MSAL | Registro PROD si hay MSAL |
| AZURE_CLIENT_SECRET | Credencial DEV fuera de Git | Credencial PROD de servidor |
| AZURE_REDIRECT_URI | http://localhost:8000/aad/callback | https://host-real/aad/callback |
| USE_EASYAUTH | false para MSAL propio | false para MSAL, true solo para el adaptador Easy Auth |
| SCM_DO_BUILD_DURING_DEPLOYMENT | No se necesita en runserver | true para ZIP de código con Oryx |
03 / CONSTRUIR
Implementación paso a paso
- Anota las variables que realmente lee tu código.
- Carga secretos por el canal aprobado del equipo; evita dejarlos en comandos guardados o capturas.
- Configura el módulo de producción y los hosts.
- Configura DB_* con usuario runtime limitado y conectividad comprobada.
- Reinicia si corresponde y revisa solo presencia y parámetros no secretos.
04 / APLICAR
Ejemplo en SensorHub
# PowerShell: ejemplo de parámetros no secretos
$rg = "rg-sensorhub-dev"
$app = "app-sensorhub-dev"
$hostName = az webapp show -g $rg -n $app --query defaultHostName -o tsv
az webapp config appsettings set -g $rg -n $app --settings `
DJANGO_SETTINGS_MODULE=config.settings.production `
"ALLOWED_HOSTS=$hostName" `
"CSRF_TRUSTED_ORIGINS=https://$hostName" `
SCM_DO_BUILD_DURING_DEPLOYMENT=true --output none
# SECRET_KEY y DB_PASSWORD: cargar por gestión segura del entorno.
# Comprobación en Python, sin volcar valores:
# assert os.environ.get("SECRET_KEY"), "Falta SECRET_KEY"
# Ruta manual con estáticos ya incluidos en SensorHub/staticfiles:
# SCM_DO_BUILD_DURING_DEPLOYMENT=true -> instala dependencias en Linux
# DISABLE_COLLECTSTATIC=true -> conserva los estáticos ya construidos
# Arranque WSGI: gunicorn --chdir SensorHub config.wsgi:application --bind 0.0.0.0:8000
# DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT: solo si DATABASES los lee.
# DB_SSLROOTCERT: ruta al certificado CA en el servidor, si usas verify-full.
# MSAL propio: AZURE_TENANT_ID, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_REDIRECT_URI.
# Academia pública: no requiere MSAL ni PostgreSQL para abrir las lecciones.Cómo leer el ejemplo
- El acento grave continúa una línea PowerShell; no debe tener espacios después.
- --output none evita imprimir la respuesta completa de app settings.
- SCM_DO_BUILD_DURING_DEPLOYMENT habilita la construcción del ZIP de código.
Error habitual
No imprimas appsettings completos para mostrar que funciona. Son configuración sensible y pueden contener credenciales.
05 / PRACTICAR
Tu turno
¿Por qué ALLOWED_HOSTS=https://miapp... es una configuración incorrecta?
Ver solución orientativa
ALLOWED_HOSTS compara nombres de host, sin protocolo. El origen completo pertenece a CSRF_TRUSTED_ORIGINS.
06 / VERIFICAR
Cómo sabes que funciona
- PROD carga production.py y DEBUG=False.
- El paquete no contiene .env y los secretos no aparecen en logs.
Para profundizar
Documentación oficial para comprobar configuración, permisos y condiciones vigentes. Revisión del tema: 11 de octubre de 2026.
CONTINUAR LA EXPERIENCIA
El siguiente paso del recorrido:
Comando de arranque: Gunicorn o Daphne →Continuar en modo relato