You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

移除Odoo多语言URL路径:通过Nginx实现单域名对应单语言

问题描述

我正在使用Odoo 16.0和18.0(社区版),以Nginx作为反向代理。Odoo原生多语言通过URL路径实现:

  • www.mycompany.com/en - 英文版本
  • www.mycompany.com/it - 意大利语版本

Odoo会设置名为frontend_lang的Cookie,值为en_US或it_IT。同时默认语言会自动重定向:比如默认语言为英文时,www.mycompany.com/en会重定向到www.mycompany.com/,www.mycompany.it/en会重定向到www.mycompany.it/。

我的两个域名Nginx配置如下:

.com域名配置

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

map $sent_http_content_type $content_type_csp {
    default "";
    ~image/ "default-src 'none'";
}


# http -> https
server {
    if ($host = www.mycompany.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  listen 80;
  listen [::]:80;
  server_name www.mycompany.com;
  rewrite ^(.*) https://$host$1 permanent;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  listen 443 quic;
  listen [::]:443 quic;
  http2 on;

  server_name www.mycompany.com;

  proxy_read_timeout 720s;
  proxy_connect_timeout 720s;
  proxy_send_timeout 720s;

  # 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;
    proxy_set_header Host $host;
  }

  # Redirect requests to odoo backend server
  location / {
    # 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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  location @odoo {
    # 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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  location ~ ^/[^/]+(!db$)/static/.+$ {
      # root and try_files both depend on your addons paths
      root /opt/odoo;
      try_files /16.0/addons$uri /16.0/OCB$uri @odoo;
      expires 24h;
      add_header Content-Security-Policy $content_type_csp;
  }

  location /web/filestore {
      internal;
      alias /root/.local/share/Odoo;
  }


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

  # SSL parameters
  include snippets/self-signed-certificate.conf;
}

.it域名配置

map $http_upgrade $connection_upgrade {
  default upgrade;
  ''      close;
}

map $sent_http_content_type $content_type_csp {
    default "";
    ~image/ "default-src 'none'";
}


# http -> https
server {
    if ($host = www.mycompany.it) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  listen 80;
  listen [::]:80;
  server_name www.mycompany.it;
  rewrite ^(.*) https://$host$1 permanent;
}

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  listen 443 quic;
  listen [::]:443 quic;
  http2 on;

  server_name www.mycompany.it;

  proxy_read_timeout 720s;
  proxy_connect_timeout 720s;
  proxy_send_timeout 720s;

  # 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;
    proxy_set_header Host $host;
  }

  # Redirect requests to odoo backend server
  location / {
    # 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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  location @odoo {
    # 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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  location ~ ^/[^/]+(!db$)/static/.+$ {
      # root and try_files both depend on your addons paths
      root /opt/odoo;
      try_files /16.0/addons$uri /16.0/OCB$uri @odoo;
      expires 24h;
      add_header Content-Security-Policy $content_type_csp;
  }

  location /web/filestore {
      internal;
      alias /root/.local/share/Odoo;
  }


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

  # SSL parameters
  include snippets/self-signed-certificate.conf;
}

目标

实现单域名对应单语言:

  • www.mycompany.com - 固定对应英文
  • www.mycompany.it - 固定对应意大利语

已尝试方案

曾将proxy_pass http://odoo;修改为proxy_pass http://odoo/en;,但触发了无限循环问题,寻求解决办法。


解决方案

核心思路

直接修改proxy_pass路径会导致Odoo重定向回根路径,进而触发Nginx再次代理到带语言的路径,形成循环。正确的做法是通过设置Cookie强制指定语言,同时拦截Odoo的语言重定向,确保域名与语言绑定。

修改后的Nginx配置

1. .com域名(强制英文)

在server块的location /部分添加Cookie设置,并处理重定向:

server {
  # 保留原有其他配置(listen、ssl、日志等)

  # Redirect requests to odoo backend server
  location / {
    # 强制设置英文Cookie,优先级高于用户原有Cookie
    add_header Set-Cookie "frontend_lang=en_US; Path=/; Domain=mycompany.com; HttpOnly; Secure" always;
    # 拦截Odoo的语言重定向,将/en路径重写回根路径
    rewrite ^/en(/.*)?$ $1 break;

    # 保留原有代理头配置
    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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  # 保留原有其他location配置(websocket、@odoo、静态文件等)
}

2. .it域名(强制意大利语)

同理,在location /部分添加意大利语Cookie设置:

server {
  # 保留原有其他配置(listen、ssl、日志等)

  # Redirect requests to odoo backend server
  location / {
    # 强制设置意大利语Cookie
    add_header Set-Cookie "frontend_lang=it_IT; Path=/; Domain=mycompany.it; HttpOnly; Secure" always;
    # 拦截Odoo的语言重定向,将/it路径重写回根路径
    rewrite ^/it(/.*)?$ $1 break;

    # 保留原有代理头配置
    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;
    proxy_redirect off;
    proxy_pass http://odoo;
    proxy_set_header Host $host;
  }

  # 保留原有其他location配置(websocket、@odoo、静态文件等)
}

补充说明

  1. Cookie设置:always参数确保即使是重定向响应也会发送Cookie,强制覆盖用户端可能存在的旧语言Cookie。HttpOnly和Secure提升安全性,仅在HTTPS下生效。
  2. 重写规则:拦截Odoo自动生成的带语言后缀的重定向,避免用户访问www.mycompany.com/en时被重定向到根路径后又触发语言检测,确保URL始终保持根路径形式。
  3. 避免循环:通过Cookie直接指定语言,Odoo会根据Cookie值渲染对应语言页面,无需再通过URL路径传递语言参数,从根源上避免了循环问题。

验证步骤

  1. 重启Nginx服务:sudo systemctl restart nginx
  2. 访问www.mycompany.com,检查Cookie中frontend_lang值为en_US,页面显示英文
  3. 访问www.mycompany.it,检查Cookie中frontend_lang值为it_IT,页面显示意大利语
  4. 尝试手动访问www.mycompany.com/it,会被重写回根路径并显示英文,不会跳转到意大利语页面

内容的提问来源于stack exchange,提问作者KaMZaTa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 17:50:54