带有docker容器变量名的Nginx反向代理返回错误文件

带有docker容器变量名的Nginx反向代理返回错误文件

我读了很多书,也尝试了很多方法,但最终还是没有奏效。希望你能帮助我。

以下是我的设置:

我有一个包含 phpmyadmin 容器的 Docker-compose 文件。我的问题不仅限于 phpmyadmin,这只是一个很好的例子。在 docker-file 下方(重要部分)。如您所见,我希望 phpmyadmin 在https://www.example.com/phpmyadmin/。我认为我的设置会容易得多,如果我使用https://phpmyadmin.example.com/(子域而不是子路径,但这不是我想要的。)phpmyadmin 容器本身运行良好。

phpmyadmin:
  image: phpmyadmin/phpmyadmin:latest
  container_name: k3633970_phpmyadmin
  restart: always
  environment:
    MYSQL_ROOT_PASSWORD: xxx
    PMA_HOST: xxx
    PMA_ABSOLUTE_URI: https://www.example.com/phpmyadmin/
  networks:
   - frontproxy_default
   - backend

然后,我有第二个 docker-compose 文件来启动 Nginx。这里没什么特别的:

nginx:
  image: nginx:alpine
  restart: unless-stopped
  volumes:
    - ./data/nginx:/etc/nginx/conf.d
  ports:
    - "80:80"
    - "443:443"
  networks:
    - frontproxy_default

第三,我的 vHost 有一个 Nginx 配置文件。我尝试将所有对 /phpmyadmin/ 的请求代理到 phpmyadmin 容器,将其他所有“/”请求代理到运行 apache+php 的另一个容器。如下所示,我对 phpmyadmin 容器进行了代理传递。当我使用 docker 容器名称时,一切都正常proxy_pass http://k3633970_phpmyadmin/;(参见注释部分)。

但是当我使用类似这样的变量时,proxy_pass $target;它就不再起作用了。(我描述相关问题是为了供我和其他人将来参考,所以这篇文章有点长)。发生的事情是,phpmyadmin 的起始页被加载,其中包括一些 JS/CSS 文件,如“js/phpmyadmin.js”或“css/phpmyadmin.css”。Web 浏览器加载了这些文件,但 Nginx 反向代理并没有提供 CSS/JS 文件,而是再次提供了起始页。浏览器显示警告,由于错误的 mime 类型,它无法包含 CSS/JS 文件,因为起始页是以“text/html”的形式提供的。这首先让我找到了错误的踪迹,即 mime 类型是错误的,而实际上 mime 类型是正确的,但传递了错误的文件。

你明白我的意思吗?我试着再解释一遍:

我正在加载 www.example.com/phpmyadmin --> 返回带有 mime 类型 text/html 的 phpmyadmin html 起始页(这是正确的)。此起始页包括 www.example.com/phpmyadmin/js/phpmyadmin.js 和 www.example.com/phpmyadmin/css/phpmyadmin.css,但返回的内容如下:www.example.com/phpmyadmin/js/phpmyadmin.js --> phpmyadmin html首页返回 mime 类型为 text/html。www.example.com/phpmyadmin/css/phpmyadmin.css --> phpmyadmin html首页返回 mime 类型 text/html。

这是我的 nginx 配置文件。

server {
    listen 443 ssl;
    server_name www.example.com;
    server_tokens off;
    ssl_certificate /etc/letsencrypt/live/www.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;


   location /phpmyadmin/ {
        resolver 127.0.0.11 valid=30s;
        set $target http://k3633970_phpmyadmin/; #Notice the trailing slash!
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass $target;
    }

# This works, without variables, but this is not what I want
#   location /phpmyadmin/ {
#        resolver 127.0.0.11 valid=30s;
#        set $upstreamx k3633970_phpmyadmin;
#        proxy_set_header Host $host;
#        proxy_set_header X-Real-IP $remote_addr;
#        proxy_pass http://k3633970_phpmyadmin/;
#         gzip  on;
#    }

    location / {
        resolver 127.0.0.11 valid=30s;
        set $upstream k3633970_vhost_1000303;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_pass http://$upstream:80;
    }
}

原因如下,根据 Nginx 文档所述:

如果 proxy_pass 指令指定了 URI,那么当请求传递给服务器时,规范化请求 URI 中与位置匹配的部分将被指令中指定的 URI 替换。

好的,明白了。但是我现在该如何解决这个问题呢?

我尝试了能想到的所有组合set $target http://k3633970_phpmyadmin$uri; set $target http://k3633970_phpmyadmin$request_uri; set $target http://k3633970_phpmyadmin/$uri;等等。但没有找到可行的组合。

请帮帮我,我被困住了——谢谢!

最后说明:为什么我需要代理传递中的变量?全部原因是:我有 10 个 docker-compose 文件,其中包含 10 个 wordpress 堆栈,每个堆栈有 3 个容器(apache+php / mariabdb / phpmyadmin)和一个 nginx 反向代理。如果我使用 docker 主机名,则所有 10 个 docker-compose 堆栈必须启动并运行在我启动 nginx 之前。这是不可能的,有时一两个堆栈会因为测试/维护而关闭。使用变量的方法允许在 10 个 docker 堆栈中只有 8 个启动并运行时启动 nginx。

谢谢你!

答案1

您的 nginx 服务必须使用“服务名称”而不是“容器名称”来解析 phpmyadmin 容器 ip。

此外,当您将请求代理到 phpmyadmin 容器时,您必须在 URL 中保留 /phpmyadmin 路径,如果您在末尾添加斜杠,它会删除该部分,因此您不能在末尾添加斜杠。或者您也可以使用正则表达式解析重建完整 URL。

因此这样的事情应该可行:

location ~* ^/phpmyadmin/(.*)$ {
  set $query $1;
  set $phpmyadmin phpmyadmin; # Service name in docker-compose file
  proxy_pass http://$phpmyadmin/phpmyadmin/$query$is_args$args; # Rebuild the URL
}

答案2

在@jonathan-rioux 的帮助下,这是现在的工作配置:

location ~* ^/phpmyadmin/(.*)$ {
    resolver 127.0.0.11 valid=30s;
    set $query $1;
    set $target http://k3633970_phpmyadmin/$query$is_args$args;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_pass $target;
}

谢谢你!

相关内容