系统配置

本文档描述了在生产环境或面向互联网的服务上设置 Odoo 的基本步骤。对于未暴露在互联网上的开发系统 installation ,通常不是必需的。

警告

如果要设置一个公共服务器,请务必查看安全 安全 建议!

数据库过滤(dbfilter)

Odoo是一个多租户系统,单个 Odoo 系统可以运行多个数据库实例。它也是高度可定制的,可以根据“当前数据库”进行定制(从加载模块开始)。

This is not an issue when working with the backend (web client) as a logged-in company user。这不是问题,登录时选择数据库,之后加载自定义项。

对于未登录的用户(门户、网站)来说,这就是一个问题,因为它们没有绑定到数据库,Odoo 需要知道应该使用哪个数据库来加载网站页面或执行操作。如果不使用多租户,这不是问题,因为只有一个数据库可以使用,但是如果有多个数据库可以访问,Odoo 需要一个规则来知道应该使用哪个。

这就是 --db-filter 的目的之一,它指定如何根据请求的主机名(域)选择数据库。该值是一个正在表达式 regular expression ,可能包括动态注入的主机名 (%h) 或访问的第一个子域 (%d) 。

对于在生产环境中托管多个数据库的服务器,特别是如果使用了 website ,则 必须 设置 dbfilter ,否则许多功能将无法正常工作。

配置实例

  • 只显示名称以 mycompany 开头的数据库

/etc/odoo.conf 中:

[options]
dbfilter = ^mycompany.*$
  • 只显示 www 之后的第一个子域名匹配的数据库。例如传入的请求是 www.mycompany.commycompany.co.uk ,将使用 mycompany 作为数据库。而传入 www2.mycompany.comhelpdesk.mycompany.com 时则不显示。

/etc/odoo.conf 中:

[options]
dbfilter = ^%d$

注解

正确的设置 --db-filter 选项是保护部署安全的重要部分。设置成功并确保每个主机名只匹配一个数据库,将有效阻止访问数据库管理器页面,并使用 --no-database-list 启动参数来阻止列出数据库,同样会阻止访问数据库管理页面。参见security

PostgreSQL

默认情况下,PostgreSQL只允许通过UNIX套接字和环回地址(“localhost”,即安装PostgreSQL服务器的机器的地址)进行连接。

如果 Odoo 和 PostgreSQL部署在同一台主机上,UNIX套接字是可以的,并且在默认情况下可不提供主机名。但是如果 Odoo 和 PostgreSQL 运行在不同的主机 1 上,就需要监听网络接口 2 :

  • 在运行 Odoo 的主机和运行 PostgreSQL 的主机之间采用环回地址并使用SSH隧道 use an SSH tunnel 连接时,需要配置 Odoo 连接到SSH隧道

  • 在安装 Odoo 的主机上通过 ssl (有关详细信息请参阅 PostgreSQL connection settings )连接时,需要 Odoo 通过网络连接

配置实例

  • 在localhost上设置允许 tcp 连接

  • 在 192.168.1.x 上配置允许 tcp 连接

在配置文件 /etc/postgresql/<YOUR POSTGRESQL VERSION>/main/pg_hba.conf 中设置如下:

# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
host    all             all             192.168.1.0/24          md5

在配置文件 /etc/postgresql/<YOUR POSTGRESQL VERSION>/main/postgresql.conf 中设置如下:

listen_addresses = 'localhost,192.168.1.2'
port = 5432
max_connections = 80

Odoo 配置

开箱即用,Odoo通过UNIX套接字连接到本地postgres,端口为5432。当Postgres不在本地部署或不使用安装默认值时,可以使用 数据库选项 重新配置。

使用package安装时 packaged installers 将自动创建一个新用户( odoo ),并将其设置为数据库用户。

  • 数据库管理界面受 admin_passwd 设置保护。只能使用配置文件设置 admin_passwd (译注:说的应该是只能存储在配置文件中吧,数据库管理界面也能改。),只需在进行数据库更改之前检查即可。它应该设置为随机生成的值,以确保第三方不能使用此接口。

  • 包括数据库管理界面在内的所有数据库操作都使用 数据库选项 中的设置,使用数据库管理界面还需要PostgreSQL用户具有 createdb 权限。

  • 因为 PostgreSQL 数据库中用户始终可以删除其拥有的数据库。要想使数据库管理界面完全不起作用, 需要在创建 PostgreSQL 用户时使用 no-createdb (此角色不可以创建新数据库)参数,并且数据库的拥有者必须是 PostgreSQL 的其他用户。

    警告

    PostgreSQL 用户 不能 是超级用户

