Odoo Docker Deployment

How to install Odoo on production environment using Docker

Initial server configuring

Let's consider the process to deploy Odoo 16.0 for production purposes on Ubuntu 22.04 Server. We carry out all the settings on a clean, newly created server.

SSH settings

Install the openssh package by running the command:

sudo apt-get install openssh-server

Next, modify your SSH configuration file to improve security:

sudo nano /etc/ssh/sshd_config
  • change the port number from the standard 22 to another in the range above of 1000:

Port 22
  • prohibit connection to the server by SSH using the root login:

PermitRootLogin no
  • prohibit connection to the server using passwords, to achieve this, comment out this line:

PasswordAuthentication no
  • allow ssh connection only to certain users (add a line to the bottom of the file):

AllowUsers user1 user2
  • allow SSH connections only from certain IP addresses:

AllowUsers = *@123.123.123.123
# Allow access only for IP 123.123.123.123

Generate a pair of SSH keys on your local computer (if they have not been generated before):

ssh-keygen -t rsa -b 4096

Add public keys to access the server without entering a password:

  • On a local computer, copy a public key to the clipboard

cat ~/.ssh/id_rsa.pub
odoo ssh public key
  • On the server, paste from the clipboard and save the file

nano ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys
ssh authorized keys

After making the changes, restart the SSH service with the command

sudo /etc/init.d/ssh reload

Open a new terminal (without closing the current one) and try to connect to the server via SSH. If the connection fails, check everything again and make the necessary changes through the first terminal.

Install and setup Docker

Run the following commands to perform system update:

sudo apt-get update
sudo apt-get upgrade -y

The following commands will install docker on your system:

sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common
UBUNTU_RLS=$(lsb_release -rs)
if [[ ${UBUNTU_RLS:0:2} -le 21 ]] ; then
   curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
   sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
else
   curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
   echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
fi
sudo apt update
apt-cache policy docker-ce
sudo apt install -y docker-ce docker-compose

Let's check the status of Docker installation:

sudo systemctl status docker

Add the current user to the docker group:

sudo usermod -aG docker $(whoami)

Let's create a directory for Odoo docker containers:

sudo mkdir /opt/docker
sudo chown -R $(whoami): /opt/docker

Moving on now ... create a directory structure for a separate project and give it a name, for example, "test":

mkdir /opt/docker/test
mkdir /opt/docker/test/config
mkdir /opt/docker/test/addons
mkdir /opt/docker/test/addons/custom
mkdir /opt/docker/test/backups
mkdir /opt/docker/test/build
mkdir /opt/docker/test/logs
mkdir /opt/docker/test/geoip

Next, we will create the Odoo configuration file "odoo.conf":

nano /opt/docker/test/config/odoo.conf

Add the following text to the file:

[options]
admin_passwd = MASTER_PASS
xmlrpc_port = 8069
db_user = odoo
db_password = odoo
addons_path=
dbfilter = ^%d$
list_db = True
log_db_level = warning
log_handler = :INFO
log_level = debug_rpc
logfile = /mnt/logs/odoo-server.log
logrotate = False
limit_time_cpu = 120
limit_time_real = 180
limit_time_real_cron = 0
max_cron_threads = 2
proxy_mode = True
workers = 3

The generation of a strong master password can be performed as follows:

python3 -c 'import base64, os; print(base64.b64encode(os.urandom(72)))'

Paste the generated password in the configuration file into the admin_passwd parameter.

Creating the "docker-compose" file

Now, create the configuration file "docker-compose.yml" with the command:

nano /opt/docker/test/docker-compose.yml

Add the following text to the configuration file:

version: "2"
services:
  web:
    build: ./build
    depends_on:
      - db
    restart: unless-stopped
    ports:
      - "127.0.0.1:18069:8069"
      - "127.0.0.1:18072:8072"
    volumes:
      - odoo-web-data:/var/lib/odoo
      - ./config:/etc/odoo
      - ./addons:/mnt/extra-addons
      - ./backups:/mnt/backups
      - ./logs:/mnt/logs
      - ./geoip:/usr/share/GeoIP/
    # command: -u all -d test
    networks:
      - test
  db:
    image: postgres:12
    restart: unless-stopped
    command: postgres -c "max_connections=300"
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_PASSWORD=odoo
      - POSTGRES_USER=odoo
      - PGDATA=/var/lib/postgresql/data/pgdata
    volumes:
      - odoo-db-data:/var/lib/postgresql/data/pgdata
    logging:
      options:
        max-size: 50m
    networks:
      - test
volumes:
  odoo-web-data:
  odoo-db-data:
networks:
   test:

Creating the "Dockerfile" configuration file

First, look up your current Linux user ID as follows:

sudo grep "^$(whoami):" /etc/passwd | cut -f 3 -d:

In the similar way, we get the user's group ID:

sudo grep "^$(whoami):" /etc/passwd | cut -f 4 -d:

Add the file to create the Odoo container:

nano /opt/docker/test/build/Dockerfile

Place the following text to the Dockerfile:

FROM odoo:16.0
USER root
RUN usermod -u 1000 odoo
RUN groupmod -g 1000 odoo
RUN mkdir /var/lib/odoo/.local
RUN chown -R 1000:1000 /var/lib/odoo
RUN pip3 install --upgrade pip
# Adding additional python libraries is as follows:
# Python dependency for installing the "auto_backup" module
RUN pip3 install paramiko
# After adding a new line, the container needs to be rebuilt with the command: docker-compose down && docker-compose up -d –-build
USER odoo

Let's try to run the container:

cd /opt/docker/test
docker-compose up -d

The process of uploading images and creating a container for the current project will begin. Once these processes are complete, the docker container will be launched. You can view the Odoo log using the following command:

tail -f /opt/docker/test/logs/odoo-server.log

If the container was created successfully, stop the container with the command:

docker-compose down

Configuring NGINX and Certbot

Steps to take before you start setting up

Before setting up the NGINX configuration, you need to create a domain for the Odoo system, we will take the following domain name as an example: test.domain.com

In a domain control panel of your domain name registration service, add a record of type A for the domain (subdomain) and specify the IP address of your server:

odoo docker domain ip address

NGINX Installation

To install NGINX, run the command:

sudo apt-get install -y nginx

Installing Certbot

Install Certbot with the following commands:

sudo apt install snapd -y
sudo snap install certbot --classic

The next steps will include:

  • creating an NGINX configuration to obtain an SSL certificate for the domain;

  • making the configuration changes necessary to launch the Odoo system with a domain name.

Creating a NGINX configuration file

Let's create an NGINX configuration file for the domain "test.domain.com":

sudo nano /etc/nginx/sites-available/test.domain.com.conf

First, let's add the following text to it for receiving an SSL certificate:

server {
   listen [::]:80;
   listen 80;
   server_name test.domain.com www.test.domain.com;
 }

Let's activate this configuration by creating a symlink - a link to the file in the "/etc/nginx/sites-enabled" directory:

sudo ln -s /etc/nginx/sites-available/test.domain.com.conf /etc/nginx/sites-enabled/test.domain.com.conf

Then we will test that the configuration is correct:

sudo nginx -t

Restart the NGINX service if there are no errors:

sudo nginx -s reload

Obtaining an SSL certificate

Next, we will get a certificate for our domain "test.domain.com" by this command:

sudo certbot -m "admin@domain.com" -d "test.domain.com" --non-interactive --agree-tos --nginx certonly

The result is:

