Skip to Content

Odoo 19 security architecture: combining firewall, 2FA, permissions and Web RBL properly

Defence in depth for Odoo 19 Community -- with a step-by-step guide
27 September 2026 by
Odoo 19 security architecture: combining firewall, 2FA, permissions and Web RBL properly

Odoo 19 security architecture: firewall, 2FA, permissions, Web RBL

On our five websites Odoo is reachable from the open internet, and that is not an exception but the normal case: anyone who runs an offer, a shop or a customer login has a public server. A single vulnerable password, a forgotten configuration file or an overly generous permission is enough to turn a public server into an open one.

This article shows how to secure Odoo 19 properly — not with a single measure, but with several layers that complement one another: firewall and reverse proxy, our open-source module Web RBL, two-factor authentication, password policy and permissions — and which attack attempts each of them actually intercepts. At the end there is a step-by-step guide with which any Odoo installation of your own can be brought up to the same standard.

Defence in depth: why one measure is never enough

Every single security measure has a gap. A firewall does not see what happens in an Odoo login form. A strong password does not help if it has already been stolen elsewhere. A permission structure is no use against an attacker who has not even logged in yet. The principle that closes these gaps is called defence in depth: several independent layers, each of which could be bypassed on its own — but not all of them together.

Four layers of defence: firewall, Web RBL, Odoo application, database

At our company there are four layers, each with a different task:

  • Firewall / reverse proxy — keeps out anything obviously malicious before it even reaches the server
  • Web RBL — connects both sides: Odoo learns from its own application log what the firewall cannot see at all, and feeds it back to the firewall
  • Odoo itself — two-factor authentication, password policy, permissions, session management
  • Database & operations — backup, access protection for the administration, secrets kept out of every log

The following sections go through each layer individually.

Layer 1: Firewall and reverse proxy

The firewall is the first instance to see a request, and the only one that can keep an attacker away from every service on the server — not just from the website, but also from the mail server, the VPN access and the management interface itself. What is sensibly activated at this point depends on the vendor, but the building blocks are the same for OPNsense, pfSense, HAProxy, FortiGate, Sophos or Check Point:

FunctionWhat it helps against
Current TLS version and restricted encryption methodsEavesdropping on and manipulation of the connection; outdated methods have been considered broken or weak for years
Reputation and origin lists (RBL)Known attacker networks, Tor exit nodes, entire countries without customers of your own — see below
Rate limiting per addressPassword guessing and directory scanners that make dozens of requests within seconds
Separation of management and data trafficThe firewall interface itself must not be reachable via the same address as the public website
IDS/IPS (intrusion detection/prevention)Known attack patterns at network level, regardless of which application is running behind
Automatic security updates for the firewall itselfAn unpatched firewall is no longer a firewall, but an additional target

RBL lists: the standard way in which reputation is delivered

RBL stands for Real-time Blackhole List, a term from the mail world: one address per line, retrievable over HTTP, reloaded regularly. Practically every firewall can read such a list and build rules from it — OPNsense and pfSense as URL Table Alias, HAProxy as an ACL file, FortiGate as External Block List, Palo Alto as External Dynamic List, Cisco, Sophos, Juniper and MikroTik with their own names for the same principle.

This is exactly where our own module comes in — and exactly where the second layer begins.

Layer 2: Web RBL — the bridge between application and firewall

A firewall sees packets, not application logic. It does not know that a request for /xmlrpc/2/common is a login attempt, that twenty different paths in fourteen seconds mean a scanner, or that an address has just successfully guessed a password. Only Odoo itself knows all of that. Web RBL, our own open-source module (AGPL-3), makes this knowledge usable — for Odoo itself and, delivered as an RBL list, for the firewall in front of it as well.

Web RBL threat lists: Tor, Spamhaus DROP, FireHOL, blocklist.de

Threat lists continuously synchronised, each with its own level.

