通过HTTPS和Nginx管理RabbitMQ

11

我正试图使用nginx通过HTTPS/SSL访问RabbitMQ接口,但是我无法确定我缺少了什么。

以下是我的rabbitmq.conf文件:

[
  {ssl, [{versions, ['tlsv1.2', 'tlsv1.1']}]},
  {rabbit, [
      {reverse_dns_lookups, true},
      {hipe_compile, true},
      {tcp_listeners, [5672]},
      {ssl_listeners, [5671]},
      {ssl_options, [
        {cacertfile, "/etc/ssl/certs/CA.pem"},
        {certfile,   "/etc/nginx/ssl/my_domain.crt"},
        {keyfile,    "/etc/nginx/ssl/my_domain.key"},
        {versions, ['tlsv1.2', 'tlsv1.1']}
      ]}
    ]
  },
  {rabbitmq_management, [
    {listener, [
      {port, 15671},
      {ssl,  true},
      {ssl_opts, [
        {cacertfile, "/etc/ssl/certs/CA.pem"},
        {certfile,   "/etc/nginx/ssl/my_domain.crt"},
        {keyfile,    "/etc/nginx/ssl/my_domain.key"},
        {versions, ['tlsv1.2', 'tlsv1.1']}
      ]}
    ]}
  ]}
].

当我重启rabbitmq-server时,一切都正常。

我的nginx文件看起来像这样:

location /rabbitmq/ {
        if ($request_uri ~* "/rabbitmq/(.*)") {
                proxy_pass https://example.com:15671/$1;
        }
}

现在,我猜测ngnix配置有些问题,无法解析HTTPS网址,因为我尝试浏览时出现504超时错误:

https://example.com/rabbitmq/

显然,这不是正确的FQDN,但SSL证书在没有/rabbitmq/的情况下正常工作

有人能否通过FQDN和HTTPS在外部连接上使用RabbitMQ管理Web界面?

我需要在nginx配置中创建一个新的“服务器”块来专门处理15671端口吗?

任何帮助都将不胜感激!

6个回答

31