配置实例

  • PostgreSQL 的 ip 地址: 192.168.1.2

  • 端口: 5432

  • 数据库用户: odoo

  • 密码: pwd

  • 数据库过滤器配置:仅筛选名称以 mycompany 开头的 db

/etc/odoo.conf 中:

[options]
admin_passwd = mysupersecretpassword
db_host = 192.168.1.2
db_port = 5432
db_user = odoo
db_password = pwd
dbfilter = ^mycompany.*$

使用 SSL 连接 PostgreSQL数据库

从 Odoo 11.0 开始,可以设置强制采用SSL方式连接 PostgreSQL。通过配置参数 db_sslmode 来实现。选项包括 ‘disable’, ‘allow’, ‘prefer’, ‘require’, ‘verify-ca’ or ‘verify-full’ 。

详见 PostgreSQL Doc

内置服务器

Odoo 内建HTTP服务器,支持多线程或多进程( multithreading or multiprocessing )。

对于生产模式下,建议使用多进程( multiprocessing )方式,因为它可以提高稳定性,更好地利用计算资源,并且能够监控和限制资源使用。

  • 多进程(Multiprocessing)模式通过 a non-zero number of worker processes 选项启用,worker的数量应基于机器中的CPU核数(还需要为 cron 的执行留出一些空间,具体取决于预测的cron工作量)

  • 需要根据具体硬件配置来设置Worker 数量,以避免资源耗尽

警告

多进程(multiprocessing)模式目前在Windows上不可用

