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

  1. Lee /traefik-certs/acme.json (montado desde el host)

  2. Extrae todos los certificados del resolver letsencrypt

  3. Decodifica los certificados PEM desde base64

  4. Para cada certificado:

    1. Extrae el dominio principal y SANs

    2. Parsea la fecha de expiración con cryptography.x509

    3. Busca un HostingSite activo que coincida con el dominio

    4. Crea o actualiza un HostingSSLCertificate via update_or_create

  5. 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

site

ForeignKey

Sitio asociado (HostingSite)

domain

CharField

Dominio del certificado

type

CharField

Tipo: letsencrypt, custom, self_signed

issuer

CharField

Entidad emisora (ej: Let's Encrypt)

expires_at

DateTimeField

Fecha de expiración

is_active

BooleanField

Estado activo

auto_renew

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.sh

  • Frecuencia: Cron cada 15 minutos en el host

  • Destino: Dovecot (local_name blocks) + Postfix (sni_maps)

  • Fuente: Mismo acme.json de 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.