This document describes basic steps to set up Odoo in production or on an internet-facing server. It follows installation, and is not generally necessary for a development systems that is not exposed on the internet.
Odoo is a multi-tenant system: a single Odoo system may run and serve a number of database instances. It is also highly customizable, with customizations (starting from the modules being loaded) depending on the “current database”.
This is not an issue when working with the backend (web client) as a logged-in company user: the database can be selected when logging in, and customizations loaded afterwards.
However it is an issue for non-logged users (portal, website) which aren’t bound to a database: Odoo needs to know which database should be used to load the website page or perform the operation. If multi-tenancy is not used that is not an issue, there’s only one database to use, but if there are multiple databases accessible Odoo needs a rule to know which one it should use.
That is one of the purposes of --db-filter: it specifies how the database should be selected based on the hostname (domain) that is being requested. The value is a regular expression, possibly including the dynamically injected hostname (
%h) or the first subdomain (
%d) through which the system is being accessed.
For servers hosting multiple databases in production, especially if
website is used, dbfilter must be set, otherwise a number of features will not work correctly.
Show only databases with names beginning with ‘mycompany’
Show only databases matching the first subdomain after
www: for example the database “mycompany” will be shown if the incoming request was sent to
mycompany.co.uk, but not for
By default, PostgreSQL only allows connection over UNIX sockets and loopback connections (from “localhost”, the same machine the PostgreSQL server is installed on).
UNIX socket is fine if you want Odoo and PostgreSQL to execute on the same machine, and is the default when no host is provided, but if you want Odoo and PostgreSQL to execute on different machines 1 it will need to listen to network interfaces 2, either:
Only accept loopback connections and use an SSH tunnel between the machine on which Odoo runs and the one on which PostgreSQL runs, then configure Odoo to connect to its end of the tunnel
Accept connections to the machine on which Odoo is installed, possibly over ssl (see PostgreSQL connection settings for details), then configure Odoo to connect over the network
Allow tcp connection on localhost
Allow tcp connection from 192.168.1.x network
/etc/postgresql/<YOUR POSTGRESQL VERSION>/main/pg_hba.conf set:
/etc/postgresql/<YOUR POSTGRESQL VERSION>/main/postgresql.conf set:
Out of the box, Odoo connects to a local postgres over UNIX socket via port 5432. This can be overridden using the database options when your Postgres deployment is not local and/or does not use the installation defaults.
The packaged installers will automatically create a new user (
odoo) and set it as the database user.
The database management screens are protected by the
admin_passwdsetting. This setting can only be set using configuration files, and is simply checked before performing database alterations. It should be set to a randomly generated value to ensure third parties can not use this interface.
All database operations use the database options, including the database management screen. For the database management screen to work requires that the PostgreSQL user have
Users can always drop databases they own. For the database management screen to be completely non-functional, the PostgreSQL user needs to be created with
no-createdband the database must be owned by a different PostgreSQL user.
connect to a PostgreSQL server on 192.168.1.2
using an ‘odoo’ user account,
with ‘pwd’ as a password
filtering only db with a name beginning with ‘mycompany’
SSL Between Odoo and PostgreSQL
Since Odoo 11.0, you can enforce ssl connection between Odoo and PostgreSQL. in Odoo the db_sslmode control the ssl security of the connection with value chosen out of ‘disable’, ‘allow’, ‘prefer’, ‘require’, ‘verify-ca’ or ‘verify-full’
Odoo includes built-in HTTP servers, using either multithreading or multiprocessing.
For production use, it is recommended to use the multiprocessing server as it increases stability, makes somewhat better use of computing resources and can be better monitored and resource-restricted.
Multiprocessing is enabled by configuring a non-zero number of worker processes, the number of workers should be based on the number of cores in the machine (possibly with some room for cron workers depending on how much cron work is predicted)
Worker limits can be configured based on the hardware configuration to avoid resources exhaustion
Worker number calculation
Rule of thumb : (#CPU * 2) + 1
Cron workers need CPU
1 worker ~= 6 concurrent users
memory size calculation
We consider 20% of the requests are heavy requests, while 80% are simpler ones
A heavy worker, when all computed field are well designed, SQL requests are well designed, … is estimated to consume around 1GB of RAM
A lighter worker, in the same scenario, is estimated to consume around 150MB of RAM
Needed RAM = #worker * ( (light_worker_ratio * light_worker_ram_estimation) + (heavy_worker_ratio * heavy_worker_ram_estimation) )
In multiprocessing, a dedicated LiveChat worker is automatically started and listening on the gevent port but the client will not connect to it.
Instead you must have a proxy redirecting requests whose URL starts with
/websocket/ to the gevent port. Other request should be proxied to the normal HTTP port
To achieve such a thing, you’ll need to deploy a reverse proxy in front of Odoo, like nginx or apache. When doing so, you’ll need to forward some more http Headers to Odoo, and activate the proxy_mode in Odoo configuration to have Odoo read those headers.
Server with 4 CPU, 8 Thread
60 concurrent users
60 users / 6 = 10 <- theoretical number of worker needed
(4 * 2) + 1 = 9 <- theoretical maximal number of worker
We’ll use 8 workers + 1 for cron. We’ll also use a monitoring system to measure cpu load, and check if it’s between 7 and 7.5 .
RAM = 9 * ((0.8*150) + (0.2*1024)) ~= 3Go RAM for Odoo
Whether it’s accessed via website/web client or web service, Odoo transmits authentication information in cleartext. This means a secure deployment of Odoo must use HTTPS3. SSL termination can be implemented via just about any SSL termination proxy, but requires the following setup:
Enable Odoo’s proxy mode. This should only be enabled when Odoo is behind a reverse proxy
Set up the SSL termination proxy (Nginx termination example)
Set up the proxying itself (Nginx proxying example)
Your SSL termination proxy should also automatically redirect non-secure connections to the secure port
Redirect http requests to https
Proxy requests to odoo
Odoo as a WSGI Application
It is also possible to mount Odoo as a standard WSGI application. Odoo provides the base for a WSGI launcher script as
odoo-wsgi.example.py. That script should be customized (possibly after copying it from the setup directory) to correctly set the configuration directly in
odoo.tools.config rather than through the command-line or a configuration file.
However the WSGI server will only expose the main HTTP endpoint for the web client, website and webservice API. Because Odoo does not control the creation of workers anymore it can not setup cron or livechat workers
To run cron jobs for an Odoo deployment as a WSGI application requires
A classical Odoo (run via
Connected to the database in which cron jobs have to be run (via odoo-bin -d)
Which should not be exposed to the network. To ensure cron runners are not network-accessible, it is possible to disable the built-in HTTP server entirely with odoo-bin --no-http or setting
http_enable = Falsein the configuration file
The second problematic subsystem for WSGI deployments is the LiveChat: where most HTTP connections are relatively short and quickly free up their worker process for the next request, LiveChat require a long-lived connection for each client in order to implement near-real-time notifications.
This is in conflict with the process-based worker model, as it will tie up worker processes and prevent new users from accessing the system. However, those long-lived connections do very little and mostly stay parked waiting for notifications.
The solutions to support livechat/motifications in a WSGI application are:
Deploy a threaded version of Odoo (instead of a process-based preforking one) and redirect only requests to URLs starting with
/websocket/to that Odoo, this is the simplest and the websocket URL can double up as the cron instance.
Deploy an evented Odoo via
odoo-geventand proxy requests starting with
/websocket/to the gevent port.
Serving static files and attachments
For development convenience, Odoo directly serves all static files and attachments in its modules. This may not be ideal when it comes to performances, and static files should generally be served by a static HTTP server.
Serving static files
Odoo static files are located in each module’s
static/ folder, so static files can be served by intercepting all requests to
/MODULE/static/FILE, and looking up the right module (and file) in the various addons paths.
Attachments are files stored in the filestore which access is regulated by Odoo. They cannot be directly accessed via a static web server as accessing them requires multiple lookups in the database to determine where the files are stored and whether the current user can access them or not.
Nevertheless, once the file has been located and the access rights verified by Odoo, it is a good idea to serve the file using the static web server instead of Odoo. For Odoo to delegate serving files to the static web server, the X-Sendfile (apache) or X-Accel (nginx) extensions must be enabled and configured on the static web server. Once it is set up, start Odoo with the --x-sendfile CLI flag (this unique flag is used for both X-Sendfile and X-Accel).
For starters, keep in mind that securing an information system is a continuous process, not a one-shot operation. At any moment, you will only be as secure as the weakest link in your environment.
When deploying an internet-facing server, please be sure to consider the following security-related topics:
Always set a strong super-admin admin password, and restrict access to the database management pages as soon as the system is set up. See Database Manager Security.
Choose unique logins and strong passwords for all administrator accounts on all databases. Do not use ‘admin’ as the login. Do not use those logins for day-to-day operations, only for controlling/managing the installation. Never use any default passwords like admin/admin, even for test/staging databases.
Do not install demo data on internet-facing servers. Databases with demo data contain default logins and passwords that can be used to get into your systems and cause significant trouble, even on staging/dev systems.
Use appropriate database filters ( --db-filter) to restrict the visibility of your databases according to the hostname. See dbfilter. You may also use -d to provide your own (comma-separated) list of available databases to filter from, instead of letting the system fetch them all from the database backend.
db_filterare configured and only match a single database per hostname, you should set
list_dbconfiguration option to
False, to prevent listing databases entirely, and to block access to the database management screens (this is also exposed as the --no-database-list command-line option)
Make sure the PostgreSQL user (--db_user) is not a super-user, and that your databases are owned by a different user. For example they could be owned by the
postgressuper-user if you are using a dedicated non-privileged
db_user. See also Configuring Odoo.
Configure your server in multi-process mode with proper limits matching your typical usage (memory/CPU/timeouts). See also Builtin server.
Run Odoo behind a web server providing HTTPS termination with a valid SSL certificate, in order to prevent eavesdropping on cleartext communications. SSL certificates are cheap, and many free options exist. Configure the web proxy to limit the size of requests, set appropriate timeouts, and then enable the proxy mode option. See also HTTPS.
If you need to allow remote SSH access to your servers, make sure to set a strong password for all accounts, not just
root. It is strongly recommended to entirely disable password-based authentication, and only allow public key authentication. Also consider restricting access via a VPN, allowing only trusted IPs in the firewall, and/or running a brute-force detection system such as
Consider installing appropriate rate-limiting on your proxy or firewall, to prevent brute-force attacks and denial of service attacks. See also Blocking Brute Force Attacks for specific measures.
Many network providers provide automatic mitigation for Distributed Denial of Service attacks (DDOS), but this is often an optional service, so you should consult with them.
Whenever possible, host your public-facing demo/test/staging instances on different machines than the production ones. And apply the same security precautions as for production.
If your public-facing Odoo server has access to sensitive internal network resources or services (e.g. via a private VLAN), implement appropriate firewall rules to protect those internal resources. This will ensure that the Odoo server cannot be used accidentally (or as a result of malicious user actions) to access or disrupt those internal resources. Typically this can be done by applying an outbound default DENY rule on the firewall, then only explicitly authorizing access to internal resources that the Odoo server needs to access. Systemd IP traffic access control may also be useful to implement per-process network access control.
If your public-facing Odoo server is behind a Web Application Firewall, a load-balancer, a transparent DDoS protection service (like CloudFlare) or a similar network-level device, you may wish to avoid direct access to the Odoo system. It is generally difficult to keep the endpoint IP addresses of your Odoo servers secret. For example they can appear in web server logs when querying public systems, or in the headers of emails posted from Odoo. In such a situation you may want to configure your firewall so that the endpoints are not accessible publicly except from the specific IP addresses of your WAF, load-balancer or proxy service. Service providers like CloudFlare usually maintain a public list of their IP address ranges for this purpose.
If you are hosting multiple customers, isolate customer data and files from each other using containers or appropriate “jail” techniques.
Setup daily backups of your databases and filestore data, and copy them to a remote archiving server that is not accessible from the server itself.
Blocking Brute Force Attacks
For internet-facing deployments, brute force attacks on user passwords are very common, and this threat should not be neglected for Odoo servers. Odoo emits a log entry whenever a login attempt is performed, and reports the result: success or failure, along with the target login and source IP.
The log entries will have the following form.
These logs can be easily analyzed by an intrusion prevention system such as
For example, the following fail2ban filter definition should match a failed login:
This could be used with a jail definition to block the attacking IP on HTTP(S).
Here is what it could look like for blocking the IP for 15 minutes when 10 failed login attempts are detected from the same IP within 1 minute:
Database Manager Security
Configuring Odoo mentioned
admin_passwd in passing.
This setting is used on all database management screens (to create, delete, dump or restore databases).
If the management screens must not be accessible at all, you should set
list_db configuration option to
False, to block access to all the database selection and management screens.
Be sure to setup an appropriate
db_name parameter (and optionally,
db_filter too) so that the system can determine the target database for each request, otherwise users will be blocked as they won’t be allowed to choose the database themselves.
If the management screens must only be accessible from a selected set of machines, use the proxy server’s features to block access to all routes starting with
/web/database except (maybe)
/web/database/selector which displays the database-selection screen.
If the database-management screen should be left accessible, the
admin_passwd setting must be changed from its
admin default: this password is checked before allowing database-alteration operations.
It should be stored securely, and should be generated randomly e.g.
which will generate a 32 characters pseudorandom printable string.
Odoo supports all the major desktop and mobile browsers available on the market, as long as they are supported by their publishers.
Here are the supported browsers:
to have multiple Odoo installations use the same PostgreSQL database, or to provide more computing resources to both software.
technically a tool like socat can be used to proxy UNIX sockets across networks, but that is mostly for software which can only be used over UNIX sockets
or be accessible only over an internal packet-switched network, but that requires secured switches, protections against ARP spoofing and precludes usage of WiFi. Even over secure packet-switched networks, deployment over HTTPS is recommended, and possible costs are lowered as “self-signed” certificates are easier to deploy on a controlled environment than over the internet.