Saving debug log to /var/log/letsencrypt/letsencrypt.log
Requesting a certificate for test.domain.com

Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/test.domain.com/fullchain.pem
Key is saved at:         /etc/letsencrypt/live/test.domain.com/privkey.pem
This certificate expires on 2023-09-24.
These files will be updated when the certificate renews.
Certbot has set up a scheduled task to automatically renew this certificate in the background.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
If you like Certbot, please consider supporting our work by:
 * Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
 * Donating to EFF:                    https://eff.org/donate-le
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Let's change the NGINX configuration settings for use with the Odoo system:

sudo nano /etc/nginx/sites-available/test.domain.com.conf

We will use the following data if we are installing Odoo version 16 or higher:

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}
#odoo server
upstream odoo_test {
   server 127.0.0.1:18069;
}
upstream odoochat_test {
   server 127.0.0.1:18072;
}

server {
   listen [::]:80;
   listen 80;
   server_name test.domain.com www.test.domain.com;
   return 301 https://test.domain.com;
 }

server {
   listen [::]:443 ssl;
   listen 443 ssl;

   server_name www.test.domain.com;

   ssl_certificate /etc/letsencrypt/live/test.domain.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/test.domain.com/privkey.pem;

   return 301 https://test.domain.com;
}

server {
   listen [::]:443 ssl http2;
   listen 443 ssl http2;

   server_name test.domain.com;

   ssl_certificate /etc/letsencrypt/live/test.domain.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/test.domain.com/privkey.pem;

   # log
   access_log /var/log/nginx/test.domain.com.access.log;
   error_log /var/log/nginx/test.domain.com.error.log;

   proxy_read_timeout 720s;
   proxy_connect_timeout 720s;
   proxy_send_timeout 720s;

   # Redirect longpoll requests to odoo websocket port
   location /websocket {
      proxy_pass http://odoochat_test;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
   }

   # Redirect requests to odoo backend server
   location / {
      # Add Headers for odoo proxy mode
      proxy_set_header X-Forwarded-Host $host;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header X-Forwarded-Proto $scheme;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_redirect off;
      proxy_pass http://odoo_test;
      client_max_body_size 512M;
   }

   location ~* /web/static/ {
      proxy_cache_valid 200 90m;
      proxy_buffering on;
      expires 864000;
      proxy_pass http://odoo_test;
   }

   location ~* /web/database/manager {
      allow 123.123.123.123;
      deny all;
      proxy_pass http://odoo_test;
   }

   location ~* /web/database/selector {
      allow 123.123.123.123;
      deny all;
      proxy_pass http://odoo_test;
   }

   # common gzip
   gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
   gzip on;
}

Data for Odoo version 15 or lower:

#odoo server
upstream odoo_test {
   server 127.0.0.1:18069;
}
upstream odoochat_test {
   server 127.0.0.1:18072;
}

server {
   listen [::]:80;
   listen 80;
   server_name test.domain.com www.test.domain.com;
   return 301 https://test.domain.com;
 }

server {
   listen [::]:443 ssl;
   listen 443 ssl;

   server_name www.test.domain.com;

   ssl_certificate /etc/letsencrypt/live/test.domain.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/test.domain.com/privkey.pem;

   return 301 https://test.domain.com;
}

server {
   listen [::]:443 ssl http2;
   listen 443 ssl http2;

   server_name test.domain.com;

   ssl_certificate /etc/letsencrypt/live/test.domain.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/test.domain.com/privkey.pem;

   # log
   access_log /var/log/nginx/test.domain.com.access.log;
   error_log /var/log/nginx/test.domain.com.error.log;

   proxy_read_timeout 720s;
   proxy_connect_timeout 720s;
   proxy_send_timeout 720s;

   # Add Headers for odoo proxy mode
   proxy_set_header X-Forwarded-Host $host;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header X-Real-IP $remote_addr;

   # Redirect longpoll requests to odoo longpolling port
   location /longpolling {
      proxy_pass http://odoochat_test;
   }

   # Redirect requests to odoo backend server
   location / {
      proxy_redirect off;
      proxy_pass http://odoo_test;
      client_max_body_size 512M;
   }

   location ~* /web/static/ {
      proxy_cache_valid 200 90m;
      proxy_buffering on;
      expires 864000;
      proxy_pass http://odoo_test;
   }

   location ~* /web/database/manager {
      # allow 121.121.121.121;
      # deny all;
      proxy_pass http://odoo_test;
   }

   location ~* /web/database/selector {
      # allow 121.121.121.121;
      # deny all;
      proxy_pass http://odoo_test;
   }

   # common gzip
   gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
   gzip on;
}

