Seguretat a Odoo: hardening del servidor i Nginx per a producció

Guia tècnica completa per reduir la superfície d'atac d'Odoo: usuari no-root, tallafoc, fail2ban, TLS, HSTS, rate limiting, capçaleres de seguretat, ocultar el gestor de bases de dades i backups xifrats.

Per què la seguretat d'Odoo en producció es descuida sistemàticament

La majoria d'implantacions Odoo arriben a producció amb la configuració per defecte de l'assistent d'instal·lació, un Nginx copiat d'un tutorial de fa cinc anys i la contrasenya mestra de la base de dades com a «admin». Aquesta combinació és el somni de qualsevol atacant automatitzat que escaneja rangs d'IP buscant instàncies Odoo exposades.

Odoo exposa per defecte diversos vectors d'atac que cal tancar explícitament abans de posar una instància a Internet: el gestor de bases de dades accessible des de fora, l'endpoint de login sense límit d'intents, la versió exacta d'Odoo a les capçaleres HTTP i una configuració TLS que pot quedar en paràmetres de fa una dècada. Aquesta guia recorre cadascun d'aquests vectors i dóna la configuració concreta per tancar-los.

El context és real: l'arquitectura descrita aquí és la que aplico en producció a clients com Rehabmedic (sector salut, dades de pacients, compliment RGPD) i la que és a la base del servidor que allotja skanndar.top.

Superfície d'atac d'Odoo: què pot ser atacat

Abans d'endurir, cal entendre què cal endurir. En una instal·lació Odoo estàndard amb Nginx com a proxy, els vectors d'atac són:

  • /web/database/manager: interfície web per crear, esborrar, duplicar i restaurar bases de dades. Si és accessible des d'Internet, un atacant pot intentar crear una BD pròpia, restaurar un dump amb dades alterades o simplement esborrar les existents.
  • /web/database/backup i /web/database/restore: endpoints que permeten descarregar i restaurar còpies de seguretat de tota la base de dades només coneixent la contrasenya mestra.
  • Endpoint de login /web/login: sense rate limiting, accepta intents de força bruta contra qualsevol compte d'usuari, inclòs el de l'administrador.
  • Capçaleres HTTP de versió: Odoo inclou per defecte capçaleres que revelen la versió exacta del sistema, la qual cosa permet als atacants buscar vulnerabilitats conegudes d'aquella versió específica.
  • Port de base de dades 5432: si PostgreSQL és accessible des de fora del servidor (un error comú), qualsevol persona amb credencials pot connectar-se directament a la BD.
  • Port 8069 exposat directament: Odoo no està dissenyat per rebre trànsit extern directament; el protocol HTTP d'Odoo no té les proteccions que afegeix un proxy invers.
  • Xmlrpc: els endpoints /xmlrpc/2/common i /xmlrpc/2/object permeten accés programàtic a gairebé tota la funcionalitat d'Odoo. Sense restriccions d'IP ni autenticació API adequada, són un altre vector de força bruta.

Hardening del sistema operatiu

Usuari no-root per a Odoo

Odoo mai no ha de córrer com a root. Si el procés d'Odoo és compromès, l'atacant no ha de tenir privilegis de sistema. La pràctica estàndard és crear un usuari dedicat sense shell de login:

# Crear usuario y grupo odoo sin home ni shell interactiva
useradd -r -s /usr/sbin/nologin -d /opt/odoo -m odoo

# Asignar ownership de los directorios de Odoo
chown -R odoo:odoo /opt/odoo
chown -R odoo:odoo /var/log/odoo
chmod 750 /opt/odoo
chmod 750 /var/log/odoo

# El fichero odoo.conf no debe ser legible por otros usuarios
chown odoo:odoo /etc/odoo/odoo.conf
chmod 640 /etc/odoo/odoo.conf

En entorns Docker, això equival a definir l'usuari al Dockerfile (USER odoo) i assegurar-se que l'entrypoint no fa sudo ni canvia d'usuari en temps d'execució.

Tallafoc amb UFW o iptables

La política per defecte ha de denegar tot el trànsit entrant i obrir només els ports necessaris. Els ports 8069 i 8072 d'Odoo mai no han d'estar oberts al tallafoc públic: només Nginx ha de parlar amb ells, i ho ha de fer per la interfície de loopback o per la xarxa interna Docker:

# UFW: política restrictiva
ufw default deny incoming
ufw default allow outgoing

# Solo SSH, HTTP y HTTPS son accesibles desde Internet
ufw allow 22/tcp    # SSH (mejor cambiar al puerto no estándar)
ufw allow 80/tcp    # HTTP → redirigir a HTTPS en Nginx
ufw allow 443/tcp   # HTTPS

# PostgreSQL solo desde localhost o red interna
# NO abrir 5432 al exterior

# Activar
ufw enable
ufw status verbose

Si el servidor està en una VPC o xarxa privada de núvol (AWS, Hetzner, OVH), afegir també les regles de grup de seguretat a nivell de proveïdor com a segona capa.

fail2ban: bloqueig automàtic d'atacs de força bruta

fail2ban llegeix els logs de Nginx i d'Odoo i bloqueja automàticament les IPs que superen un llindar d'intents fallits. És especialment efectiu contra els escàners automatitzats que intenten credencials conegudes contra l'endpoint de login d'Odoo:

# /etc/fail2ban/jail.local

[DEFAULT]
bantime  = 3600       # 1 hora bloqueado por defecto
findtime = 600        # ventana de detección: 10 minutos
maxretry = 5          # 5 intentos fallidos antes del ban
ignoreip = 127.0.0.1/8 ::1  # no banear localhost

# Jail para Nginx: ataques genéricos y escaneos
[nginx-http-auth]
enabled  = true
port     = http,https
logpath  = /var/log/nginx/error.log
maxretry = 5

# Jail específica para el login de Odoo
# (requiere que los logs de Odoo registren intentos fallidos)
[odoo-login]
enabled  = true
port     = http,https
logpath  = /var/log/odoo/odoo.log
filter   = odoo-login
maxretry = 5
bantime  = 7200

El filtre de fail2ban per a Odoo busca la cadena que Odoo escriu al log quan un login falla:

# /etc/fail2ban/filter.d/odoo-login.conf
[Definition]
failregex = .*Login failed for.*<HOST>
            .*Authentication failure.*<HOST>
ignoreregex =

Verificar que fail2ban està corrent i veure els banns actius:

systemctl status fail2ban
fail2ban-client status odoo-login
fail2ban-client status nginx-http-auth

Configuració segura de Nginx

TLS modern i HSTS

La configuració TLS per defecte de Nginx és massa permissiva. Cal forçar TLS 1.2 i 1.3 exclusivament, usar xifrats segurs i activar HSTS amb preload perquè els navegadors recordin que el domini només s'ha d'accedir per HTTPS:

# /etc/nginx/conf.d/ssl-params.conf
# Incluir este fichero desde los bloques server con: include conf.d/ssl-params.conf;

# Solo TLS 1.2 y 1.3 (eliminar TLS 1.0 y 1.1)
ssl_protocols TLSv1.2 TLSv1.3;

# Cifrados modernos — Mozilla Intermediate Configuration (2024)
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# Sesiones TLS
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;

# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;

# Parámetros DH (generar con: openssl dhparam -out /etc/nginx/dhparam.pem 4096)
ssl_dhparam /etc/nginx/dhparam.pem;

Capçaleres de seguretat HTTP

Les capçaleres de seguretat són la segona línia de defensa contra atacs XSS, clickjacking i injecció de contingut. Odoo ja n'envia algunes per defecte, però s'han de reforçar a Nginx per garantir que s'apliquen fins i tot si Odoo falla:

# /etc/nginx/conf.d/security-headers.conf
# Incluir con: include conf.d/security-headers.conf;

# Evitar que la página sea cargada en un iframe (clickjacking)
add_header X-Frame-Options "SAMEORIGIN" always;

# Evitar que el navegador detecte el MIME type de forma automática
add_header X-Content-Type-Options "nosniff" always;

# XSS Protection (para navegadores antiguos sin CSP)
add_header X-XSS-Protection "1; mode=block" always;

# HSTS: forzar HTTPS durante 1 año, incluir subdominios y preload
# AVISO: una vez activado, NO se puede revertir sin esperar el tiempo de expiración
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# Referrer Policy: no filtrar la URL completa en peticiones cross-origin
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# Permissions Policy: desactivar funcionalidades del navegador no necesarias
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

