Objetivo: salir a producción sin sorpresas (auth, pool, WebSocket, colas, logs, backups).
Tip: imprime esto y úsalo como “gate” antes de abrir el 443.
Datos del despliegue (rellenar)
Proyecto/Cliente: ___________________________
Fecha: ____ / ____ / ______
Responsable: _______________________________
Host Odoo: _________________________________
Host PgBouncer: ____________________________
Host PostgreSQL: ____________________________
Versión Odoo: ________ PostgreSQL: ________ PgBouncer: ________
Usuarios concurrentes objetivo: _____________
1) Red y exposición
Odoo NO está expuesto a Internet (solo loopback o red privada)
Solo el reverse proxy escucha en 443
Firewall aplicado:
443 público
8069/8072 cerrados al público
6432 solo desde Odoo/red interna
5432 solo desde PgBouncer/bastión
DNS/hostnames correctos (sin “apuntar a IP vieja”)
2) Reverse proxy + WebSocket (crítico)
/ enruta a Odoo HTTP (8069)
/websocket/ enruta a gevent (8072)
proxy_mode = True en Odoo
Headers: X-Forwarded-For, X-Forwarded-Proto, Host
Timeouts del proxy razonables (PDF/reportes no mueren por timeout)
3) Odoo: seguridad mínima
admin_passwd fuerte y fuera del repositorio
list_db = False
dbfilter definido (si aplica multi-DB / multi-tenant)
addons_path separado (core vs custom)
Parámetros sensibles solo en secretos/ENV (no hardcode en git)
4) Odoo: performance y límites
workers dimensionados por CPU/RAM (documentado)
max_cron_threads conservador (1–2) salvo evidencia
Límites definidos:
limit_time_cpu
limit_time_real
limit_memory_soft
limit_memory_hard
Crons pesados identificados (lista) y horarios controlados
Jobs masivos usan batching (evitar transacciones largas)
5) PgBouncer: pooling correcto
pool_mode = transaction (para tráfico ORM normal)
default_pool_size calculado (no “a ojo”)
reserve_pool_size configurado para picos cortos
max_client_conn suficiente para el pico (documentado)
Si multi-DB: límites max_db_connections / max_user_connections revisados
Procedimiento de RELOAD probado (sin downtime)
6) Auth: usuarios, auth_file y rotación
auth_type definido (ideal: scram-sha-256)
auth_file (userlist.txt) con:
formato correcto "user" "secret"
permisos 0600 (owner correcto)
Si usas auth_user/auth_query: rol técnico y query/función validados
Rotación de password documentada + ensayo realizado (cambio + reload + validación)
No se usa trust en producción
7) TLS (si aplica)
TLS en 443 (proxy)
TLS entre Odoo↔PgBouncer si cruzan red no confiable
db_sslmode definido (si aplica: verify-full con CA/hostname)
Certificados con SAN correcto + caducidad monitoreada
8) PostgreSQL: estabilidad y protección
max_connections coherente con PgBouncer (no inflado sin control)
Timeouts definidos:
statement_timeout (política clara)
lock_timeout
idle_in_transaction_session_timeout
Autovacuum/maintenance plan (monitoreo + ventanas)
Roles/permisos mínimos (no usar superuser para Odoo)
9) Observabilidad mínima (antes de abrir)
PgBouncer
Logs útiles activados:
log_connections=1
log_disconnections=1
log_pooler_errors=1
Comandos verificados:
SHOW POOLS; (cola: cl_waiting, maxwait)
SHOW STATS;
SHOW SERVERS; / SHOW CLIENTS;
Odoo
Métricas de latencia p95/p99 (al menos login + operación crítica)
Alertas por errores (timeouts, deadlocks, “pool full”)
Duración de crons y solapes monitorizados
Infra
CPU/RAM/swap
I/O wait/latencia disco
red (drops/retransmits)
file descriptors (especialmente PgBouncer)
10) Backups y “día 2”
Backups automáticos configurados
Restore probado (RTO/RPO real)
Plan de upgrades (Odoo/Postgres/PgBouncer) documentado
Runbook básico:
“si hay lentitud” → mirar SHOW POOLS; + pg_stat_activity
“si falla auth” → revisar userlist.txt + RELOAD + logs
“si hay cola” → identificar transacciones largas/locks
Firmas (para cerrar el gate)
Responsable técnico: _______________________ Fecha: //____
QA/Operaciones: ___________________________ Fecha: //____
Aprobación final: __________________________ Fecha: //____