Test that the configuration is correct and restart the NGINX service if there are no errors:

sudo nginx -t && sudo nginx -s reload

Adding third-party modules

To connect third-party Odoo modules, go to the "addons" directory and clone a required repository:

cd /opt/docker/test/addons

For a sample, let's copy the standard Odoo themes for a website by the following command:

git clone -b 16.0 --single-branch --depth=1 https://github.com/odoo/design-themes

The modules with Odoo website themes will be added to the /opt/docker/test/addons/design-themes directory, then you need to add this path to the Odoo configuration file to the "addons_path" parameter as follows:

nano /opt/docker/test/config/odoo.conf

Add the path to the modules:

addons_path=/mnt/extra-addons/design-themes

Let's restart the docker container with these commands:

cd /opt/docker/test && docker-compose down && docker-compose up -d

In the same way, we will add other repositories and modules we need, for example, a backup module:

cd /opt/docker/test/addons && git clone -b 16.0 --single-branch --depth=1 https://github.com/Yenthe666/auto_backup.git

Add the path to the modules to the configuration file:

addons_path=/mnt/extra-addons/design-themes
    ,/mnt/extra-addons/auto_backup

Creating a database

After connecting the additional modules, open the project domain name https://test.domain.com in your browser.

If the previous steps were completed successfully, you will be redirected to the page for creating a new database.

odoo docker new database create

To create a database, fill in the fields:

  • Master Password - password from the Odoo configuration file (parameter "admin_passwd").

  • Database Name - must match the name of the project, in our case it is "test".

  • Email - e-mail address or login of the system administrator.

  • Password - administrator password, it is advisable to use complex, long passwords. To generate a complex password of 50 characters, you can use the command: pwgen -N 1 -s 50 -y.

  • Language - the main language that will be activated when creating the database.

  • Country - the country that will be selected for the created company in the system.

  • Demo data - this option should be activated only if you are creating a database for demonstration purposes. Usually, this option is not activated for production systems.

odoo docker new database parameters

After filling in all the required fields, click on "Create database".

Setting up a backup

For automatic database backup, we use the Odoo module from Yenthe666 available on the GitHub https://github.com/Yenthe666/auto_backup.git repository.

Connect the repository as described in the section Adding third-party modules, then log in and activate the developer mode to continue by the following steps.

odoo docker auto backup

Install the Database auto-backup / auto_backup module and go to the menu Settings - Technical - Back-ups - Configure back-ups.

odoo docker configure backups

Create a new configuration by clicking on "New". Leave all the values that were added by default, except for the Backup Directory parameter, it needs to be set to the following value: /mnt/backups

odoo docker backup path

The next step is to activate the Backup scheduler background task in the menu Settings - Technical - Automation - Scheduled Actions.

odoo docker backup cron

Also, specify the time when the database should be backed up. By default, the backup takes place once a day.

odoo docker backup cron run

To check the correctness of the settings, click on "Run Manually". A copy of the database will be created and saved by the path /opt/docker/test/backups

in Odoo
2541 23.08.2023
Odoo Docker Deployment
Yurii Razumovskyi

Entrepreneur, Odoo consultant, architect, developer, Ukrainian Odoo association member, OCA Member, Odoo Learning Partner.

Odoo Docker Deployment
Yurii Razumovskyi 23 August, 2023
Share this post
Odoo Birthday
Found out when the first official Odoo release was published