Enable Dark Mode!
By: Cybrosys Technologies

How to Setup Different URL and Log in for Multi-Company in Odoo with Nginx


When an administrator has multiple logins in multi companies, It gets confusing when we log in via the same URL. Here comes the application where it needs to set up a different URL and login for a multi-company in Odoo with Nginx. 
Different logins for multi companies with different URLs will make the ERP more user friendly, which will help the multi-company business end-users. When it is configured with SSL, it will make the business more secure.  
Let us start with Nginx, Given below is an NGINX configuration:
server {
listen 80;
listen [::]:80;
server_name testing.com *.testing.com api.testtesting.cybrosys.com;
rewrite ^(.*) https://$host$1 permanent;
server {
server_name *.*.testing.com *.testing.com;
listen 443 ssl;
access_log /var/log/nginx/testing-access.log;
error_log /var/log/nginx/testing-error.log;
location /longpolling {
    proxy_connect_timeout   3600;
    proxy_read_timeout  3600;
    proxy_send_timeout  3600;
    send_timeout        3600;
location / {     
    proxy_connect_timeout   3600;
    proxy_read_timeout  3600;
    proxy_send_timeout  3600;
    send_timeout        3600;
    proxy_redirect off;
    proxy_set_header Host $http_host;
    proxy_set_header X-Forwarded-Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
ssl on;
ssl_certificate /etc/nginx/ssl/odoo.chained.crt;
ssl_certificate_key /etc/nginx/ssl/test.key;
ssl_session_timeout 30m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
gzip on;
gzip_min_length 1000;
upstream odoo {
server weight=1 fail_timeout=0;
Below given code is for any URL which ends with testing.com (eg: test_company.testing.com, this URL can be set while creating a company as exact_domain) will return to the parent domain. 
server_name testing.com *.testing.com api.testtesting.cybrosys.com;
rewrite ^(.*) https://$host$1 permanent;
To know more about Nginx, please refer to our blog: How to Configure SSL Certificate in NGINX
Next, we move on to the methods which help in multi-company login from multiple URL,
class ResUsers(models.Model):
   _inherit = 'res.users'
def init(self):
   users = self.env['res.users'].search([])
   for user in users:
       if user.username:
           user.login = user.username + "@" + (user.company_id.company_domain)
       elif user.login and not user.username:
           user.username = user.login.rsplit('@', 1)[0]
We have inherited the model, res.users, and added an init method. This method is to set the user.login ie, it should be username@company_domain. Where company_domain is a char field which can be filled  while creating a company in the model res.company also while creating users in res.users
company_domain = fields.Char(string="Company Domain")
Next we override Create method from the model res.users,
def create(self, vals_list):
   logins = []
   if type(vals_list).__name__ == 'list':
       for vals in vals_list:
           if not 'username' in vals:
               vals['username'] = vals['email']
           if 'company_domain' in vals:
               vals['login'] = vals['username'] + "@" + vals['company_domain']
           elif 'company_ids' in vals:
               vals['login'] = vals['username'] + "@"
           if 'login' in vals:
               vals['login'] = vals['login'].lower()
           logins = self.env['res.users'].search([('login', '=', vals['login'])]).ids
           if len(logins) > 0:
               raise UserError(_("You cant have two users with same username."))
   elif type(vals_list).__name__ == 'dict':
       logins = []
       if not 'username' in vals_list or vals_list['username'] == False:
           vals_list['username'] = vals_list['email']
       if 'company_domain' in vals_list and vals_list['company_domain'] != False:
           vals_list['login'] = vals_list['username'] + "@" + vals_list['company_domain']
       elif 'company_id' in vals_list:
           vals_list['login'] = vals_list['username'] + "@" + str(self.env['res.company'].with_user(1).browse(
           logins = self.env['res.users'].search([('login', '=', vals_list['login'])]).ids
       if (not 'login' in vals_list) and ('username' in vals_list or 'email' in vals_list):
           if 'username' in vals_list:
               vals_list['login'] = vals_list['username'] + "@" + str(self.env['res.company'].with_user(1).browse(
                   vals_list.get('company_id', self.env.company.id)).company_domain)
           elif 'email' in vals_list:
               vals_list['login'] = vals_list['email'] + "@" + str(self.env['res.company'].with_user(1).browse(
                   vals_list.get('company_id', self.env.company.id)).company_domain)
       if 'login' in vals_list:
           vals_list['login'] = vals_list['login'].lower()
       if len(logins) > 0:
           raise UserError(_("You cant have two users with same username."))
   res = super(ResUsers, self).create(vals_list)
   return res
In this method, we set the login for the user. Here it contains mainly two conditions, where it checks whether the vals_list is dict or list. Let us discuss the code line by line,
logins = []  // A list is initialized for logins
   if type(vals_list).__name__ == 'list': // Check whether vals_list is of the type list
       for vals in vals_list: // looping vals_list
if not 'username' in vals: // If vals does not contain username
               vals['username'] = vals['email'] //set username as email
           if 'company_domain' in vals: // If vals contain company_domain 
               vals['login'] = vals['username'] + "@" + vals['company_domain'] // set login as username@company_domain
           elif 'company_ids' in vals: // If vals doesn’t contain company_domain and it has company_ids 
               vals['login'] = vals['username'] + "@"    +self.env['res.company'].with_user(1).browse(vals['company_ids'][0][2][0]).company_domain // set login as username@company_domain(It is taken from the login user’s company_domain)
           if 'login' in vals: // if vals contain login
               vals['login'] = vals['login'].lower() // convert login to lower case
           logins = self.env['res.users'].search([('login', '=', vals['login'])]).ids    // Get the user with corresponding login ie username
           if len(logins) > 0:  // Checking if logins is greater than 0
               raise UserError(_("You cant have two users with same username."))  // If login is greater than 0, an alert message appears.

Similar things have been done if vals_list is of the type dict. Then we super the existing Create method
Next, we override the method authenticate in the model res.users itself.
def authenticate(cls, db, login, password, user_agent_env):
   is_local_url = True if cls.is_valid_url(user_agent_env['base_location']) else False
   # is_local_url = True
   if 'HTTP_HOST' in user_agent_env and not is_local_url:
       _logger.info(user_agent_env['HTTP_HOST'], login)
       login = login + "@" + user_agent_env['HTTP_HOST'].split('.')[0]
   return super(ResUsers, cls).authenticate(db, login.lower(), password, user_agent_env)
This method gets values such as db, login, password, and user_agent_env from the controller(which is defined in default odoo methods).
First we check whether the url is valid or not, from the method is_valid_url(),
It is as follows:
def is_valid_url(url):
   import re
   regex = re.compile(
       r'^https?://'  # http:// or https://
       r'(localhost|'  # localhost...
       r'cybrosys|'  # localhost...
       r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})'  # ...or ip
       r'(?::\d+)?'  # optional port
       r'(?:/?|[/?]\S+)$', re.IGNORECASE)
   return url is not None and regex.search(url)
If the url is valid, is_local_url is set to True.
if 'HTTP_HOST' in user_agent_env and not is_local_url:
If the user_agent_env contains HTTP_HOST and if is_local_url is not True,
login = login + "@" + user_agent_env['HTTP_HOST'].split('.')[0]
Then, login is set as the login@first part of the HTTP_HOST. For example: If the url is of test@testing.com and login we retrieved from the controller is  abc then,
login = abc@testing 

This is how we can set up different URL and login for multi company in odoo with Nginx

Odoo Training Package
Odoo Implementation Package

If you need any assistance in odoo, we are online, please chat with us.

cybrosys youtube


Leave a comment


Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635


Cybrosys Limited
Alpha House,
100 Borough High Street, London,
SE1 1LB, United Kingdom


Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.


Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message