# Content Security Policy (CSP) — ajustar a los dominios reales de tu instancia
# Este es un punto de partida conservador; afina según los errores de consola
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; frame-ancestors 'self';" always;

# Ocultar la versión de Nginx
server_tokens off;

Nota important sobre CSP a Odoo: Odoo utilitza unsafe-inline i unsafe-eval extensivament al seu JavaScript. Una política CSP estricta trencarà parts de la UI. El CSP mostrat és el mínim funcional; en producció es recomana monitoritzar les violacions CSP en mode report-only abans d'activar la política en mode de bloqueig.

Rate limiting per prevenir força bruta i DDoS

El rate limiting de Nginx limita quantes peticions pot fer una IP per segon a endpoints específics. Els objectius més crítics són l'endpoint de login i els de l'API XML-RPC:

# /etc/nginx/nginx.conf (bloque http)
http {
    # ...

    # Zonas de rate limiting
    # Zona para el endpoint de login: 5 req/seg por IP, buffer de 10MB
    limit_req_zone $binary_remote_addr zone=odoo_login:10m rate=5r/m;

    # Zona para la API (XML-RPC / JSON-RPC): 30 req/seg por IP
    limit_req_zone $binary_remote_addr zone=odoo_api:10m rate=30r/s;

    # Zona global para todo el tráfico Odoo
    limit_req_zone $binary_remote_addr zone=odoo_global:10m rate=100r/s;

    # Tamaño máximo de body (evitar ataques de upload masivo)
    client_max_body_size 64m;
    client_body_timeout 30s;
    client_header_timeout 30s;
    keepalive_timeout 30s;
    send_timeout 30s;

    # ...
}

Bloc Nginx complet per a Odoo en producció

Aquest és el fitxer de configuració de servidor virtual complet. Combina totes les mesures anteriors amb el proxy invers cap a Odoo i el bloqueig explícit del gestor de bases de dades:

# /etc/nginx/sites-available/odoo.conf

# Redirigir HTTP → HTTPS
server {
    listen 80;
    server_name tudominio.com www.tudominio.com;
    return 301 https://tudominio.com$request_uri;
}

# Redirigir www → non-www (SEO: evitar contenido duplicado)
server {
    listen 443 ssl;
    server_name www.tudominio.com;
    include conf.d/ssl-params.conf;
    ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem;
    return 301 https://tudominio.com$request_uri;
}

# Servidor principal
server {
    listen 443 ssl;
    server_name tudominio.com;

    # Certificado TLS (Certbot / Let's Encrypt)
    ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem;
    include conf.d/ssl-params.conf;

    # Headers de seguridad
    include conf.d/security-headers.conf;

    # Logs
    access_log /var/log/nginx/odoo_access.log combined;
    error_log  /var/log/nginx/odoo_error.log warn;

    # -----------------------------------------------------------------
    # BLOQUEAR el gestor de bases de datos desde el exterior
    # Esta es una de las medidas más importantes para Odoo
    # -----------------------------------------------------------------
    location ~* ^/web/database/ {
        # Permitir solo desde localhost (para acceso de administración local)
        allow 127.0.0.1;
        deny all;
        # Opcional: devolver 404 en lugar de 403 para no revelar que existe
        # return 404;
    }

    # Bloquear también los endpoints de backup y restore explícitamente
    location = /web/database/backup {
        allow 127.0.0.1;
        deny all;
    }
    location = /web/database/restore {
        allow 127.0.0.1;
        deny all;
    }

    # -----------------------------------------------------------------
    # Rate limiting en endpoint de login
    # -----------------------------------------------------------------
    location = /web/login {
        limit_req zone=odoo_login burst=3 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:8069;
        include conf.d/proxy-params.conf;
    }

    # -----------------------------------------------------------------
    # Rate limiting en endpoints XML-RPC / JSON-RPC
    # -----------------------------------------------------------------
    location ~* ^/xmlrpc/ {
        limit_req zone=odoo_api burst=20 nodelay;
        limit_req_status 429;

        proxy_pass http://127.0.0.1:8069;
        include conf.d/proxy-params.conf;
    }

    location ~* ^/web/dataset/ {
        limit_req zone=odoo_api burst=50 nodelay;

        proxy_pass http://127.0.0.1:8069;
        include conf.d/proxy-params.conf;
    }

    # -----------------------------------------------------------------
    # Longpolling (chat, notificaciones en tiempo real)
    # -----------------------------------------------------------------
    location /longpolling/ {
        proxy_pass http://127.0.0.1:8072;
        include conf.d/proxy-params.conf;
        proxy_read_timeout 3600s;
        proxy_connect_timeout 3600s;
    }

    # -----------------------------------------------------------------
    # Ficheros estáticos: cache agresiva
    # -----------------------------------------------------------------
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
        proxy_pass http://127.0.0.1:8069;
        include conf.d/proxy-params.conf;
        expires 30d;
        add_header Cache-Control "public, immutable";
        # Los headers de seguridad no se aplican aquí (no son HTML)
    }

    # -----------------------------------------------------------------
    # Tráfico general Odoo
    # -----------------------------------------------------------------
    location / {
        limit_req zone=odoo_global burst=100 nodelay;

        proxy_pass http://127.0.0.1:8069;
        include conf.d/proxy-params.conf;
    }
}

