While Odoo itself can serve web pages, it is strongly recommended to have a reverse proxy in front of it. A reverse proxy acts as an intermediary managing the traffic between the clients sending requests and the Odoo servers responding to them. Using a reverse proxy has several benefits.
On the security side, it can do the following:
And on the performance side, it can provide significant improvements:
Apache is a popular option to use as a reverse proxy. Nginx is a recent alternative with good technical arguments. Here, we will choose to use Nginx as a reverse proxy and show how it can be used to perform the security and performance side functions mentioned here.
First, we should install Nginx. We want it to listen on the default HTTP ports, so we should make sure they are not already taken by some other service. Performing this command should result in an error, as follows:
$ curl http://localhost curl: (7) Failed to connect to localhost port 80: Connection refused
If not, you should disable or remove that service to allow Nginx to use those ports. For example, to stop an existing Apache server you should use this command:
$ sudo service apache2 stop
Or better yet, you should consider removing it from your system, or reconfigure it to listen on another port, so the HTTP and HTTPS ports (80
and 443
) are free to be used by Nginx.
Now we can install Nginx, which is done in the expected way:
$ sudo apt-get install nginx
To confirm that it is working correctly, we should see a Welcome to nginx page when visiting the server address with a browser or using curl http://localhost
inside our server.
Nginx configuration files follow the same approach as Apache: they are stored in /etc/nginx/available-sites/
and activated by adding a symbolic link in /etc/nginx/enabled-sites/
. We should also disable the default configuration provided by the Nginx installation, as follows:
$ sudo rm /etc/nginx/sites-enabled/default $ sudo touch /etc/nginx/sites-available/odoo $ sudo ln -s /etc/nginx/sites-available/odoo /etc/nginx/sites-enabled/odoo
Using an editor, such as nano
or vi,
we should edit our Nginx configuration file as follows:
$ sudo nano /etc/nginx/sites-available/odoo
First, we add the upstreams, and the backend servers Nginx will redirect traffic to the Odoo server in our case, which is listening on port 8069
, as follows:
upstream backend-odoo { server 127.0.0.1:8069; } server { location / { proxy_pass http://backend-odoo; } }
To test if the edited configuration is correct, use the following command:
$ sudo nginx -t
If you find errors, confirm the configuration file is correctly typed. Also, a common problem is for the default HTTP to be taken by another service, such as Apache or the default Nginx website. Double-check the instructions given before to make sure that this is not the case, then restart Nginx. After this, we can have Nginx to reload the new configuration as follows:
$ sudo /etc/init.d/nginx reload
We can now confirm that Nginx is redirecting traffic to the backend Odoo server:
$ curl http://localhost <html><head><script>window.location = '/web' + location.hash;</script></head></html>
Next, we should install a certificate to be able to use SSL. To create a self-signed certificate, follow the following steps:
$ sudo mkdir /etc/nginx/ssl && cd /etc/nginx/ssl $ sudo openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365 -nodes $ sudo chmod a-wx * # make files read only $ sudo chown www-data:root * # access only to www-data group
This creates an ssl/
directory inside the /etc/nginx/
directory and creates a passwordless self-signed SSL certificate. When running the openssl
command, some additional information will be asked, and a certificate and key files are generated. Finally, the ownership of these files is given to the user www-data
used to run the web server.
Using a self-signed certificate can pose some security risks, such as man-in-the-middle attacks, and may even not be allowed by some browsers. For a robust solution, you should use a certificate signed by a recognized certificate authority. This is particularly important if you are running a commercial or e-commerce website.
Now that we have an SSL certificate, we are ready to configure Nginx to use it.
To enforce HTTPS, we will redirect all HTTP traffic to it. Replace the server
directive we defined previously with the following:
server { listen 80; add_header Strict-Transport-Security max-age=2592000; rewrite ^/.*$ https://$host$request_uri? permanent; }
If we reload the Nginx configuration now and access the server with a web browser, we will see that the http://
address will be converted into an https://
address.
But it won't return any content before we configure the HTTPS service properly, by adding the following server configuration:
server { listen 443 default; # ssl settings ssl on; ssl_certificate /etc/nginx/ssl/cert.pem; ssl_certificate_key /etc/nginx/ssl/key.pem; keepalive_timeout 60; # proxy header and settings 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_redirect off; location / { proxy_pass http://backend-odoo; } }
This will listen to the HTTPS port and use the /etc/nginx/ssl/
certificate files to encrypt the traffic. We also add some information to the request header to let the Odoo backend service know it's being proxied.
For security reasons, it's important for Odoo to make sure the proxy_mode
parameter is set to True
. The reason for this is that, when Nginx acts as a proxy, all request will appear to come from the server itself instead of the remote IP address. Setting the X-Forwarded-For
header in the proxy and enabling --proxy-mode
solves that. But enabling --proxy-mode
without forcing this header at the proxy level would allow anyone to spoof their remote address.
At the end, the location
directive defines that all request are passed to the backend-odoo
upstream.
Reload the configuration, and we should have our Odoo service working through HTTPS, as shown in the following commands:
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful $ sudo service nginx reload * Reloading nginx configuration nginx ...done. $ curl -k https://localhost <html><head><script>window.location = '/web' + location.hash;</script></head></html>
The last output confirms that the Odoo web client is being served over HTTPS.
For the particular case where an Odoo POSBox is being used, we need to add an exception for the /pos/
URL to be able to access it in HTTP mode. The POSBox is located in the local network but does not have SSL enabled. If the POS interface is loaded in HTTPS it won’t be able to contact the POSBox at all.
Now, it is time for some fine-tuning of the Nginx settings. They are recommended to enable response buffering and data compression that should improve the speed of the website. We also set a specific location for the logs.
The following configurations should be added inside the server listening on port 443
, for example, just after the proxy definitions:
# odoo log files access_log /var/log/nginx/odoo-access.log; error_log /var/log/nginx/odoo-error.log; # increase proxy buffer size proxy_buffers 16 64k; proxy_buffer_size 128k; # force timeouts if the backend dies proxy_next_upstream error timeout invalid_header http_500 http_502 http_503; # enable data compression gzip on; gzip_min_length 1100; gzip_buffers 4 32k; gzip_types text/plain text/xml text/css text/less application/x-javascript application/xml application/json application/javascript; gzip_vary on;
We can also activate static content caching for faster responses to the types of requests mentioned in the preceding code example and to avoid their load on the Odoo server. After the location /
section, add the following second location section:
location ~* /web/static/ { # cache static data proxy_cache_valid 200 60m; proxy_buffering on; expires 864000; proxy_pass http://backend-odoo; }
With this, the static data is cached for 60 minutes. Further requests on those requests in that interval will be responded to directly by Nginx from the cache.
Long polling is used to support the instant messaging app, and when using multiprocessing workers, it is handled on a separate port, which is 8072
by default.
For our reverse proxy, this means that the long polling requests should be passed to this port. To support this, we need to add a new upstream to our Nginx configuration, as shown in the following code:
upstream backend-odoo-im { server 127.0.0.1:8072; }
Next, we should add another location to the server handling the HTTPS requests, as shown in the following code:
location /longpolling { proxy_pass http://backend-odoo-im;}
With these settings, Nginx should pass these requests to the proper Odoo server port.