dbfilter của Odoo chọn database nào mà một request được truy cập ra sao, những cái bẫy regex cần tránh, và cách module dbfilter_from_header của OCA giúp Nginx gắn tên miền riêng với từng database.
Odoo là hệ thống multi-tenant: một Odoo server có thể chạy và phục vụ nhiều database. Tùy chọn dbfilter quyết định mỗi request được truy cập những database nào.
Tài liệu triển khai chính thức có phần giới thiệu khá tốt về lọc database. Bài viết này đi sâu vào cách nó hoạt động trong thực tế, những cái bẫy cần tránh, và cách xử lý khi tên miền không khớp với tên database.
dbfilter hoạt động như thế nào?
dbfilter là một biểu thức chính quy (regex) được dựng động cho từng request. Bạn có thể dùng các biến %d và %h để điều chỉnh regex theo header Host của HTTP request:
%dđược thay bằng subdomain đầu tiên sauwww:https://demo.example.com:%d=demohttps://www.demo.example.com:%d=demo
%hđược thay bằng toàn bộ tên miền, bỏ phần port nếu có:https://demo.example.com:%h=demo.example.comhttps://demo.example.com:8080:%h=demo.example.com
Vì vậy, nếu đặt dbfilter = ^%d.*\Z, người dùng truy cập https://demo.example.com sẽ vào được các database khớp với ^demo.*\Z, chẳng hạn:
demodemo_backup_20180404
Cẩn thận với regex quá rộng
Odoo lọc danh sách database bằng re.match:
dbs = [i for i in dbs if re.match(r, i)]
re.match neo regex ở đầu tên nhưng không neo ở cuối, nên rất dễ viết ra một regex rộng hơn dự định. Ví dụ, nếu đặt dbfilter = demo_*, regex này cũng khớp với demoinefromage_prod.
Khi tên miền và tên database không khớp: dbfilter_from_header
Không phải lúc nào cũng suy ra được tên database từ tên miền.
Ví dụ, một instance Odoo có thể phục vụ hai database:
customer1_prodcustomer2_prod
Nhưng mỗi khách hàng lại muốn dùng tên miền riêng:
https://back.customer1.comhttps://app.customer2.com
Để xử lý trường hợp này, bạn có thể dùng module dbfilter_from_header của OCA.
Cài đặt
git clone https://github.com/OCA/server-tools -b 9.0 --no-checkout --single-branch --depth 1
cd server-tools
git config core.sparsecheckout true
echo "dbfilter_from_header" > .git/info/sparse-checkout
git read-tree -mu HEAD
Cấu hình
Ở phía Nginx, cần khai báo một bộ lọc database riêng cho từng virtual host. Trong ví dụ này, với https://back.customer1.com:
server_name back.customer1.com;
(...)
location / {
(...)
proxy_set_header X-Odoo-dbfilter ^customer1_.*\Z;
}
Hai điểm cần lưu ý:
- trước khi chuyển request cho Odoo, Nginx lấy tất cả HTTP header, chuyển thành chữ thường và đổi dấu gạch ngang thành dấu gạch dưới;
- chúng tôi dùng
\Zthay cho$để khớp với cuối chuỗi, vì Nginx không escape được$.
Hai tầng lọc
dbfilter_from_header tôn trọng dbfilter đã khai báo ở cấp Odoo, nên có thể thiết lập hai tầng lọc. Trong cấu hình Odoo:
dbfilter = ^.+prod.*$
Và trong Nginx:
proxy_set_header X-Odoo-dbfilter ^.*customer1.*\Z;