El fitxer de paràmetres de proxy centralitza les directives comunes i evita repeticions:

# /etc/nginx/conf.d/proxy-params.conf
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_redirect off;
proxy_buffering off;           # necesario para longpolling
proxy_read_timeout 720s;
proxy_connect_timeout 720s;
proxy_send_timeout 720s;

Configuració segura d'Odoo (odoo.conf)

El propi Odoo té opcions de configuració que redueixen significativament la superfície d'atac. Aquestes són les més importants per a un entorn de producció:

# /etc/odoo/odoo.conf

[options]

; -------------------------------------------------------
; SEGURIDAD: parámetros críticos
; -------------------------------------------------------

; Contraseña maestra de la base de datos
; NUNCA dejar 'admin' o en blanco en producción
; Generar con: python3 -c "import secrets; print(secrets.token_urlsafe(32))"
admin_passwd = REEMPLAZAR_CON_TOKEN_ALEATORIO_SEGURO

; Desactivar el listado de bases de datos disponibles en el login
; Evita que cualquier visitante vea los nombres de tus BDs
list_db = False

; Filtro de base de datos: solo servir una BD específica por dominio
; Evita que rutas maliciosas accedan a otras BDs del servidor
dbfilter = ^odoo_produccion$

; No mostrar errores de traza completa al usuario final
; (los errores detallados van al log, no al navegador)
debug_mode = False

; -------------------------------------------------------
; PROXY: necesario cuando Nginx actúa como proxy reverso
; -------------------------------------------------------
proxy_mode = True

; -------------------------------------------------------
; WORKERS Y RENDIMIENTO
; En producción usar workers múltiples (no 0)
; Regla de referencia: 2 * núcleos_CPU + 1
; -------------------------------------------------------
workers = 5
max_cron_threads = 2

; Límites de memoria para prevenir ataques de agotamiento de recursos
limit_memory_hard = 2684354560   ; 2.5 GB
limit_memory_soft = 2147483648   ; 2 GB
limit_request = 8192
limit_time_cpu = 120
limit_time_real = 240

; -------------------------------------------------------
; BASE DE DATOS
; -------------------------------------------------------
db_host = 127.0.0.1
db_port = 5432
db_user = odoo_prod
db_password = CONTRASENA_BD_SEGURA
db_maxconn = 64

; -------------------------------------------------------
; LOGS
; -------------------------------------------------------
log_level = warn
logfile = /var/log/odoo/odoo.log
logrotate = True

; -------------------------------------------------------
; DIRECTORIOS
; -------------------------------------------------------
addons_path = /opt/odoo/addons,/opt/odoo/custom_addons
data_dir = /var/lib/odoo

Sobre list_db = False: aquesta opció és especialment important. Sense ella, la pantalla de login d'Odoo mostra un desplegable amb tots els noms de les bases de dades del servidor PostgreSQL. Un atacant que sap els noms de les BD pot dirigir els seus atacs de forma molt més eficient.