A brief summary of what is described in detail in the previous article:

  • Pattern detection in paths: .env files, .git directories, configuration files, WordPress and PHP probes, path traversal, command execution via new AI interfaces
  • Login defence that counts across restarts — unlike Odoo's own counter, which lives in working memory
  • Scoring of every address from 0 to 100, with the justification in plain language
  • Misconfigurations (QNAP, Autodiscover, Synology) are recognised and never blocked, because a block does not fix the fault but merely hides it
  • Third-party threat lists such as Spamhaus, FireHOL and Tor exit nodes, continuously synchronised
  • Allowlist for addresses that should never be blocked

Two properties are particularly important for this article, because they are directly connected with the firewall and with login.

A sluggish list is a list you can trust

The allowlist — addresses that are never blocked, such as your own site connections — as a rule changes rarely. That is precisely its value, not its flaw: when a quiet list barely moves over days, every rare change stands out immediately. The daily automatic update does not exist because a lot would change, but so that the rare change does not have to be added by hand — and that is exactly the point at which one forgets it. One of our own misconfigurations last month came to light in exactly this way: not through many events, but through the one that nobody knew about, until a customer's QNAP web API was wrongly blocked. Since then QNAP has been on the list of misconfigurations that are never blocked, only reported.

Login is the place a firewall does not see

A firewall can block an address. It cannot know whether a login succeeded, and certainly not whether it came from an address that had been searching for credentials shortly before. Web RBL can: a score above an adjustable threshold prohibits login altogether, and a successful login from a conspicuous address is reported — that is the link to the next layer.

Layer 3: Securing Odoo itself

Two-factor authentication: a second secret that cannot be reused

The biggest problem with passwords is not their quality, but their reuse. A password that was stolen from another service works just as well with us, as long as it is the same one. Two-factor authentication (2FA, also called TOTP) counters this with a second secret: a six-digit code that changes every thirty seconds and is calculated from a secret known only to your own smartphone. A stolen password alone is then no longer enough.

Odoo 19 Community has this built in — as an installable module, Two-Factor Authentication (TOTP), supplemented by an email fallback option. Each user sets it up for themselves, via QR code, with any common authenticator app:

Odoo two-factor authentication: QR code to scan with the authenticator app

The setup: scan the QR code, confirm the six-digit code once, done.

On its own, however, that only helps those who set it up for themselves — and experience shows that without compulsion they remain the minority. Odoo therefore has an enforcement policy: either for employees only (internal users) or for everyone, portal users included. Without a second secret set up, nobody gets past the login form any more without at least confirming by email code.

Password policy: a minimum length cannot be taken for granted

Without an additional module, Odoo Community relies on no minimum length for passwords — a user can set a password of three characters if nobody stops them. The Password Policy module closes exactly this gap: a minimum length that is enforced on the server side, not merely suggested in the browser. Anyone who wants more — an enforced expiry period, a history against reuse — needs an OCA or third-party module for it; the Community edition is deliberately kept lean.

Permissions: only those who need it get access

Odoo separates three levels out of the box: portal users (only their own customer or supplier portal), internal users (the backend, with rights per application) and administrators (unrestricted access including technical settings). The most common mistake is not a password that is too weak, but an administrator role granted too generously: someone who only has to create invoices does not need access to the system settings.

Two principles carry most of the load:

Both can be checked in the same view in which two-factor authentication is set up:

Odoo account security: change password, 2FA, API keys, passkeys, logged-in devices

One overview, four levers: password, second factor, API keys, logged-in devices.

Sessions and devices: who is logged in right now

The same view also shows which devices an account is currently logged in from — and allows you to log out a single one or all of them at once. After a lost laptop or the suspicion of a compromised password this is the quickest effective step: the session ends immediately, regardless of whether the password has already been changed.

Layer 4: Database and operations

The fourth layer is the least visible and at the same time the most unforgivable, because a mistake here can undo everything built up before.

  • Regular, verified backups, stored separately from the server itself. A backup that has never been restored is a supposition, not a backup.
  • Secrets belong in no log file. Passwords, API keys, licence data — anyone who writes their own extensions should treat them like the master password itself: log them nowhere, not even “just for debugging”.
  • Keep modules up to date, third-party modules above all. Free add-on modules (OCA and others) naturally lag behind new Odoo versions; before any installation it is worth checking which dependencies come along automatically.

