为 Nextcloud 配置反向代理、DAV 发现与统一链接

为 Nextcloud 配置反向代理、DAV 发现与统一链接

Nextcloud 可以部署在反向代理之后。代理能够缓存图片、CSS、JavaScript 等静态资源,把 HTTPS 处理负载移到另一台服务器,或者在多台服务器之间进行负载均衡。

定义可信代理

为保证安全,必须明确指定 Nextcloud 信任哪些代理服务器。来自可信代理的连接会被特殊处理,以获取真正的客户端信息,供访问控制和日志使用。相关参数放在 config/config.php 中。

trusted_proxies 是一个数组,可包含 IPv4 地址、用 CIDR 表示的 IPv4 地址范围、IPv6 地址和用 CIDR 表示的 IPv6 地址范围。它规定了哪些服务器可以作为可信代理。这项配置用于防止客户端伪装;代理本身也必须像 Nextcloud 服务器一样受到保护。

反向代理可以通过 HTTP 请求头传递原始客户端 IP,Nextcloud 再从这些请求头中读取地址。默认使用事实上通用的 X-Forwarded-For,也可以通过 forwarded_for_headers 更改。该参数是 PHP 请求头查询键的数组,例如 X-Forwarded-For 对应 HTTP_X_FORWARDED_FOR。

配置错误可能让客户端伪造 Nextcloud 所看到的 IP,即使请求经过可信代理也一样。正确的请求头取决于实际使用的代理软件,不能只凭名字照搬。

覆盖自动识别的参数

在某些代理配置中,Nextcloud 对主机名、协议或 Web 根路径的自动识别会失败。这时可以在 config/config.php 中手动覆盖:

  • overwritehost:代理对外使用的主机名,也可以带端口。
  • overwriteprotocol:对外协议,取 http 或 https。
  • overwritewebroot:代理上通往 Nextcloud 目录的绝对 Web 路径。
  • overwritecondaddr:仅当远端地址匹配指定正则表达式时,应用覆盖参数。只对 HTTPS 使用反向 TLS 代理、而 HTTP 仍希望自动识别时,这个条件很有用。
  • overwrite.cli.url:命令行工具生成 URL 时使用的基础地址,例如通知区域可能使用该值。

参数为空或省略时保留自动识别。

服务发现

Nextcloud 在反向代理后运行时,CalDAV 或 CardDAV 的发现重定向可能无法按预期工作。原文建议由反向代理完成这些重定向。以下是不同代理的配置片段,需放在实际使用的软件及相应配置位置中。

Apache2

RewriteEngine On
RewriteRule ^/\.well-known/carddav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]
RewriteRule ^/\.well-known/caldav https://%{SERVER_NAME}/remote.php/dav/ [R=301,L]

Traefik 1

使用 Docker labels:

traefik.frontend.redirect.permanent: 'true'
traefik.frontend.redirect.regex: 'https://(.*)/.well-known/(?:card|cal)dav'
traefik.frontend.redirect.replacement: 'https://$$1/remote.php/dav'

使用 traefik.toml。下面先保留原文代码;其中 replacement 那一行缺少结束引号,不能直接作为有效 TOML 使用:

[frontends.frontend1.redirect]
  regex = "https://(.*)/.well-known/(?:card|cal)dav"
  replacement = "https://$1/remote.php/dav
  permanent = true

仅补齐结束引号后的语法修正版本如下。本地已使用 Python 的 TOML 解析器检查该片段的语法;没有启动 Traefik 或验证真实重定向。Traefik 1 是历史配置格式,请结合实际版本核对。

[frontends.frontend1.redirect]
  regex = "https://(.*)/.well-known/(?:card|cal)dav"
  replacement = "https://$1/remote.php/dav"
  permanent = true

Traefik 2

使用 Docker labels:

- "traefik.http.routers.nextcloud.middlewares=nextcloud_redirectregex@docker"
- "traefik.http.middlewares.nextcloud_redirectregex.redirectregex.permanent=true"
- "traefik.http.middlewares.nextcloud_redirectregex.redirectregex.regex=https://(.*)/.well-known/(?:card|cal)dav"
- "traefik.http.middlewares.nextcloud_redirectregex.redirectregex.replacement=https://$${1}/remote.php/dav"

使用 TOML 文件:

[http.middlewares]
  [http.middlewares.nextcloud-redirectregex.redirectRegex]
    permanent = true
    regex = "https://(.*)/.well-known/(?:card|cal)dav"
    replacement = "https://${1}/remote.php/dav"