Sobre dbfilter: el filtre limita quina base de dades es pot seleccionar segons el domini de la petició. Encara que només tinguis una BD, activar aquest filtre afegeix una capa addicional: encara que algú aconsegueixi bypassar el gestor web, la petició HTTP només podrà accedir a la BD que coincideixi amb el patró regex.

Seguretat de PostgreSQL

PostgreSQL té la seva pròpia configuració de seguretat que va més enllà del que Odoo gestiona:

# /etc/postgresql/16/main/postgresql.conf

# Solo escuchar en localhost — NUNCA en 0.0.0.0 para producción
listen_addresses = '127.0.0.1'

# Logging de conexiones y sentencias lentas
log_connections = on
log_disconnections = on
log_min_duration_statement = 1000   # loguear queries > 1 segundo
log_line_prefix = '%t [%p]: [%l-1] user=%u,db=%d,app=%a,client=%h '

# SSL obligatorio para conexiones remotas (si las hubiera)
ssl = on
# /etc/postgresql/16/main/pg_hba.conf
# Política de autenticación: solo md5/scram-sha-256 desde localhost

# TYPE  DATABASE        USER            ADDRESS                 METHOD
local   all             postgres                                peer
local   all             all                                     md5
host    odoo_produccion odoo_prod       127.0.0.1/32            scram-sha-256
# NO añadir líneas con 0.0.0.0/0 ni con trust

Còpies de seguretat xifrades i verificades

Una còpia de seguretat sense xifrar és un risc RGPD: si el fitxer de backup queda exposat accidentalment (en un S3 mal configurat, en un disc extraviat), les dades de tots els vostres clients queden compromeses. El backup ha d'estar xifrat en repòs i en trànsit.

#!/bin/bash
# /opt/scripts/backup-odoo-cifrado.sh
# Ejecutar desde cron: 0 2 * * * /opt/scripts/backup-odoo-cifrado.sh

set -euo pipefail

DB_NAME="odoo_produccion"
DB_USER="odoo_prod"
BACKUP_DIR="/opt/backups"
S3_BUCKET="s3://tu-bucket-backups/odoo/"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/odoo_${DB_NAME}_${TIMESTAMP}.dump"
ENCRYPTED_FILE="${BACKUP_FILE}.gpg"
# ID de la clave GPG del receptor (administrador del servidor)
GPG_RECIPIENT="backup@tudominio.com"

mkdir -p "${BACKUP_DIR}"

echo "[$(date)] Iniciando backup de ${DB_NAME}..."

# 1. Dump en formato custom de PostgreSQL (comprimido y resumible)
pg_dump -U "${DB_USER}" -h 127.0.0.1 -Fc "${DB_NAME}" -f "${BACKUP_FILE}"

# 2. Verificar integridad del dump
if ! pg_restore --list "${BACKUP_FILE}" > /dev/null 2>&1; then
    echo "[ERROR] El dump no es válido. Abortando."
    rm -f "${BACKUP_FILE}"
    exit 1
fi

BACKUP_SIZE=$(stat -c%s "${BACKUP_FILE}")
if [ "${BACKUP_SIZE}" -lt 1048576 ]; then
    echo "[ERROR] El dump es sospechosamente pequeño: ${BACKUP_SIZE} bytes."
    exit 1
fi

# 3. Cifrar con GPG (cifrado asimétrico — la clave privada no está en el servidor)
gpg --trust-model always \
    --recipient "${GPG_RECIPIENT}" \
    --output "${ENCRYPTED_FILE}" \
    --encrypt "${BACKUP_FILE}"

# 4. Subir a S3 (las credenciales AWS deben estar en ~/.aws/credentials o en rol IAM)
aws s3 cp "${ENCRYPTED_FILE}" "${S3_BUCKET}" --storage-class STANDARD_IA

# 5. Eliminar el dump sin cifrar localmente
rm -f "${BACKUP_FILE}"

# 6. Limpiar backups locales cifrados de más de 7 días
find "${BACKUP_DIR}" -name "*.dump.gpg" -mtime +7 -delete

echo "[$(date)] Backup completado: ${ENCRYPTED_FILE} (${BACKUP_SIZE} bytes) → ${S3_BUCKET}"

