Deployment of Odoo for production purposes is different from deploying it to your laptop computer. If the deployment is performed on a server, there are quite a few tests you should perform, including testing the database isolation, the application, which should be containerized to protect it from upgrades, the reverse proxy that protects from HTTPS, and a self-renewing certificate.
In this blog, we will deploy a complete production Odoo 19 stack, consisting of:
- Docker and Docker Compose - to run Odoo and PostgreSQL as isolated and reproducible services;
- Nginx - as a reverse proxy, to handle HTTP and WebSocket connections for live chat, notifications, and large file uploads;
- Let's Encrypt SSL - to issue a free auto-renewable SSL certificate.
At the end, you will have Odoo available at https://your-domain.com. The database and file store will reside on the server outside the containers, and at any time you can rebuild the application without losing any data.
Requirements needed prior:
- Ubuntu Server machine with either version 22.04 or 24.04 installed, minimum 2GB RAM (4GB is recommended)
- Domain name that already has its A records pointing to the server’s public IP address
- Root or Sudo access
Now let's begin:
Step 1: Installation of OpenSSH & Fail2ban
Firstly, we must configure our server before working on Odoo. SSH will be utilized for connecting to the server, and Fail2ban will defend against brute-force attacks from bots.
So, now let's go ahead and update our package index and upgrade the packages installed:
sudo apt update && sudo apt upgrade -y
Install the two libraries:
sudo apt install -y openssh-server fail2ban
In most Ubuntu Server images, OpenSSH is installed; it just have to check whether it is installed or not.
Start both services in a way that they start automatically on booting up, and then start them:
sudo systemctl enable --now ssh
sudo systemctl enable --now fail2ban
Make sure both of them function:
sudo systemctl status ssh
sudo systemctl status fail2ban
Step 2: Installing Docker and Docker Compose
Since the steps for installing docker are always changing in each release, you can use the instructions for installing docker provided by Docker.
Install Docker Engine on Ubuntu.
Install the below-mentioned packages based on the instructions.
docker-ce, docker-ce-cli, containerd.io, and docker-compose-plugin. The Compose plugin gives us access to the docker compose command, which will be used in this tutorial.
To see if all is working fine, run the following commands:
docker --version
docker compose version
Step 3: Compose File & Odoo Configuration
Create the project directory. Now, let us make the Compose file and the Odoo configuration.
mkdir -p ~/odoo19/config
cd ~/odoo19
Create the compose.yml file and add:
services:
postgres:
image: postgres:16
environment:
- POSTGRES_DB=postgres
- POSTGRES_USER=odoo
- POSTGRES_PASSWORD=strong_db_password_here
volumes:
- ./data/postgres:/var/lib/postgresql/data
restart: unless-stopped
odoo:
image: odoo:19
depends_on:
- postgres
ports:
- "127.0.0.1:8069:8069"
- "127.0.0.1:8072:8072"
volumes:
- ./config:/etc/odoo
- ./custom_addons:/mnt/extra-addons
- ./data/odoo:/var/lib/odoo
restart: unless-stopped
- The ports have been set for 127.0.0.1. Access to Odoo will be available through the server alone, while Nginx will be the only exposed public interface. The loopback address is necessary, elsewise Docker will create an exception for your firewall, allowing exposure of port 8069 to the world.
- Port 8072 is for gevent/longpolling. This port is responsible for WebSocket connections related to live chat, discuss, and real-time notifications services. It becomes active if workers > 0.
config/odoo.conf
[options]
admin_passwd = a_long_random_master_password
db_host = postgres
db_port = 5432
db_user = odoo
db_password = strong_db_password_here
addons_path = /mnt/extra-addons
data_dir = /var/lib/odoo
; --- Reverse proxy ---
proxy_mode = True
; --- Workers (multi-processing) ---
workers = 2
max_cron_threads = 1
; --- Resource limits ---
limit_memory_hard = 2684354560
limit_memory_soft = 2147483648
limit_time_cpu = 600
limit_time_real = 1200
; --- Logging ---
log_level = info
- db_host should match the service name in the Compose file.
- Setting proxy_mode = True makes sure that Odoo takes into consideration the X-Forwarded-* headers and generates an appropriate absolute URL with the protocol HTTPS. Otherwise, links for password reset would point to http://localhost:8069.
- With workers, start from (CPU cores * 2) + 1. With 2 cores on a VPS, 2 would be enough.
The Odoo container works under restricted permissions and cannot change any files owned by root. To determine the UID/GID used in this image, execute:
docker run --rm odoo:19 id
#uid=100(odoo) gid=101(odoo) groups=101(odoo)
The UID and GID should not be the same, so do not make any assumptions that they will be identical to one another.
Create directories and set ownership:
mkdir -p custom_addons data/odoo/sessions data/postgres
sudo chown -R 100:101 custom_addons data/odoo
Service installation starts with the steps below:
docker compose up -d
docker compose logs -f odoo
Local responsiveness check:
curl -I http://127.0.0.1:8069
Step 4: Nginx Reverse Proxy
Install Nginx:
sudo apt install -y nginx
Create /etc/nginx/sites-available/odoo:
server {
listen 80;
server_name your-domain.com;
client_max_body_size 100M;
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_connect_timeout 720s;
proxy_send_timeout 720s;
proxy_read_timeout 720s;
location / {
proxy_pass http://127.0.0.1:8069;
proxy_redirect off;
}
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";
}
}Enable the website and remove the default:
sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/
sudo rm -f /etc/nginx/sites-enabled/default
Check the settings and reset:
sudo nginx -t
sudo systemctl reload nginx
Installation of Certbot and Nginx plugin:
sudo apt install -y certbot python3-certbot-nginx
Certificate request:
sudo certbot --nginx -d your-domain.com
Enter your email address, agree to the terms, and tick the redirect box. Certbot will automatically add the listen 443 ssl line, paths for the certificate, and redirection from HTTP to HTTPS into your Nginx configuration file.
Confirm automatic renewals are set up:
sudo certbot renew --dry-run
The Certbot package also sets up a systemd timer to automatically renew the certificate twice each day; therefore, no further configuration is needed. The Odoo system is presently available at https://your-domain.com.
Now, Odoo 19 is working in Docker with a PostgreSQL backend, through Nginx reverse proxy with auto HTTPS. Everything is located in the ~/odoo19/data directory, so it is easy to rebuild all containers from scratch, and nothing will be lost.
To read more about How to Deploy a Module in Odoo.sh in Odoo 19, refer to our blog How to Deploy a Module in Odoo.sh in Odoo 19.