This article will walk you through installing Odoo 9 from source on an Ubuntu (or other Debian distro) box using the Odoo GitHub Repo. If you would like instructions for Odoo version 8, they can be found here.


This is meant strictly for development environments, as it installs a lot of headers that are only needed to build the binaries. LasLabs will soon be releasing an Open Source Ansible playbook to take care of the production setups, but for now there are always the Odoo docs.

We will be using a Python Virtual Environment in order to better maintain Odoo specific dependencies alongside other Python apps. Checkout The Hitchhiker’s Guide To Python’s article on VirtualEnvs for more information on VirtualEnv.

Configuration Reference

The following table is a reference of configuration variables, such as users and file directories, that you may want to change in your setup. If you do decide to change something, you’ll need to make sure that you transpose these values for your’s in the steps below.

Name Value
System User odoo
Database Name odoo
Database User odoo
Install Directory /opt/odoo
Configuration Path /etc/odoo/odoo.conf
Addons Path /opt/odoo/addons
Log Path /var/log/odoo/odoo-server.log
Init Script Path /etc/init.d/odoo
VirtualEnv Path /opt/odoo/_venv

Ready The Server

  1. Standard procedure when beginning any software maintenance is to update your package repos and application versions (update and upgrade respectively):

sudo apt-get update &&
sudo apt-get -y upgrade
  1. Install build dependencies:

sudo apt-get install -y git python-virtualenv postgresql-9.5 \
postgresql postgresql-server-dev-9.5 postgresql-client-9.5 \
libxml2-dev libjpeg-dev libldap2-dev libsasl2-dev libxslt1-dev \
python-dev libtiff5-dev node-clean-css node-less libpng-dev \
npm nodejs gdebi python-pip
  1. Install newest version of WkHtmlToPdf to circumvent stale repo versions with known issues. Find the latest version on their download page:

cd /opt/ &&
sudo wget &&
sudo tar xf wkhtmltox-0.12.4_linux-generic-amd64.tar.xz &&
sudo rm wkhtmltox-0.12.4_linux-generic-amd64.tar.xz &&
sudo ln -s /opt/wkhtmltox/bin/wkhtmltopdf /usr/bin &&
sudo ln -s /opt/wkhtmltox/bin/wkhtmltoimage /usr/bin
  1. Install node modules required for Odoo website

sudo npm install -y -g less less-plugin-clean-css &&
sudo ln -s /usr/bin/nodejs /usr/bin/node

Configure Database

  1. Change to the postgres system user so that we can work with the database:

sudo su - postgres
  1. Create the odoo database and user. Save the password that you choose here, we will need it later:

createuser --createdb --username postgres --no-superuser --no-createrole --pwprompt odoo
  1. Exit the postgres system user:


Install Odoo

  1. Create the Odoo user:

sudo adduser --system --group odoo --home /opt/odoo
  1. Checkout the Odoo 9.0 branch from GitHub into the install directory:

sudo git clone --depth 1 --branch 9.0 --single-branch /opt/odoo
  1. Update owner to Odoo system user:

sudo chown -R odoo: /opt/odoo
  1. Switch to the Odoo system user so that we don’t have to worry about permissions anymore. We need to explicitly define /bin/bash as a shell due to the user not having a shell (this is a good thing):

sudo su - odoo -s /bin/bash
  1. Change to the install directory and create a Python Virtual Environment for dependency isolation:

cd /opt/odoo &&
virtualenv ./_venv
  1. Activate the VirtualEnv, install the Python dependencies, then install Odoo:

source ./_venv/bin/activate &&
pip install -r ./requirements.txt &&
pip install ./
  1. If you are developing modules and need Odoo to run tests, you will also need anybox.testing.openerp:

pip install anybox.testing.openerp
  1. Exit the Odoo user:


Configure Odoo

  1. Make the configuration file directory:

sudo mkdir /etc/odoo
  1. Copy the sample config to its final location. Update the permissions for security (it will be holding passwords):

sudo cp /opt/odoo/debian/openerp-server.conf /etc/odoo/odoo.conf &&
sudo chmod 640 /etc/odoo/odoo.conf &&
sudo chown odoo: /etc/odoo/odoo.conf
  1. Edit the configuration file, make it look something like the below (adding in your password). The admin_password is used when performing database operations from the database management portal ($ODOO_BASE_URI/web/database/manager) – such as creations, backups, and drops:

db_host = False
db_port = False
db_user = odoo
addons_path = /opt/odoo/addons
logfile = /var/log/odoo/odoo-server.log
  1. Verify that the server runs manually. Use CTRL+C to exit the prompt:

sudo su - odoo -s /bin/bash
source /opt/odoo/_venv/bin/activate

** If you get something like below, the server is working. You can verify by going to http://ip-of-odoo-server:80:

2015-09-15 04:45:25,516 18499 INFO ? openerp: OpenERP version 8.0
2015-09-15 04:45:25,516 18499 INFO ? openerp: addons paths: ['/opt/rx/.local/share/Odoo/addons/8.0', u'/opt/rx/openerp/addons', u'/opt/rx/addons']
2015-09-15 04:45:25,516 18499 INFO ? openerp: database hostname: localhost
2015-09-15 04:45:25,516 18499 INFO ? openerp: database port: 5432
2015-09-15 04:45:25,516 18499 INFO ? openerp: database user: rx
2015-09-15 04:45:25,625 18499 INFO ? openerp.service.server: HTTP service (werkzeug) running on
2015-09-15 04:45:29,120 18499 INFO ? openerp.addons.bus.bus: Bus.loop listen imbus on db postgres
2015-09-15 04:45:29,429 18499 INFO ? Will use the Wkhtmltopdf binary at /usr/local/bin/wkhtmltopdf
2015-09-15 04:45:29,563 18499 INFO ? openerp.http: HTTP Configuring static files
2015-09-15 04:45:29,571 18499 INFO None openerp.http: Generating nondb routing
2015-09-15 04:45:29,583 18499 ERROR None openerp.http: Exception during JSON request handling.
Traceback (most recent call last):
File "/opt/rx/openerp/", line 537, in _handle_exception
return super(JsonRequest, self)._handle_exception(exception)
File "/opt/rx/openerp/", line 1415, in _dispatch_nodb
func, arguments = self.nodb_routing_map.bind_to_environ(request.httprequest.environ).match()
File "/opt/rx/_venv/local/lib/python2.7/site-packages/werkzeug/", line 1430, in match
raise NotFound()
NotFound: 404: Not Found
  1. Exit Odoo user session:


Allow Automatic Booting

  1. Copy the sample init script to the init folder, and set permissions:

sudo cp /opt/odoo/debian/init /etc/init.d/odoo &&
sudo chmod 755 /etc/init.d/odoo &&
sudo chown root: /etc/init.d/odoo
  1. Make appropriate alterations for our environment by editing /etc/init.d/odoo and replacing the variable declarations at the top with the following instead:

  1. In both the init script and config file, we have a log path defined. It doesn’t exist yet, and the Odoo system user will need read/write access to it:

sudo mkdir /var/log/odoo &&
sudo chown odoo:root /var/log/odoo
  1. Start the server:

sudo /etc/init.d/odoo start
  1. Test the server by going to http://ip-or-domain-of-server:8069
  • If there are errors, check the logs – less /var/log/odoo/odoo-server.log

  1. Stop the server (once everything works):

sudo /etc/init.d/odoo stop
  1. Allow for automatic booting (as described on StackOverflow):

sudo update-rc.d odoo defaults
  1. Start Odoo through system services:

sudo service odoo start

Next Steps

From here you would want to create a database and begin configuring Odoo (http://ip-or-domain-of-server:8069/web/database/manager).

For performance and scalability, it is recommended to run Odoo behind an Nginx proxy (as seen in this article).

Configuration File Reference

Thanks to Luke Branch on the Odoo forums for this:

## Server startup config - Common options
# Admin password for creating, restoring and backing up databases
admin_passwd = admin
# specify additional addons paths (separated by commas)
addons_path = /opt/odoo/addons
## XML-RPC / HTTP - XML-RPC Configuration
# disable the XML-RPC protocol
xmlrpc = True
# Specify the TCP IP address for the XML-RPC protocol. The empty string binds to all interfaces.
xmlrpc_interface =
# specify the TCP port for the XML-RPC protocol
xmlrpc_port = 8069
# Enable correct behavior when behind a reverse proxy
proxy_mode = True
## XML-RPC / HTTPS - XML-RPC Secure Configuration
# disable the XML-RPC Secure protocol
xmlrpcs = True
# Specify the TCP IP address for the XML-RPC Secure protocol. The empty string binds to all interfaces.
xmlrpcs_interface =
# specify the TCP port for the XML-RPC Secure protocol
xmlrpcs_port = 8071
# specify the certificate file for the SSL connection
secure_cert_file = server.cert
# specify the private key file for the SSL connection
secure_pkey_file = server.pkey
## NET-RPC - NET-RPC Configuration
# enable the NETRPC protocol
netrpc = False
# specify the TCP IP address for the NETRPC protocol
netrpc_interface =
# specify the TCP port for the NETRPC protocol
netrpc_port = 8070
## WEB - Web interface Configuration
# Filter listed database REGEXP
dbfilter = .*
## Static HTTP - Static HTTP service
# enable static HTTP service for serving plain HTML files
static_http_enable = False
# specify the directory containing your static HTML files (e.g '/opt/')
static_http_document_root = None
# specify the URL root prefix where you want web browsers to access your static HTML files (e.g '/')
static_http_url_prefix = None
## Testing Group - Testing Configuration
# Launch a YML test file.
test_file = False
# If set, will save sample of all reports in this directory.
test_report_directory = False
# Enable YAML and unit tests.
test_disable = False
# Commit database changes performed by YAML or XML tests.
test_commit = False
## Logging Group - Logging Configuration
# file where the server log will be stored (default = None)
logfile = /var/log/openerp/openerp-server.log
# do not rotate the logfile
logrotate = True
# Send the log to the syslog server
syslog = False
# setup a handler at LEVEL for a given PREFIX. An empty PREFIX indicates the root logger. This option can be repeated. Example: "openerp.orm:DEBUG" or "werkzeug:CRITICAL" (default: ":INFO")
log_handler = ["[':INFO']"]
# specify the level of the logging. Accepted values: info, debug_rpc, warn, test, critical, debug_sql, error, debug, debug_rpc_answer, notset
#log_level = debug
log_level = info