The login path as a whole

The four layers do not work one after the other in separate rooms, but on the same request, step by step. This is clearest using a login as an example:

Flow of a login through five checkpoints: firewall, login form, Web RBL, 2FA, session

Five places at which a malicious request can end before it reaches the actual target — and only one at which a legitimate user passes them all.

Attack scenarios and how to counter them

The following overview assigns real attack patterns to the layers that actually stop them. Several of them are not theory, but our own observations from seventeen days of real traffic on our five websites.

Attack scenarioHow it worksWhat stops it
Password guessing A script tries hundreds of combinations against the login form or XML-RPC Firewall rate limiting, Web RBL counter across restarts, block after ten attempts, immediate block when a wait message is ignored
Reused credentials stolen elsewhere The attacker already knows the username and password — from another, hacked service Two-factor authentication stops the login despite a correct password; Web RBL additionally reports a successful login from a conspicuous address
Search for forgotten secrets Automated requests for .env, .git, cloud access keys — in our case 57,721 requests in seventeen days for .env alone Web RBL blocks on the first hit; the firewall then receives the address as an RBL entry for all other services too
Directory and path scanners Dozens of invented paths within a few seconds, in search of forgotten applications Behaviour detection: many error pages, hardly a hit, in a short time — regardless of whether the path matches a known pattern
Misconfigured device of your own A sync client or an email program points to the wrong address by mistake and knocks every minute Recognition as a misconfiguration rather than an attack, ticket instead of block — a block would not fix the fault, only postpone it
Automated harvesting of mandatory information A harvester retrieves imprint pages under foreign spellings, often in preparation for a wave of warning letters The canonical path always stays reachable (legally necessary), foreign spellings are recognised and reported or blocked
Lost or stolen device A logged-in notebook or mobile phone falls into the wrong hands Session overview with immediate logout of all devices, regardless of the password
Internal permission set too broadly A user account with more rights than necessary is compromised or misused Least necessary privilege per application limits the damage from the outset to what the account really needs
Misuse of an external interface A stolen API key or a compromised third-party system accesses via XML-RPC/JSON-RPC Separate, revocable API keys instead of the user password; Web RBL also monitors failed RPC logins
Misjudged search engine crawler A legitimate crawler generates so much traffic that it looks like a distributed attacker — on one of our sites it was over seventy per cent of all traffic, caused by GPTBot An allowlist with the published address ranges of well-known search engines prevents a wrong block that would remove your own site from indexing
Outdated third-party module with a known vulnerability A security vulnerability in a free add-on module becomes public, the update only arrives weeks later Check before every installation what comes along automatically; updates first on a test instance, not on the open heart
Open database administration The management interface is reachable over the open internet; a guessed or weak master password is enough to delete or copy databases The interface is never exposed publicly, the master password stays long, random and written down nowhere

Step by step: securing your own Odoo installation

The following sequence is the one in which we ourselves would proceed — from the greatest effect to the finest setting.

1. Enforce two-factor authentication

  1. If not yet installed: open Apps, search for “Two-Factor Authentication” and install it (with several websites, “Two-Factor Authentication by Mail” is additionally recommended as a fallback option).
  2. Open Settings → General Settings → Permissions.
  3. Activate “Enforce two-factor authentication”.
  4. Choose a policy: “Employees only” for internal users, “All users” if portal users (customers with access) are also to be included.
  5. Save. From the next login attempt, Odoo requires at least the email code from every user without a second secret set up, until they have set up the authenticator app.

2. Set a minimum length for passwords

  1. Open Apps, search for “Password Policy” and install it.
  2. Open Settings → General Settings → Permissions.
  3. Set “Minimum password length” — twelve characters is a sensible starting value.
  4. Save. The rule applies immediately to every new or changed password, not retroactively to existing passwords.

