Setting SITE_URL — URL base pública para emails y enlaces
Ubicación
Archivo: config/settings/base.py
Definición:
SITE_URL = os.getenv("SITE_URL") or "https://crearack.com"
Tipo: Django setting, string con URL base (scheme + host, sin trailing slash)
Propósito
Inyectar la URL base pública del SaaS en:
- Email de bienvenida: el campo
login_urly la base del enlace “Set password” - Otros emails futuros que generen enlaces internos (password reset, confirmaciones)
Caso de uso principal: Permitir que STAGE y PROD usen la misma codebase (mismo settings.py) pero generen enlaces hacia hosts distintos.
Configuración por entorno
| Entorno | Valor env var | Resultado SITE_URL | Emails apuntan a |
|---|---|---|---|
| PROD | No definida | https://crearack.com | crearack.com |
| STAGE | https://stage.example.net | https://stage.example.net | stage.example.net |
| DEV local | No definida | https://crearack.com | crearack.com (fallback OK para links que no se usan) |
Patrón getenv-or
SITE_URL = os.getenv("SITE_URL") or "https://crearack.com"
Usa or en lugar de .get(..., default=...) para evitar el footgun de Dokploy: si Dokploy declara la env var como vacía (string ""), os.getenv("SITE_URL") retorna "" (falseo en Python), y el or pasa al default. Sin esto, SITE_URL sería "" y los emails apuntarían a rutas relativas inválidas.
Consumidores
core.email_service._generate_set_password_url(user)
return f"{settings.SITE_URL}/accounts/password/reset/key/{uidb36}-{token}/"
El enlace “Crea tu contraseña” del email de bienvenida sale con este SITE_URL.
core.email_service.send_welcome_email(user)
context = {
# ...
"login_url": settings.SITE_URL,
"set_password_url": _generate_set_password_url(user),
}
El template welcome.html usa {{ login_url }} para el botón de login y {{ set_password_url }} para el enlace de creación de contraseña.
Histórico de cambios
Pre-v1.65.3
Los URLs de email estaban hardcodeados:
login_url = "https://crearack.com"
return f"https://crearack.com/accounts/password/reset/key/..."
Problema: STAGE generaba emails con enlaces a PROD, confundiendo a testers.
v1.65.3 (commit 1d2876c)
- Introducida
SITE_URLenconfig/settings/base.py compose.prod.ymldeclara la env var en los servicios (default vacío para PROD)- STAGE fija su propio valor en Dokploy
core/email_service.pyreemplazó hardcodes porsettings.SITE_URL
Ejemplo: Variable en compose.prod.yml
environment:
# Base pública para links en emails. PROD: sin valor (default crearack.com).
# STAGE la fija en su Dokploy — sin esto sus emails apuntan a PROD (F1 PR-0).
- SITE_URL=${SITE_URL:-}
El patrón ${VAR_NAME:-} en docker-compose pasará el valor de SITE_URL si existe, o una cadena vacía si no. El Python getenv-or luego aplica el default.
Testing
File: tests/api/test_signup_activation.py
Test: test_email_links_respect_site_url
@override_settings(SITE_URL="https://stage.example.net", ...)
def test_email_links_respect_site_url(client, django_capture_on_commit_callbacks):
response = _signup(client, django_capture_on_commit_callbacks, ...)
body = mail.outbox[0].body
assert "https://stage.example.net/accounts/password/reset/key/" in body
assert "https://crearack.com/accounts/password/reset" not in body
Verifica que el override en tests funciona y que no hay hardcodes residuales.
Contexto (F1 PR-0)
- Task: #137 (Preparación de alta de cuentas)
- Iniciativa: Fase 1 (F1)
- Commit: v1.65.3 (1d2876c)
- Cazado en plan-review: 2026-08-04
Véase también
- [[entity—core—service—send-welcome-email]]
- [[entity—core—service—signup-activation]]
- [[feature—auth—email-welcome-activation-link]]
- [[concept—saas—multi-environment-configuration]]
- [[entity—core—model—user]]