La respuesta corta
Para alojar Odoo en DigitalOcean, hazlo correr en un Droplet con suficiente memoria. Pon Postgres en el Droplet o en el PostgreSQL gestionado de DigitalOcean. Cierra todos los puertos menos el 80 y el 443. Envía las copias de la base de datos y de los archivos a Spaces, en otra región. Luego prueba una restauración antes de salir en vivo.
DigitalOcean es fácil de usar, y su panel de control se aprende rápido. Por eso es un primer hogar común para Odoo. Esta guía te da los comandos exactos para cada paso, y una forma de comprobar que cada paso funcionó.
Para la instalación en sí (Odoo, Postgres, el archivo de configuración y el proxy), sigue nuestra guía sobre Odoo en un VPS. Esta página cubre lo que cambia en DigitalOcean.
Antes de empezar
Vas a usar doctl, la herramienta de línea de comandos de DigitalOcean. Instálala en tu propio equipo. Luego crea un token de acceso personal en el panel de control (API > Tokens) e inicia sesión:
doctl auth init
doctl compute ssh-key list
El segundo comando lista tus claves SSH. Apunta el ID o la huella de la clave que quieres en el servidor. Si la lista está vacía, añade primero tu clave en Settings > Security.
En esta guía, el Droplet y la base de datos viven en fra1 (Fráncfort). Las copias van a ams3 (Ámsterdam). Usa tus propias regiones. Solo mantén las copias en una región distinta a la del Droplet.
Qué Droplet elegir
DigitalOcean tiene Droplets con CPU compartida y Droplets con CPU dedicada.
- CPU compartida (planes Basic): está bien para pruebas y equipos pequeños.
- CPU dedicada (General Purpose y otros): es mejor cuando la gente usa Odoo todo el día. Así su velocidad no depende de otros clientes.
El mínimo para empezar: 2 vCPU, 4 GB de memoria y 50 GB de disco. Con eso corren Odoo y Postgres en un solo Droplet para un equipo pequeño. La memoria importa más que la CPU: cada worker necesita su parte, y Postgres quiere la suya si corre en el mismo Droplet. Para más usuarios, importaciones grandes o Postgres gestionado, nuestra guía sobre cuántos workers de Odoo necesitas muestra cómo calcularlo.
Elige la región con cuidado. Tus datos viven donde vive el Droplet.
Crea una red privada
Una VPC es una red privada. Tu Droplet y tu base de datos hablan por ella, así que su tráfico nunca cruza internet.
doctl vpcs create --name odoo-vpc --region fra1
doctl vpcs list
Copia el ID de odoo-vpc. Abajo lo llamamos VPC_ID.
Crea el Droplet
Primero, revisa los nombres de tamaños e imágenes, porque cambian con el tiempo:
doctl compute size list
doctl compute image list-distribution --format ID,Distribution,Slug
Luego crea el Droplet. s-2vcpu-4gb es un tamaño con CPU compartida, y g-2vcpu-8gb es un tamaño con CPU dedicada. Los dos son solo ejemplos.
doctl compute droplet create odoo-prod \
--region fra1 \
--size g-2vcpu-8gb \
--image ubuntu-24-04-x64 \
--ssh-keys YOUR_KEY_ID \
--vpc-uuid VPC_ID \
--enable-monitoring \
--enable-backups \
--tag-names odoo \
--wait
Qué hacen las opciones:
--ssh-keyspone tu clave en la cuenta root. Sin ella, DigitalOcean te envía una contraseña por correo.--vpc-uuidpone el Droplet en tu red privada.--enable-monitoringinstala el agente de métricas. Lo necesitas para la alerta de disco más adelante.--enable-backupsactiva las copias de Droplet. Más abajo verás lo que hacen.
Obtén el ID del Droplet y sus direcciones IP pública y privada:
doctl compute droplet list
Abajo llamamos al ID DROPLET_ID. Entra y comprueba que el agente de métricas está corriendo:
ssh root@PUBLIC_IP
systemctl status do-agent
Si creaste el Droplet sin esa opción, instala el agente desde el Droplet:
curl -sSL https://repos.insights.digitalocean.com/install.sh | sudo bash
Ahora instala Odoo con nuestra guía sobre Odoo en un VPS. Si piensas usar PostgreSQL gestionado, sáltate el paso que instala el servidor de Postgres. Sigues necesitando las herramientas cliente de Postgres para las copias.
Dónde va Postgres
- En el mismo Droplet. Simple, y está bien para muchos equipos. Sigue la guía del VPS tal como está.
- En el PostgreSQL gestionado de DigitalOcean. DigitalOcean se encarga del servidor de base de datos por ti. Gestiona las actualizaciones y guarda sus propias copias. Las conexiones usan SSL y un puerto distinto del habitual.
El resto de esta sección es para el PostgreSQL gestionado.
Crea el cluster
Créalo en la misma región y la misma VPC que el Droplet:
doctl databases options slugs --engine pg
doctl databases create odoo-db \
--engine pg \
--version 17 \
--region fra1 \
--size db-s-1vcpu-1gb \
--num-nodes 1 \
--private-network-uuid VPC_ID \
--wait
doctl databases list
Copia el ID del cluster. Abajo lo llamamos DB_ID.
db-s-1vcpu-1gb es el tamaño más pequeño, y aparece solo como ejemplo. Permite solo 22 conexiones, muy pocas para la mayoría de las instalaciones de Odoo. Mira "Conexiones" más abajo y elige un tamaño mayor de la lista.
Deja entrar solo al Droplet
Añade el Droplet como fuente de confianza. Así nada más puede llegar a la base de datos:
doctl databases firewalls append DB_ID --rule droplet:DROPLET_ID
doctl databases firewalls list DB_ID
Puedes usar --rule tag:odoo en su lugar. Así entra cada Droplet con la etiqueta odoo.
Obtén los datos de conexión
Ejecuta esto en tu propio equipo. --private da la dirección en la red privada. --show muestra la contraseña, que está oculta por defecto:
doctl databases connection DB_ID --private --show
Obtienes un host que empieza por private-, un puerto (25060 en los ejemplos de DigitalOcean), el usuario admin doadmin, su contraseña y sslmode=require. Usa el puerto que veas.
Crea el usuario odoo y la base de datos
Odoo no debe usar doadmin. Dale su propio usuario, y haz que ese usuario sea el dueño de la base de datos. Así Odoo no necesita el derecho de crear bases de datos.
En el Droplet, instala el cliente de Postgres de la misma versión que el cluster. Luego conéctate como doadmin con la cadena de conexión del paso anterior:
psql "postgresql://doadmin:PASSWORD@PRIVATE_HOST:25060/defaultdb?sslmode=require"
Ejecuta estas tres líneas:
CREATE ROLE odoo LOGIN PASSWORD 'a-long-random-password';
GRANT odoo TO doadmin;
CREATE DATABASE yourdb OWNER odoo;
¿Por qué la línea del medio? doadmin no es superusuario. Desde PostgreSQL 16, solo puede dar una base de datos a un rol del que es miembro. Sin esa línea, la tercera falla con must be able to SET ROLE "odoo".
Creamos el usuario con SQL, no en el panel de control, para que doadmin tenga permiso para darlo. Comprueba el resultado:
\l yourdb
\du odoo
El dueño de yourdb debe ser odoo. El rol odoo no debe tener derechos extra, como "Create DB". Eso es lo que quieres.
Apunta Odoo a ella
En /etc/odoo/odoo.conf:
db_host = private-odoo-db-do-user-0000000-0.x.db.ondigitalocean.com
db_port = 25060
db_user = odoo
db_password = a-long-random-password
db_name = yourdb
db_sslmode = require
dbfilter = ^yourdb$
Usa tu propio host de doctl databases connection. Como aquí Odoo no puede crear bases de datos, prepara la base vacía una vez desde la línea de comandos:
sudo -u odoo odoo -c /etc/odoo/odoo.conf -d yourdb -i base --stop-after-init
El chat en vivo de Odoo también se conecta a una base de datos llamada postgres para escuchar las actualizaciones. Comprueba que el usuario odoo puede llegar a ella:
psql "postgresql://odoo:PASSWORD@PRIVATE_HOST:25060/postgres?sslmode=require" -c "select 1"
Conexiones
Cada proceso de Odoo puede abrir hasta db_maxconn conexiones. El valor por defecto es 64. Con 4 workers, 2 hilos de cron y el proceso del chat en vivo, son 7 procesos. Pon un límite más bajo en odoo.conf:
db_maxconn = 8
Así son 7 × 8 = 56 conexiones como máximo. Elige un tamaño de base de datos que permita más. Revisa el límite con SHOW max_connections; en psql.
Usa el puerto directo, no el pooler
DigitalOcean ofrece connection pools (PgBouncer). Los pools nuevos usan el modo "transaction" por defecto. En ese modo, PgBouncer no soporta LISTEN, y el chat en vivo de Odoo usa LISTEN. Conecta Odoo al puerto propio del cluster, como arriba, no a un pool.
Qué copia la base de datos gestionada
La base de datos gestionada guarda sus propias copias. Puedes restaurarla a cualquier momento de los últimos 7 días. No hace copia del filestore. Los adjuntos, las imágenes y los documentos viven en /var/lib/odoo/filestore, en el Droplet. Necesitan su propia copia, y la copia de abajo se encarga de los dos.
Firewall
Usa un DigitalOcean Cloud Firewall. Descarta todo el tráfico que ninguna regla permite. Permite:
- 80 y 443 desde cualquier lugar
- 22 solo desde tus propias direcciones IP
Cambia 203.0.113.10/32 por tu propia IP:
doctl compute firewall create --name odoo-fw \
--inbound-rules "protocol:tcp,ports:80,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:443,address:0.0.0.0/0,address:::/0 protocol:tcp,ports:22,address:203.0.113.10/32" \
--outbound-rules "protocol:tcp,ports:all,address:0.0.0.0/0,address:::/0 protocol:udp,ports:all,address:0.0.0.0/0,address:::/0 protocol:icmp,address:0.0.0.0/0,address:::/0" \
--droplet-ids DROPLET_ID
Las reglas de salida importan. Sin reglas de salida, el Droplet no puede llegar a nada, ni siquiera a las actualizaciones o a Spaces.
Compruébalo desde tu equipo:
doctl compute firewall list
nc -vz -w 5 PUBLIC_IP 8069
El segundo comando debe dar timeout. Los puertos propios de Odoo (8069 y 8072) solo debe alcanzarlos el proxy, en el Droplet.
Mantén la misma dirección
Una Reserved IP mantiene tu dirección igual si algún día reconstruyes o sustituyes el Droplet:
doctl compute reserved-ip create --droplet-id DROPLET_ID
Apunta tu registro DNS a esta dirección, no a la IP propia del Droplet.
Copias de seguridad en Spaces
Qué hacen las copias de Droplet
Las copias de Droplet copian todo el disco, a horas fijas. Puedes elegir cada 4, 6 o 12 horas, cada día o cada semana, en la pestaña Backups del Droplet. Se guardan en el mismo centro de datos que el Droplet.
Son "crash-consistent". Guardan lo que hay en el disco, no lo que hay en memoria. DigitalOcean avisa de que las bases de datos con mucha actividad son las más afectadas, y de que las cargas con muchas escrituras pueden necesitar copias a nivel de aplicación. Así que mantén las copias de Droplet, pero no cuentes solo con ellas para Odoo.
Antes de una actualización grande, haz también un snapshot:
doctl compute droplet-action snapshot DROPLET_ID --snapshot-name odoo-before-upgrade --wait
Crea el bucket
Spaces es el almacenamiento de archivos de DigitalOcean. Funciona con herramientas de S3. Crea el bucket en el panel de control (Spaces Object Storage > Create Bucket), en una región distinta a la del Droplet. Aquí es ams3. Déjalo privado.
Crea una clave solo para este bucket
No pongas en el Droplet una clave que pueda llegar a todos tus buckets. Crea una clave limitada que solo pueda usar your-odoo-backups:
doctl spaces keys create odoo-backup \
--grants 'bucket=your-odoo-backups;permission=readwrite'
O en el panel de control: Spaces Object Storage > Access Keys > Create Access Key, elige acceso limitado, elige el bucket y dale Read/Write/Delete. Copia el secret enseguida. Solo se muestra una vez.
Spaces no tiene un nivel de "solo escritura". Los dos niveles por bucket son lectura, y lectura/escritura/borrado. Es una razón más para activar el versionado (mira abajo).
Configura s3cmd para el usuario odoo
sudo apt install s3cmd
sudo mkdir -p /backups && sudo chown odoo: /backups
sudo -u odoo -H s3cmd --configure
Da estas respuestas:
- Access Key / Secret Key: la clave limitada del paso anterior
- Default Region: pulsa Enter
- S3 Endpoint:
ams3.digitaloceanspaces.com - DNS-style bucket template:
%(bucket)s.ams3.digitaloceanspaces.com - Use HTTPS protocol: Yes
- Test access / Save settings: Y
Esto escribe ~odoo/.s3cfg. Compruébalo:
sudo -u odoo -H s3cmd ls s3://your-odoo-backups
El archivo de contraseña
Con PostgreSQL gestionado, la copia necesita la contraseña del usuario odoo. Ponla en ~odoo/.pgpass, para que no esté en el script:
echo "PRIVATE_HOST:25060:*:odoo:a-long-random-password" | sudo -u odoo tee ~odoo/.pgpass
sudo chmod 600 ~odoo/.pgpass
El script de copia
Guarda la base de datos y el filestore juntos, y luego copia los dos a Spaces:
#!/bin/bash
# /usr/local/bin/odoo-backup.sh, run as the odoo user
set -euo pipefail
# Managed PostgreSQL only. Postgres on the Droplet? Delete this line.
export PGHOST=PRIVATE_HOST PGPORT=25060 PGUSER=odoo PGSSLMODE=require
DB=yourdb
DAY=$(date +%F)
DIR=/backups/$DAY
mkdir -p "$DIR"
pg_dump -Fc "$DB" > "$DIR/$DB.dump"
tar -czf "$DIR/$DB-filestore.tar.gz" -C /var/lib/odoo/filestore "$DB"
s3cmd put --recursive "$DIR" s3://your-odoo-backups/
find /backups -mindepth 1 -maxdepth 1 -type d -mtime +3 -exec rm -rf {} +
sudo chmod 755 /usr/local/bin/odoo-backup.sh
La versión de pg_dump debe ser la misma que la versión mayor del servidor, o más nueva. Compruébalo con pg_dump --version.
Ejecútalo cada noche
/etc/systemd/system/odoo-backup.service:
[Unit]
Description=Back up Odoo database and filestore to Spaces
Wants=network-online.target
After=network-online.target
[Service]
Type=oneshot
User=odoo
ExecStart=/usr/local/bin/odoo-backup.sh
/etc/systemd/system/odoo-backup.timer:
[Unit]
Description=Nightly Odoo backup
[Timer]
OnCalendar=*-*-* 02:30:00
RandomizedDelaySec=15m
Persistent=true
[Install]
WantedBy=timers.target
Actívalo, y ejecútalo una vez a mano:
sudo systemctl daemon-reload
sudo systemctl enable --now odoo-backup.timer
sudo systemctl start odoo-backup.service
journalctl -u odoo-backup.service -n 20
sudo -u odoo -H s3cmd ls s3://your-odoo-backups/
Deberías ver la carpeta de hoy con dos archivos dentro.
Borra las copias viejas solas
Spaces admite reglas de caducidad. Ejecuta esto desde tu propio equipo, con una clave que tenga acceso completo al bucket. Esta borra las copias a los 30 días:
s3cmd expire --expiry-days=30 --expiry-prefix= s3://your-odoo-backups
s3cmd getlifecycle s3://your-odoo-backups
Guarda las versiones viejas
Spaces también admite versionado. Cuando está activo, un archivo borrado se guarda como una versión vieja. Así que si alguien consigue la clave del Droplet y borra tus copias, aún puedes recuperarlas. Viene desactivado. Actívalo con la AWS CLI y el endpoint de la región:
aws s3api put-bucket-versioning \
--bucket your-odoo-backups \
--endpoint=https://ams3.digitaloceanspaces.com \
--versioning-configuration Status=Enabled
aws s3api get-bucket-versioning \
--bucket your-odoo-backups \
--endpoint=https://ams3.digitaloceanspaces.com
Las versiones viejas también ocupan espacio. Comprueba cómo se limpian antes de confiar en la regla de 30 días.
Prueba una restauración
Hazlo en un Droplet de prueba, nunca en el de producción. Descarga la copia de un día:
sudo -u odoo -H mkdir -p /backups/restore
cd /backups/restore
sudo -u odoo -H s3cmd get s3://your-odoo-backups/2026-10-25/yourdb.dump yourdb.dump
sudo -u odoo -H s3cmd get s3://your-odoo-backups/2026-10-25/yourdb-filestore.tar.gz yourdb-filestore.tar.gz
Ejecuta también como usuario odoo los comandos de abajo. Con PostgreSQL gestionado, pon antes los mismos PGHOST, PGPORT, PGUSER y PGSSLMODE que en el script de copia.
En PostgreSQL gestionado, el usuario odoo no puede crear bases de datos. Así que crea primero la base vacía como doadmin:
CREATE DATABASE yourdb_restored OWNER odoo;
Luego restaura como odoo:
pg_restore -d yourdb_restored --no-owner --role=odoo yourdb.dump
mkdir -p /var/lib/odoo/filestore/yourdb_restored
tar -xzf yourdb-filestore.tar.gz -C /var/lib/odoo/filestore/yourdb_restored --strip-components=1
Con Postgres en el Droplet, usa createdb -O odoo yourdb_restored en lugar de la línea SQL.
Antes de arrancar Odoo en la copia, neutralízala. Una copia de producción sigue teniendo tus servidores de correo y tus tareas programadas, así que puede enviar correos a clientes reales. Como usuario odoo, ejecuta:
odoo neutralize -c /etc/odoo/odoo.conf -d yourdb_restored
Usa odoo-bin en lugar de odoo si ejecutas Odoo desde el código fuente. Esto apaga en la copia los servidores de correo saliente, las acciones programadas y los proveedores de pago. Nuestra guía sobre copiar producción a staging explica lo que cubre y lo que se le escapa.
Arranca Odoo en el Droplet de prueba con db_name = yourdb_restored. Entra, y abre algunos adjuntos. Nuestra guía sobre cómo saber si una copia de Odoo se restaurará cubre la prueba completa.
Alertas de disco y de caída
Los logs, el filestore y las copias locales crecen. Recibe un correo antes de que el disco se llene:
doctl monitoring alert create \
--type v1/insights/droplet/disk_utilization_percent \
--compare GreaterThan --value 80 --window 5m \
--entities DROPLET_ID \
--emails [email protected] \
--description "Odoo disk over 80%"
Haz lo mismo para la memoria con --type v1/insights/droplet/memory_utilization_percent. El correo debe pertenecer a tu cuenta de DigitalOcean.
Luego comprueba que Odoo responde desde fuera, y que el certificado SSL no caduca:
doctl monitoring uptime create odoo-web \
--target https://erp.example.com/web/login \
--type https --regions eu_west,us_east
doctl monitoring uptime list
doctl monitoring uptime alert create CHECK_ID \
--name "Odoo down" --type down --period 2m \
--emails [email protected]
doctl monitoring uptime alert create CHECK_ID \
--name "SSL expires soon" --type ssl_expiry --threshold 14 \
--comparison less_than --period 5m \
--emails [email protected]
CHECK_ID sale del comando list.
Enviar correo desde Odoo
DigitalOcean bloquea los puertos SMTP 25, 465 y 587 en todos los Droplets. Así que Odoo no puede enviar correo directamente, ni a través de Gmail u Outlook por esos puertos.
Usa un servicio de envío de correo que acepte otro puerto. DigitalOcean sugiere SendGrid, que acepta el puerto 2525. Comprueba que el puerto está abierto desde el Droplet:
nc -vz -w 5 smtp.sendgrid.net 2525
Luego, en Odoo, activa el modo desarrollador. Ve a Settings > Technical > Outgoing Mail Servers y añade uno:
- SMTP Server:
smtp.sendgrid.net - SMTP Port:
2525 - Connection Encryption: TLS (STARTTLS)
- Username:
apikey(esa misma palabra) - Password: tu API key de SendGrid
Haz clic en Test Connection. Luego configura SPF y DKIM para tu dominio, como explica tu servicio de envío, para que tu correo no acabe marcado como spam.
Trampas de Odoo en cualquier servidor, DigitalOcean incluido
Proxy mode, gestor de bases de datos, workers. En odoo.conf:
proxy_mode = True
list_db = False
admin_passwd = a-long-random-string
workers = 4
gevent_port = 8072
Sin proxy_mode, los enlaces de los correos salen con http://. Sin list_db = False, cualquiera puede llegar al gestor de bases de datos. Ajusta workers a la memoria del Droplet.
Websocket. Desde Odoo 16, el chat y las actualizaciones en vivo pasan por el puerto 8072. Tu nginx debe enviar /websocket allí, y pasar quién es el visitante:
location /websocket {
proxy_pass http://127.0.0.1:8072;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
Tu bloque principal location /, que va al puerto 8069, necesita las mismas dos líneas X-Forwarded.
Disco. Rota los logs de Odoo, y mantén la alerta de disco de arriba.
Antes de salir en vivo
- Odoo corre con
workerspor encima de 0, ajustado a la memoria del Droplet /websocketva al puerto 8072, y el chat funcionaproxy_mode = True, y los enlaces de los correos empiezan porhttps://list_db = Falsey unadmin_passwdfuerte- El Cloud Firewall solo permite 80, 443 y tu propio SSH, y el puerto 8069 no responde desde fuera
- Con PostgreSQL gestionado: Odoo se conecta como
odoopor el host privado, condb_sslmode = require, y solo el Droplet es fuente de confianza - Tu DNS apunta a la Reserved IP
- El certificado SSL se renueva solo, y el check de uptime te avisa antes de que caduque
- Los logs rotan, y recibes un correo cuando el disco pasa del 80%
- Odoo envía un correo de prueba a través de un servicio en el puerto 2525
- El timer de la copia se ejecutó, y la carpeta de hoy está en Spaces, en otra región
- Una copia de la base de datos y de los archivos se ha restaurado en otro Droplet, y los adjuntos se abren
Quédate con DigitalOcean, déjanos el trabajo de Odoo
Puedes quedarte con tu Droplet y aun así no gestionar Odoo tú mismo. Con bring your own server, el Droplet sigue en tu cuenta y en la región que elijas. Nosotros hacemos funcionar Odoo en él: despliegues desde Git, staging, copias de seguridad, actualizaciones y ayuda de expertos en Odoo. Tú mantienes el Droplet en marcha y con el tamaño suficiente. Nuestro software se conecta desde tu Droplet hacia fuera, así que no nos abres ningún puerto.
Skysize está hecho por ex ingenieros de Odoo y tiene la certificación ISO 27001.
Habla con un experto en hosting de Odoo
Preguntas frecuentes
¿Es DigitalOcean bueno para Odoo? Sí. Es fácil de usar. Elige un Droplet con suficiente memoria, y CPU dedicada para equipos que usan Odoo todo el día.
¿Puede Odoo usar el PostgreSQL gestionado de DigitalOcean?
Sí, con SSL y db_sslmode = require. Crea el usuario odoo y la base de datos con SQL como doadmin, y haz que odoo sea el dueño. Haz copia del filestore aparte.
¿Debe Odoo conectarse a través de un connection pool de DigitalOcean?
No. Los pools usan el modo transaction por defecto, y ese modo no soporta el comando LISTEN que usa el chat en vivo de Odoo. Conéctate al puerto propio del cluster.
¿Bastan las copias de Droplet para Odoo? Solas no. Copian el disco mientras la base de datos está corriendo. Guarda también la base de datos y el filestore juntos, fuera del Droplet, y prueba una restauración.
¿Por qué Odoo no envía correo desde mi Droplet? DigitalOcean bloquea los puertos SMTP 25, 465 y 587 en los Droplets. Envía a través de un servicio de correo que acepte otro puerto, como el 2525.
¿Qué clave de Spaces debe usar el Droplet? Una clave de acceso limitado solo para el bucket de copias, con lectura/escritura/borrado en ese bucket. Nunca una clave de acceso completo.