解决 Mastodon Docker 容器中 Nginx 重定向循环问题 (ERR_TOO_MANY_REDIRECTS)

如果你在使用 Unraid 或其他 Docker 环境部署 Mastodon,并通过 Cloudflare Tunnel (或其他将 HTTPS 流量转发为 HTTP 的代理) 访问时,可能会遇到经典的 ERR_TOO_MANY_REDIRECTS 错误。这通常是因为容器内部的 Nginx 与外部代理之间的协议识别不一致造成的无限重定向循环。

本文将深入分析这个问题,并提供一个详细的解决方案。

问题现象

你可能已经配置了 Cloudflare Tunnel (或其他反向代理) 来处理 SSL 证书和外部流量,并将流量转发到运行在 Docker 容器内的 Mastodon Nginx。然而,当你尝试访问你的 Mastodon 网站 (例如 https://your.domain.com) 时,浏览器却显示“重定向次数过多”的错误。

在 Mastodon Docker 容器的日志中,你可能会看到类似 Nginx 报告的 unknown "schemehttp_x_forwarded_proto" variable 错误,或者没有任何错误,但重定向循环依然存在。

问题根源分析

这个问题的核心在于协议识别的混淆

  1. 外部代理 (Cloudflare Tunnel) 的作用: Cloudflare Tunnel 会在 Cloudflare 边缘终止 HTTPS 连接。这意味着用户浏览器通过 HTTPS 访问 Cloudflare,然后 Cloudflare Tunnel 会将这些请求转换为 HTTP 并发送到你的 Docker 容器内部的 Nginx。
  2. 容器内部 Nginx 的默认行为: Mastodon Docker 容器 (特别是基于 LinuxServer.io 的镜像) 内部通常包含一个 Nginx 实例。
    • 这个 Nginx 可能默认配置成监听 80 端口 (HTTP) 和 443 端口 (HTTPS)。
    • 在处理 proxy_set_header X-Forwarded-Proto 头部时,如果使用了 $scheme 变量,Nginx 会根据它实际收到的协议来设置这个头部。当它从 Cloudflare Tunnel 收到 HTTP 请求时,$scheme 的值就是 http
  3. Mastodon 应用程序的响应: Mastodon 应用程序会检查 X-Forwarded-Proto 头部来判断原始请求是否通过 HTTPS。
    • 如果 Mastodon 收到的 X-Forwarded-Protohttp (即使原始用户访问的是 HTTPS),它会误以为这是一个不安全的 HTTP 请求。
    • 为了安全性,Mastodon 应用程序会尝试将用户重定向到 HTTPS
  4. 重定向循环的形成:
    • 用户 HTTPS 访问 -> Cloudflare -> Cloudflare Tunnel -> Docker Nginx (收到 HTTP)
    • Docker Nginx 将 X-Forwarded-Proto: http 发送给 Mastodon 后端
    • Mastodon 收到 X-Forwarded-Proto: http,尝试 302/301 重定向到 HTTPS
    • 重定向响应回到 Docker Nginx -> Cloudflare Tunnel -> Cloudflare -> 用户浏览器
    • 用户浏览器再次尝试 HTTPS 访问 (响应了重定向) -> 重复第一步,形成无限循环。

之前可能遇到的 Nginx 错误 unknown "schemehttp_x_forwarded_proto" variable 则是 Nginx 配置文件中变量拼写错误导致 Nginx 无法启动的问题。

解决方案

解决此问题的关键是确保 Nginx 正确地将原始请求协议 (HTTPS) 传递给 Mastodon 应用程序,即使 Nginx 实际收到的是 HTTP 请求。我们需要利用 Cloudflare 在转发请求时添加的 X-Forwarded-Proto 头部。

步骤 1: 进入 Mastodon Docker 容器的 Shell

首先,你需要进入你的 Mastodon Docker 容器的命令行界面。

docker exec -it <mastodon_容器名称或ID> bash

提示: 你可以通过 docker ps 命令查看正在运行的容器及其名称或 ID。

步骤 2: 定位并备份 Nginx 配置文件

Mastodon Docker 容器 (特别是 LinuxServer.io 的镜像) 的 Nginx 配置文件通常位于 /config/nginx/site-confs/default.conf

  1. 确认文件存在:Bashls /config/nginx/site-confs/default.conf 如果你不确定哪个文件包含 Nginx 配置,可以通过 grep 命令来查找监听 80 端口的 server 块:Bashgrep -r "listen 80" /config/nginx/site-confs/ 输出通常会指向 default.conf
  2. 备份配置文件 (强烈推荐): 在进行任何修改之前,务必备份原始文件,以防万一。Bashcp /config/nginx/site-confs/default.conf /config/nginx/site-confs/default.conf.bak

3. 编辑 Nginx 配置文件

使用 vinano (如果容器内有安装) 编辑 /config/nginx/site-confs/default.conf 文件:

vi /config/nginx/site-confs/default.conf

在文件中,找到所有包含 proxy_set_header X-Forwarded-Proto 的行。这通常出现在 location @proxylocation ^~ /api/v1/streaming 块中。

你需要将这两行 (或其他任何包含 X-Forwarded-Proto $scheme; 的行) 从:

proxy_set_header X-Forwarded-Proto $scheme;

修改为:

proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

正确修改后的示例片段如下:

location ^~ /api/v1/streaming {
    proxy_set_header Host $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 $http_x_forwarded_proto; # <-- 修正这里
    proxy_set_header Proxy "";

    proxy_pass http://streaming;
    proxy_buffering off;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    tcp_nodelay on;
}

location @proxy {
    proxy_set_header Host $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 $http_x_forwarded_proto; # <-- 修正这里
    proxy_set_header Proxy "";
    proxy_pass_header Server;

    proxy_pass http://backend;
    proxy_buffering on;
    proxy_redirect off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;

    proxy_cache CACHE;
    proxy_cache_valid 200 7d;
    proxy_cache_valid 410 24h;
    proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
    add_header X-Cached $upstream_cache_status;

    tcp_nodelay on;
}

解释:

  • $scheme 变量表示 Nginx 实际接收到的协议 (在这个场景中是 HTTP)。
  • $http_x_forwarded_proto 变量则捕获了上游代理 (Cloudflare) 传递过来的原始协议 (也就是 HTTPS)。通过使用这个变量,我们确保 Mastodon 应用程序总是知道用户最初是通过 HTTPS 访问的,从而避免了不必要的重定向。

4. 保存并退出

vi 中,输入 :wq 然后按回车保存并退出。

5. 重启 Mastodon Docker 容器

退出容器的 Shell,然后从你的 Docker 管理界面 (如 Unraid UI) 或通过命令行重启 Mastodon 容器。

docker restart <mastodon_容器名称或ID>

6. 清除浏览器缓存

重启容器后,务必清除你的浏览器缓存和 Cookie,然后尝试在无痕模式/隐私模式下访问你的 Mastodon 网站。这可以确保你不会受到旧的重定向缓存影响。

避免未来再次出现问题

因为您修改的配置文件 (/config/nginx/site-confs/default.conf) 位于 /config 目录下,而这个目录通常在 Docker 容器中是通过 卷 (Volume) 挂载到宿主机的。这意味着您的修改是持久化的。在正常的容器升级中,这个文件会保持不变,所以再次遇到相同问题的可能性大大降低。

USDT Icon
需支付 0.2 USDT 解锁内容

不过,作为最佳实践,下次升级 Docker 容器前,可以快速查看 Mastodon 容器或其 Nginx 基础镜像的更新日志 (Changelog)。如果日志中提到 Nginx 配置文件的重大修改,你可以稍微留意一下,以防需要重新检查你的设置。

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注

目录