我最终回到默认的rabbitmq.config文件,然后根据另一个现在找不到的stackoverflow答案,修改了我的nginx配置块为以下内容。

    location ~* /rabbitmq/api/(.*?)/(.*) {
        proxy_pass http://127.0.0.1:15672/api/$1/%2F/$2?$query_string;
        proxy_buffering                    off;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location ~* /rabbitmq/(.*) {
        rewrite ^/rabbitmq/(.*)$ /$1 break;
        proxy_pass http://127.0.0.1:15672;
        proxy_buffering                    off;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

另外,我的浏览器对JS文件进行了缓存,导致出现问题,我已经禁用了它。

我将尝试逐步重新启用SSL,但现在示例URL已经可以正常工作:

https://example.com/rabbitmq/

这让我有了很大的进展,但是我从js文件中得到了一堆“无法读取未定义的属性'length'”错误,并且我尝试过禁用和清除缓存...你是否找到了JS文件的核心问题以及如何解决它? - scnerd
1
我从nginx缓存中删除了.js扩展名。 - Dario Zadro
2
你在这里为我节省了大量的时间。我只是将目标修改为防火墙后面的另一台服务器,它完美地工作了。只需记得在浏览器中在URL末尾添加“/”。 - David Welborn
太棒了David,很高兴能帮到你! - Dario Zadro
1
谢谢Dario。它适用于一些API,如queueexchange。但对于不需要%2F作为vhost的user API则无效。 - leoleozhu
显示剩余2条评论

22

我尝试了以下的nginx.conf文件

    location /rabbitmq/ {
        proxy_pass http://rabbitmq/;
        proxy_buffering                    off;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

然而,我无法获取有关队列或交换机的详细信息。我的API调用返回404错误。 而且URL中有一个%2F,它是URL编码的/。
我们需要保留API URL中的%2F并将其传递给RabbitMQ。
以下链接描述了如何保留编码的URL部分并进行重写。 Nginx pass_proxy subdirectory without url decoding 所以我的解决方案是:
    location /rabbitmq/api/ {
        rewrite ^ $request_uri;
        rewrite ^/rabbitmq/api/(.*) /api/$1 break;
        return 400;
        proxy_pass http://rabbitmq$uri;
        proxy_buffering                    off;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /rabbitmq/ {
        proxy_pass http://rabbitmq/;
        proxy_buffering                    off;
        proxy_set_header Host              $http_host;
        proxy_set_header X-Real-IP         $remote_addr;
        proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

1
太棒了,我尝试了5个变体,但这一个成功了。 - JerMah
这是最佳解决方案。 - Erik Bors
另一个防止URL解码的解决方案是使用$request_uri:location ^~ /rabbitmq/ { if ($request_uri ~* "/rabbitmq/(.*)") { proxy_pass http://rabbitmq_server/$1; }} - Mikhail Shcheglov
非常感谢您的解决方案,我一直在错误的方式下尝试修复它(单个重写!),这个技巧让它起作用了! - N Dorigatti

8

对我来说这个方法很有效

location /rabbitmq {
  proxy_pass http://localhost:15672/;
  rewrite ^/rabbitmq/(.*)$ /$1 break;
}

我不需要使用其他指令。


1
这个答案再次证明了复制大量配置有时是危险的。这个答案结束了我两天的调试和寻找答案。谢谢。 - Rafik Farhad

2
如果有人正在寻找Apache(2.4)的解决方案:
<VirtualHost *:443>
        ServerName              rabbitmq.your-domain.com
        AllowEncodedSlashes     NoDecode 
        ... // rest of the settings

        <Location "/">
          Require all granted
          
          ProxyPass         http://localhost:15672/
          ProxyPassReverse  http://localhost:15672/
        </Location>
        <Location "/api">
          Require all granted

          ProxyPass         http://localhost:15672/api nocanon
        </Location>
</VirtualHost>

实际上,有两个元素非常重要:

  1. 在VirtualHost级别上设置“AllowEncodedSlashes NoDecode”
  2. 在"/api"位置上的ProxyPass中使用'nocanon'参数

2

这个方法对我有效,而且我不需要设置其他头部信息。这是对@user3142747答案的一个变体:

location /rabbitmq/ {
    # Strip off the "/rabbitmq" prefix
    rewrite  ^/rabbitmq/(.*) /$1 break;

    # Do NOT suffix proxy_pass path with a trailing "/". This allows NGINX to pass the client request completely unchanged.
    #    - see http://mailman.nginx.org/pipermail/nginx/2009-November/016577.html
    proxy_pass $scheme://localhost:15672;
}

0
我知道可能有点晚了,但是RabbitMQ有一个子路径配置,你可以很容易地使用Path Prefix进行设置。
这是一个使用Docker Compose在Nginx代理后面暴露RabbitMQ的示例:
version: "3"
services:
  rabbitmq:
    hostname: 'rmq'
    image: rabbitmq:management
    container_name: 'rmq'
    restart: always
    environment:
      - RABBITMQ_DEFAULT_USER=rmq-usr
      - RABBITMQ_DEFAULT_PASS=burFPso0ULwPMp_w3lkg4QT6-a2H6
    ports:
      - "5672:5672"
      - "127.0.0.1:15672:15672"
    volumes:
      - ./data:/var/lib/rabbitmq/
      - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf

rabbitmq.conf文件:

management.path_prefix = /rmq

在Nginx的server.conf块中:
upstream rmq {
  server 127.0.0.1:15672 fail_timeout=0;
}
server {
  listen 443 ssl http2;
  server_name example.com;
  error_page 497 https://example.com$request_uri;
  ssl_certificate /etc/ssl/certs/example.pem;
  ssl_certificate_key /etc/ssl/private/example.key;
  location /rmq {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $http_host;
    proxy_intercept_errors on;
    proxy_buffering off;
    proxy_redirect off;
    proxy_pass http://rmq;
    allow my.trusted.ip.addresses1;
    allow my.trusted.ip.addresses2;
    deny all;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接