Certificados SSL (Traefik → Django)
NoxPanel sincroniza automáticamente los certificados Let’s Encrypt gestionados por Traefik hacia la base de datos Django, permitiendo mostrar información de certificados en el dashboard de hosting.
Visión General
Traefik gestiona todos los certificados SSL via Let’s Encrypt (ACME). Los certificados
se almacenan en acme.json. NoxPanel lee este fichero periódicamente y crea/actualiza
registros HostingSSLCertificate en Django, vinculando cada certificado al sitio
correspondiente.
Flujo de Datos
┌──────────────┐ ACME ┌──────────────┐ mount ┌──────────────┐
│ Let's Encrypt│ ───────────> │ Traefik │ ──────────> │ acme.json │
└──────────────┘ └──────────────┘ └──────┬───────┘
│
┌──────────────────────────────────┘
│ /traefik-certs/acme.json
▼
┌──────────────┐
│ sync_ssl_ │ Celery (cada 6h)
│ certificates │ o manual
│ _from_ │
│ traefik() │
└──────┬───────┘
│
▼
┌──────────────┐
│ Hosting │
│ SSL │
│ Certificate │
│ (Django DB) │
└──────────────┘
Implementación
Función Principal
Ubicación: hosting/services.py
sync_ssl_certificates_from_traefik() → dict
Lee
/traefik-certs/acme.json(montado desde el host)Extrae todos los certificados del resolver
letsencryptDecodifica los certificados PEM desde base64
Para cada certificado:
Extrae el dominio principal y SANs
Parsea la fecha de expiración con
cryptography.x509Busca un
HostingSiteactivo que coincida con el dominioCrea o actualiza un
HostingSSLCertificateviaupdate_or_create
Devuelve
{'created': N, 'updated': N, 'errors': N}
_parse_cert_expiry(cert_pem: str) → datetime
Parsea un certificado PEM y extrae la fecha de expiración usando la librería
cryptography (disponible como dependencia de paramiko).
Tarea Celery
Ubicación: hosting/tasks.py
@shared_task(name='hosting.sync_ssl_certificates')
def sync_ssl_certificates():
from hosting.services import sync_ssl_certificates_from_traefik
return sync_ssl_certificates_from_traefik()
Registrada en CELERY_BEAT_SCHEDULE (cada 6 horas):
'sync-ssl-certificates': {
'task': 'hosting.sync_ssl_certificates',
'schedule': 21600.0, # 6 horas
},
Modelo
HostingSSLCertificate en hosting/models.py:
Campo |
Tipo |
Descripción |
|---|---|---|
|
ForeignKey |
Sitio asociado ( |
|
CharField |
Dominio del certificado |
|
CharField |
Tipo: |
|
CharField |
Entidad emisora (ej: |
|
DateTimeField |
Fecha de expiración |
|
BooleanField |
Estado activo |
|
BooleanField |
Renovación automática habilitada |
Dashboard
El dashboard de hosting muestra el conteo de certificados SSL usando los registros
de HostingSSLCertificate:
# hosting/views.py
"ssl_count": HostingSSLCertificate.objects.filter(
site__tenant=tenant, is_active=True
).count() or HostingSite.objects.filter(
tenant=tenant, ssl_enabled=True, is_active=True
).count()
El modal de certificados muestra: dominio, tipo, emisor, fecha de expiración y estado de renovación automática.
Ejecución Manual
Para ejecutar la sincronización manualmente:
# Via Django shell
docker exec noxpanel-web-1 python manage.py shell -c \
"from hosting.services import sync_ssl_certificates_from_traefik; \
print(sync_ssl_certificates_from_traefik())"
# Via Celery
docker exec noxpanel-web-1 python manage.py shell -c \
"from hosting.tasks import sync_ssl_certificates; \
sync_ssl_certificates.delay()"
Certificados SNI para Mail
Los certificados para subdominios de correo (mail.*, imap.*, smtp.*,
pop.*) se sincronizan por separado via el script sync_sni_certs.sh:
Script:
app/scripts/sync_sni_certs.shFrecuencia: Cron cada 15 minutos en el host
Destino: Dovecot (
local_nameblocks) + Postfix (sni_maps)Fuente: Mismo
acme.jsonde Traefik
Important
Postfix requiere stop && start (no solo reload) tras actualizar SNI maps,
ya que los procesos smtpd cachean la configuración SNI en memoria.