La clau d'aquest procés és el xifrat asimètric amb GPG: només el posseïdor de la clau privada (l'administrador) pot desxifrar el backup. Encara que algú obtingui accés al bucket S3 o al disc on s'emmagatzemen els fitxers xifrats, les dades són il·legibles.

RGPD i ENS: consideracions per a instàncies Odoo a Espanya

Les empreses a Espanya que tracten dades personals a Odoo (clients, empleats, pacients en el sector salut) estan subjectes al Reglament General de Protecció de Dades (RGPD) i, si són proveïdors de serveis a les Administracions Públiques, també a l'Esquema Nacional de Seguretat (ENS).

Les mesures tècniques descrites en aquesta guia cobreixen els controls tècnics del RGPD (article 32), concretament:

  • Seudonimització i xifrat: els backups xifrats i el TLS en trànsit compleixen el requisit de xifrat tant en repòs com en trànsit.
  • Confidencialitat i integritat: l'enduriment del servidor (usuari no-root, tallafoc, PostgreSQL sense exposició externa) garanteix que només els sistemes autoritzats accedeixen a les dades.
  • Disponibilitat i resiliència: els backups verificats i el fail2ban que prevé atacs de disponibilitat contribueixen a aquest requisit.
  • Capacitat de restauració: els backups regulars amb verificació d'integritat compleixen el requisit de poder restaurar la disponibilitat de les dades en cas d'incident.

A més, es recomana:

  • Activar el registre d'auditoria d'Odoo (mòdul auditlog de l'OCA) per registrar quin usuari va modificar quines dades i quan. Essencial per demostrar el control d'accés en cas d'inspecció de l'AEPD.
  • Configurar la política de contrasenyes a Odoo (Settings > Technical > Security > Password Policy): longitud mínima, complexitat, caducitat.
  • Activar l'autenticació de dos factors (2FA) per a comptes d'administrador i usuaris amb accés a dades especialment sensibles.
  • Revisar els permisos de grups d'Odoo periòdicament: el principi de mínim privilegi implica que un usuari de vendes no ha de tenir accés a nòmines, i un usuari d'emmagatzematge no ha de veure dades comptables.

Llista de verificació de seguretat: abans d'anar a producció

ComprovacióEstat esperat
Odoo corre com a usuari no-rootVerificar amb ps aux | grep odoo
Port 8069/8072 no exposat al tallafocufw status — no ha d'aparèixer 8069
Port 5432 no exposat a l'exteriorss -tlnp | grep 5432 — only 127.0.0.1
/web/database/manager bloquejat des de l'exteriorcurl -I https://tudominio.com/web/database/manager → 403
list_db = False a odoo.confEl login no mostra desplegable de BD
admin_passwd no és 'admin'Token aleatori de 32+ caràcters
TLS 1.0 i 1.1 desactivatsnmap --script ssl-enum-ciphers tudominio.com
HSTS actiu amb max-age=31536000curl -I https://tudominio.com | grep Strict-Transport
server_tokens offLa capçalera Server no ha de revelar la versió de Nginx
fail2ban actiu i monitoritzant Odoofail2ban-client status odoo-login
Backups xifrats i verificats diàriamentCron actiu, verificar S3 o destinació remota
2FA activat per a comptes d'administradorSettings > Users > Enable 2FA

Conclusió

L'hardening no és un projecte puntual: és una disciplina contínua. Les configuracions d'aquesta guia cobreixen els vectors d'atac més freqüents i les exigències de compliment més habituals a Espanya, però la seguretat requereix actualitzacions quan apareixen noves vulnerabilitats a Odoo (seguir el Odoo S.A. Security Advisory), quan canvien els estàndards TLS, o quan l'arquitectura del sistema evoluciona.

Si estàs implantant Odoo en un sector regulat (salut, finances, administració pública) o simplement vols assegurar-te que la teva instància no és el proper client en una nota de premsa d'incident de seguretat, la inversió en hardening correcte des del primer dia és ordres de magnitud més barata que la resposta a un incident.

Voleu una auditoria de seguretat de la vostra instància Odoo?

Sol·licitar auditoria de seguretat

Odoo vs SAP vs Dynamics: comparativa honesta per a pimes espanyoles 2026
Cost total, temps d'implantació, flexibilitat i quan triar cada ERP sense fum de pipa