Worker 数计算方法

  • 按经验 worker = (#CPU * 2) + 1

  • Cron worker 需要占用 CPU

  • 1 worker ≈ 6 个并发用户

内存计算方法

  • 一般认为20%的请求是繁重任务的请求,而80%是轻量任务的请求

  • 一个承担繁重请求任务的 worker,在所有计算字段都设计得很好,SQL请求也设计得很好的情况下,消耗内存大约为1GB

  • 承担轻量请求任务的 worker 消耗的内存大约150MB

所需内存 = #worker * ( (轻量任务worker占比 * 轻量任务worker内存消耗) + (繁重任务worker占比 * 繁重任务worker内存消耗) )

在线聊天(LiveChat)

在多进程(multiprocessing)模式下,LiveChat的 worker 会自动启动并监听端口 the gevent port ,但客户端不会连接到它。

必须具有一个接受重定向请求的端口,该请求的URL以 /websocket/ 开头。其他请求则重定向到正常 HTTP 请求端口 normal HTTP port

要实现这样的目标,需要在Odoo前面部署一个反向代理服务,如nginx或apache。还需要将更多的http Headers 转发到Odoo,并在Odoo配置中激活proxy_mode,让Odoo读取这些 headers。

配置实例

  • 服务器CPU: 4 核 8 线程

  • 并发用户数为:60

  • 理论上需要的 worker数为:60 / 6 = 10

  • 理论上CPU能提供的最大worker数为:(4 * 2) + 1 = 9

  • 按以上推算,将设置为 8 个 worker + 1 个 cron。还需要使用监视系统来测量CPU负载,并检查它是否在7和7.5之间。

  • 所需内存为: 9 * ((0.8*150) + (0.2*1024)) ≈ 3G

/etc/odoo.conf 配置如下:

[options]
limit_memory_hard = 1677721600
limit_memory_soft = 629145600
limit_request = 8192
limit_time_cpu = 600
limit_time_real = 1200
max_cron_threads = 1
workers = 8

HTTPS

无论通过网站/web客户端还是web服务访问,Odoo都以明文传输身份验证信息。这意味着Odoo的安全部署必须使用 HTTPS3 。SSL termination 可以通过几乎任何SSL termination 代理实现,但需要以下设置:

  • 启用选项 proxy mode 。该选项只能在启用反向代理时启用

  • 设置 SSL termination 代理( ` Nginx termination example`_ )

  • 设置代理( Nginx proxying example )

  • SSL termination 还应该自动将非安全连接重定向到安全端口

配置实例

  • 将http请求重定向到https

  • 代理请求(Proxy requests to odoo)

/etc/odoo.conf 中:

proxy_mode = True

/etc/nginx/sites-enabled/odoo.conf 中的设置:

#odoo server
upstream odoo {
  server 127.0.0.1:8069;
}
upstream odoochat {
  server 127.0.0.1:8072;
}
map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

# http -> https
server {
  listen 80;
  server_name odoo.mycompany.com;
  rewrite ^(.*) https://$host$1 permanent;
}

server {
  listen 443 ssl;
  server_name odoo.mycompany.com;
  proxy_read_timeout 720s;
  proxy_connect_timeout 720s;
  proxy_send_timeout 720s;

  # Add Headers for odoo proxy mode
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_set_header X-Real-IP $remote_addr;

  # SSL parameters
  ssl_certificate /etc/ssl/nginx/server.crt;
  ssl_certificate_key /etc/ssl/nginx/server.key;
  ssl_session_timeout 30m;
  ssl_protocols TLSv1.2;
  ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
  ssl_prefer_server_ciphers off;

  # log
  access_log /var/log/nginx/odoo.access.log;
  error_log /var/log/nginx/odoo.error.log;

  # Redirect websocket requests to odoo gevent port
  location /websocket {
    proxy_pass http://odoochat;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
  }

  # Redirect requests to odoo backend server
  location / {
    proxy_redirect off;
    proxy_pass http://odoo;
  }

  # common gzip
  gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
  gzip on;
}

Odoo 是一个 WSGI 应用

可以将 Odoo 作为标准 WSGI 应用挂载。Odoo 提供了 WSGI 的基础启动脚本 doo- WSGI .example.py 。可根据需要自定义(从安装目录复制),以便在 odoo.tools.config 中正确使用,而不是通过命令行或配置文件。

但是,WSGI 服务器将仅暴露 Web 客户端、网站和 Web 服务 API 的主 HTTP 端点。因为Odoo不再控制worker的创建,它不能设置cron或livechat worker

Cron Workers

在WSGI部署方式下运行cron作业

  • 典型运行方法(运行 doo-bin)

  • 连接到运行cron作业的数据库(运行命令 odoo-bin -d )

  • 这不该暴露在网络中。为了确保cron runner 无法被访问网络,可以使用选项 odoo-bin --no-http 或在配置文件中设置 http_enable = False 完全禁用内置HTTP服务器

在线聊天(LiveChat)

WSGI部署的第二个问题是LiveChat:大多数HTTP连接相对较短,并且可以快速释放以接收下一个请求,LiveChat需要为每个客户端提供长连接,以实现准实时通知。

这与基于进程(process-based)的worker 模型相冲突,因为它将绑定worker进程(processes),并防止新用户访问系统。然而,这些长连接很小,大多是在等待通知。

在WSGI应用中支持实时聊天/通知的解决方案是:

  • 部署一个线程(threaded)版本(而不是基于进程(process-based)的preforking ),并将以 /websocket/ 开头的URL请求重定向到 Odoo,这是最简单的websocket URL可以兼作cron实例的方法。 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.

  • 通过 odoo-gevent 部署Odoo 并代理以 /websocket/ 开头请求 the gevent port

静态文件和附件服务

为了方便开发,Odoo 内置静态文件和附件服务。其性能方面可能不理想,静态文件通常应该由静态HTTP服务器提供服务。

静态文件服务

Odoo静态文件位于每个模块的 static/ 文件夹中,因此可以通过拦截 /MODULE/static/FILE 的所有请求,并在各种插件路径中查找正确的模块(和文件)来提供静态文件服务。

Example

使用 debian软件包 安装 Odoo 社区版和企业版时 ,插件路径是 /usr/lib/python3/dist-packages/odoo/addons。添加以下块到 NGINX(https)的配置文件中,以使 NGINX 为Odoo提供静态文件服务。

location @odoo {
    # copy-paste the content of the / location block
}

# Serve static files right away
location ~ ^/[^/]+/static/.+$ {
    root /usr/lib/python3/dist-packages/odoo/addons;
    try_files $uri @odoo;
    expires 24h;
}

Example

使用 源代码 安装社区版和企业版时 ,两个版本的git存储库已分别在 /opt/odoo/opt/odoo-enterprise 中。插件路径是 /opt/odoo/odoo,/opt/odoo/addons,/opt/odoo-enterprise 。添加以下块到 NGINX(https)的配置文件中,以使 NGINX 为 Odoo 提供静态文件服务。

location @odoo {
    # copy-paste the content of the / location block
}

# Serve static files right away
location ~ ^/[^/]+/static/.+$ {
    try_files /static-base$uri /static-addons$uri /static-enterprise$uri @odoo$uri;
    expires 24h;
}

location /static-base {
    internal;
    alias /opt/odoo/odoo/addons;
}

location /static-addons {
    internal;
    alias /opt/odoo/addons;
}

location /static-enterprise {
    internal;
    alias /opt/odoo-enterprise;
}

警告

实际的 NGINX 配置文件在很大程度上取决于具体安装情况。上述两个片段仅突出显示两种可能的配置,不能按原样使用。

附件服务

附件是存储在文件存储中的文件,Odoo对其访问进行规范管理。它们不能通过静态web服务器直接访问,因为访问它们需要在数据库中进行多次查找,以确定文件存储在哪里以及当前用户是否可以访问它们。

尽管如此,一旦文件被 Odoo 找到并验证了访问权限,使用静态web服务器而不是 Odoo 来提供文件访问是一个好主意。由 Odoo 委派服务文件到静态web服务器, X-Sendfile (apache) 或 X-Accel (nginx) 扩展必须在静态web服务器上启用和配置。设置好之后,用选项 --x-sendfile CLI标志(这个唯一的标志用于 x-sendfile 和 X-Accel )。

注解

  • apache(和兼容的web服务器)的 X-Sendfile 扩展不需要任何补充配置。

  • NGINX 的X-Accel扩展 需要 以下额外配置:

    location /web/filestore {
        internal;
        alias /path/to/odoo/data-dir/filestore;
    }
    

    如果你不知道文件存储的路径是什么,用 --x-sendfile 选项启动Odoo,并通过Odoo导航到 /web/filestore URL(不要通过NGINX导航到URL)。可看到此日志,他是一个警告,消息中包含你需要的配置。

安全

对于初学者,请记住,保护信息系统是一个持续的过程,而不是一次性操作。在任何时候,安全都取决于环境中最薄弱的环节。

因此,请不要将本节作为防止所有安全问题的最终措施清单。它只是对应该确保包含在安全行动计划中的首要事项的一个总结。其余的将来自于操作系统和发行版的最佳安全实践、用户、密码和访问控制管理等方面的最佳实践。

在部署面向互联网的服务器时,请务必考虑以下与安全相关的主题:

  • 设置一个强壮的超级管理员、管理员密码,并在系统设置后立即限制访问数据库管理页面。参见 数据库管理器安全

  • 为所有数据库上的所有管理员帐户选择唯一的登录名和强密码。不要使用 ‘admin’ 作为登录名。不要将这些登录用于日常操作,只用于控制、管理安装。 永远不要 使用任何默认密码,如admin/admin ,即使是测试、演示数据库。

  • 不要 在面向互联网的服务器上安装演示数据。带有演示数据的数据库包含默认的登录名和密码,这些登录名和密码可以用来进入系统并造成严重后果,甚至在演示、开发系统上也是如此。

  • 使用适当的数据库过滤器 ( --db-filter ) 来根据主机名限制数据库的可见性。参见 数据库过滤(dbfilter) 。也可使用 -d 来提供(用逗号分隔的)可用数据库筛选列表,而不是让系统从数据库后端获取。

  • 一旦 db_namedb_filter 配置好,每个主机名只匹配一个数据库,应该将 list_db 配置选项设置为 False ,以完全阻止列出数据库,并阻止对数据库管理界面的访问(这也容易受攻击的 --no-database-list 命令行选项)。

  • 确保 PostgreSQL 用户 ( --db_user ) 不是 超级用户,并且数据库属于不同的用户。例如,如果您正在使用专用的非特权用户 db_user ,那么它们可能属于 postgres 超级用户。参见 Odoo 配置

  • 通过 GitHub 、 https://www.odoo.com/page/downloadhttp://nightly.odoo.com 下载最新版本,定期安装最新版本,以保持安装更新。

  • 将服务器配置为多进程模式(multi-process),并根据典型的使用情况(内存/CPU/超时设置)进行适当的限制。参见 内置服务器

  • 运行Odoo后端的web服务器提供有效的SSL证书提供 HTTPS 终结 (HTTPS termination ),以防止窃听明文通信。SSL证书很便宜,还有许多免费的选择。配置web代理来限制请求的大小并设置适当的超时时间,然后启用 proxy mode 选项。参见 HTTPS

  • 如果需要允许远程SSH访问服务器,请确保为 所有 帐户设置一个强密码,而不仅仅是 root 。强烈建议完全禁用基于密码的身份验证,只允许公钥身份验证。也可以考虑通过VPN限制访问,只允许防火墙中受信任的ip,和(或)运行一个 brute-force 检测系统,如 fail2ban 等。

  • 考虑在代理或防火墙上安装适当的 rate-limiting ,以防止暴力攻击和拒绝服务攻击。参见 阻止暴力攻击 了解具体的方法。

    许多网络提供商为分布式拒绝服务攻击(DDOS)提供自动缓解方案,但这通常是可选的服务,具体需要咨询他们。

  • 只要可能,尽量将面向公众的演示、测试、演示实例托管在与生产实例不同的机器上。并采取与生产相同的安全措施。

  • 如果您的面向公共的 Odoo 服务器可以访问敏感的内部网络资源或服务(例如通过私有VLAN),请执行适当的防火墙规则来保护这些内部资源。这将确保 Odoo 服务器不会被意外使用(或恶意用户操作的结果)来访问或破坏这些内部资源。通常,这可以通过在防火墙上应用出站缺省 DENY 规则来实现,然后只显式授权对 Odoo 服务器需要访问的内部资源的访问。 Systemd IP traffic 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.

  • 如果托管多个客户,则使用容器或适当的 “jail” 技术将客户数据和文件彼此隔离。

  • 设置数据库和文件存储数据的每日备份,并将它们复制到服务器本身无法访问的远程存档服务器。

阻止暴力攻击

对于面向互联网的部署,对用户密码的暴力攻击非常常见,对于Odoo服务器来说,这种威胁不应被忽视。每当执行登录尝试时,Odoo 都会发出一个日志条目,并报告结果:成功或失败,以及目标登录和源IP。

日志条目格式如下。

失败的登录:

2018-07-05 14:56:31,506 24849 INFO db_name odoo.addons.base.res.res_users: Login failed for db:db_name login:admin from 127.0.0.1

成功登录:

2018-07-05 14:56:31,506 24849 INFO db_name odoo.addons.base.res.res_users: Login successful for db:db_name login:admin from 127.0.0.1

这些日志可以很容易地被入侵防御系统分析,如 fail2ban

例如,下面的 fail2ban 筛选器定义应该匹配失败的登录:

[Definition]
failregex = ^ \d+ INFO \S+ \S+ Login failed for db:\S+ login:\S+ from <HOST>
ignoreregex =

这可以与 jail definition 一起使用,以阻止HTTP(S)上的攻击IP。

当在1分钟内检测到来自同一IP的10次失败登录尝试时,阻塞该 IP 15分钟:

[odoo-login]
enabled = true
port = http,https
bantime = 900  ; 15 min ban
maxretry = 10  ; if 10 attempts
findtime = 60  ; within 1 min  /!\ Should be adjusted with the TZ offset
logpath = /var/log/odoo.log  ;  set the actual odoo log path here

数据库管理器安全

Odoo 配置 提到了 admin_passwd

该设置用于所有数据库管理界面(用于创建、删除、转储或恢复数据库)。

如果管理界面完全不能访问,您应该将 list_db 配置选项设置为 False ,以阻止对所有数据库选择和管理界面的访问。

警告

强烈建议禁用任何面向internet的系统的数据库管理器!它是一种开发、演示工具,可以方便地快速创建和管理数据库,它不是为在生产环境中使用而设计的,甚至可能向攻击者暴露危险的特性。它也不是为处理大型数据库而设计的,可能会触发内存限制。

在生产系统上,数据库管理操作应该总是由系统管理员执行,包括新建数据库和自动备份。

确保设置一个适当的 db_name 参数(还有 db_filter ),以便系统可以为每个请求确定目标数据库,否则用户将被阻塞,因为不允许自己选择数据库。

如果管理界面必须只能从选定的一组机器上访问,则使用代理服务器的特性来阻止对所有以 /web/database 开头的路由的访问,除了(可能) /web/database/selector 显示数据库选择界面。

如果数据库管理界面应该保持可访问状态, admin_passwd 必须从默认的 admin 更改修改为其他:在数据库更改操作之前,会检查此密码。

它应该被安全地存储,并且应该随机生成,例如。

$ python3 -c 'import base64, os; print(base64.b64encode(os.urandom(24)))'

它将生成一个32个字符的伪随机可打印字符串。

支持的浏览器

Odoo支持市场上所有主流的桌面和移动浏览器,只要它们得到了发行商的长期支持。

下面是支持的浏览器:

  • 谷歌 Chrome

  • Mozilla Firefox

  • 微软 Edge

  • 苹果 Safari

警告

在提交错误报告之前,请确保您的浏览器是最新的,并且仍受其发行商的支持。

注解

Odoo 从13.0开始支持ES6。因此,IE已被放弃支持。

1

让多个Odoo安装使用相同的PostgreSQL数据库,或者为两个软件提供更多的计算资源。

2

从技术上讲,像 socat 这样的工具可以跨网络代理UNIX套接字,但这主要用于只能通过 UNIX 套接字使用的软件

3

或者只能通过内部分组交换(packet-switched )网络访问,但这需要安全的交换机,防止 ARP spoofing 并且不能使用 WiFi 。即使在安全的分组交换( packet-switched)网络上,也建议部署在HTTPS上,并且可能降低成本,因为在受控环境中部署 “自签名” 证书比在internet上部署更容易。