3. Review permissions

  1. Open Settings → Users & Companies → Users.
  2. Open each user individually and check the tab with the access rights per application: does this person really need “Manager” or “Administrator”, or is “User” enough?
  3. Check in particular: who has access to “Settings” itself? That should be a very small group.
  4. In the “Account Security” tab of the respective technical user, create a separate API key for every external integration (accounting, your own scripts, time tracking), instead of passing on the user password.

4. Install Web RBL and observe before arming it

  1. Place the module from github.com/Alex0176/odoo-web-rbl in the add-on path and install it.
  2. Observe for a few days: the menu Web RBL → Analysis shows which patterns actually take effect.
  3. Only then switch on web_rbl.sperren_aktiv (Settings → Technical → System Parameters) — from here on, detected probes are actually rejected.
  4. Integrate the blocklist into the firewall as an RBL list via the token-protected address given in the module (as a URL Table Alias on OPNsense/pfSense, as an ACL file on HAProxy).

5. Secure the firewall itself

  1. Make the firewall's management interface reachable exclusively from the internal network, never via the same public address as the website.
  2. Activate automatic security updates for the firewall software, where the vendor offers them.
  3. Check the TLS configuration: only current protocol versions, deactivate outdated encryption methods.
  4. If available: integrate a well-known reputation list (such as Spamhaus DROP) directly on the firewall — independently of Web RBL, because the firewall thereby also sees traffic to services that Odoo never reaches.

6. Close database administration

  1. Check whether /web/database/manager is reachable from outside — if so, set list_db = False in the Odoo configuration or block the path at firewall level.
  2. Set the master password of the database administration long and random, and do not write it down anywhere that anyone else can read.

7. Verify the backup, do not just set it up

  1. Set up an automatic, regular backup, stored separately from the Odoo server.
  2. Restore it at least once for real and check whether the restoration works — an unverified backup is a supposition.

None of these steps replaces any of the others. Anyone who implements only one of them has reinforced one door and left all the others open — anyone who implements all seven has a defence that still holds even when a single layer fails.

What this architecture does not replace

None of the measures described makes diligence unnecessary. A module that rejects .env probes does not make an accidentally published .env file harmless. Two-factor authentication does not protect against a user who reads out their code to a caller on the phone. And a firewall does not replace a decision about who really needs which permission. Security architecture creates the conditions under which a single mistake does not immediately become an incident — it does not relieve anyone of diligence.

Frequently asked questions

Is a strong password enough to secure Odoo 19?

No. A password can be stolen elsewhere, quite regardless of its quality, and then works with every service that accepts the same password. Only the combination with two-factor authentication, a firewall in front and a sensible permission structure yields a protection that still holds even after a stolen password.

How do I activate two-factor authentication in Odoo 19?

Install the “Two-Factor Authentication (TOTP)” module via the Apps management, then activate enforcement under Settings → General Settings → Permissions and choose between “Employees only” and “All users”. Each user then sets up their own second factor via QR code.

What is an RBL list, and why does Odoo need one?

RBL (Real-time Blackhole List) is an address list retrievable over HTTP that practically every firewall can read. Odoo itself ships no such list — our Web RBL module closes this gap by detecting attack traffic from its own application log and passing it back as an RBL list to the upstream firewall.

Is Odoo 19 Community adequately secured without additional modules?

Not completely. Without the Password Policy module there is no minimum password length, without Two-Factor Authentication no second factor, and without a module such as Web RBL, Odoo recognises neither probing attempts nor repeated login attempts across a restart. All four can be added at no cost.

Availability

Web RBL is publicly available under the AGPL-3 and runs in production for us on five websites:

github.com/Alex0176/odoo-web-rbl

The complete description of its functions, with all patterns, the scoring and the threat lists, is in the previous article: Web RBL – blocklist for attack traffic on your own websites.

We welcome questions, comments and bug reports — preferably as an issue on GitHub.