HAProxy

acl url_discovery path /.well-known/caldav /.well-known/carddav
http-request redirect location /remote.php/dav/ code 301 if url_discovery

NGINX

如果 Nextcloud 本身使用 NGINX,又位于另一台 NGINX 反向代理之后,应当只把以下片段放进外层反向代理配置:

location /.well-known/carddav {
    return 301 $scheme://$host/remote.php/dav;
}

location /.well-known/caldav {
    return 301 $scheme://$host/remote.php/dav;
}

location ^~ /.well-known {
    return 301 $scheme://$host/index.php$uri;
}

使用 NGINX Proxy Manager 时,原文要求在代理主机的 Advanced Settings → Custom Nginx Configuration 中加入 proxy_hide_header Upgrade;,否则 iPad、iPhone 等移动设备可能收到“Connection Closed”错误。

Caddy

subdomain.example.com {
    redir /.well-known/carddav /remote.php/dav/ 301
    redir /.well-known/caldav /remote.php/dav/ 301

    reverse_proxy {$NEXTCLOUD_HOST:localhost}
}

Pomerium

- from: https://subdomain.example.com
  path: /.well-known/carddav
  redirect:
    path_redirect: /remote.php/dav/
- from: https://subdomain.example.com
  path: /.well-known/caldav
  redirect:
    path_redirect: /remote.php/dav/

示例

代理后以子目录提供 Nextcloud

假设 Nextcloud 对外地址是 https://example.com/nextcloud,反向代理地址是 10.0.0.1,并由代理终止 TLS。可在 config/config.php 中设置:

<?php
$CONFIG = array (
  'trusted_proxies'   => ['10.0.0.1'],
  'overwriteprotocol' => 'https',
  'overwritewebroot'  => '/nextcloud',
  'overwrite.cli.url' => 'https://example.com/nextcloud',
);

大多数配置不需要 overwritehost:Nextcloud 会从代理转发的 Host 请求头读取主机名。只有需要忽略请求中的主机名并强制使用指定名称时,才设置它。未设置或为空的参数继续自动识别。

通过多个域名访问,或按条件覆盖

如果 Nextcloud 同时能通过直连 HTTP 和代理 HTTPS 访问,或者多个代理提供不同的公开域名,可以用 overwritecondaddr 限定:只有来自特定代理 IP 的请求才应用覆盖值,其余请求仍自动识别。

下例只对 10.0.0.1 的请求应用覆盖参数,该代理对外提供 https://public.example.com:

<?php
$CONFIG = array (
  'trusted_proxies'   => ['10.0.0.1'],
  'overwritehost'     => 'public.example.com',
  'overwriteprotocol' => 'https',
  'overwritecondaddr' => '^10\.0\.0\.1$',
  'overwrite.cli.url' => 'https://public.example.com',
);

overwritecondaddr 是用于匹配代理远端地址的正则表达式。设置后,仅在远端地址匹配时才启用覆盖参数。它适用于同一实例既能直连又能经代理访问,或者不同代理使用不同主机名的情况。

多个可信域名与分享链接

trusted_domains 包含多个名称时,Nextcloud 会接受这些域名上的请求,并根据当前请求的主机名生成 URL。因此,分享、下载和通知链接可能反映当时使用的主机名。

例如,通过内部名称 cloud.local 复制的分享链接会包含内部名称;只认识公开名称 cloud.example.com 的其他网络用户无法访问它。

如果希望生成的所有链接始终使用一个规范的公开主机名,可以无条件设置 overwritehost 和 overwrite.cli.url:

<?php
$CONFIG = array (
  'trusted_domains'   => ['cloud.local', 'cloud.example.com'],
  'overwritehost'     => 'cloud.example.com',
  'overwriteprotocol' => 'https',
  'overwrite.cli.url' => 'https://cloud.example.com',
);

与前面的 overwritecondaddr 不同,这种设置不区分请求来源,会对每个请求应用覆盖值。如果实例在内网仍用另一个名称访问,但所有生成链接都要统一到公开地址,就适合采用这种方式。


原文:Reverse proxy,Nextcloud 35 Administration Manual,Nextcloud 文档贡献者。文档仓库声明采用 CC BY 3.0 Unported,参见许可说明。本页将正文译为中文,保留原文配置,并单独补齐 Traefik 1 TOML 示例缺失的引号。原文感谢 @ffried 提供 Apache2 示例,@pauvos 与 @mrtumnus 提供 Traefik 示例,@JeffMatson 提供 Pomerium 示例。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容