我在家里的 Raspberry Pi 上运行 Nextcloud。它在 DynDNS 提供商 spDYN.de 上的主机名上更新其 IPv6 地址。但是,由于我的提供商仅提供 IPv6 连接(使用 DS-Lite 连接 IPv4),我只能从其他 IPv6 连接直接访问主机名,并且我必须使用 IPv4-IPv6 postmapper 从 IPv4 网络连接到它。
这没什么大不了的,因为我的网站托管在同时具有 IPv6 和 IPv4 连接的服务器上,所以我根据以下说明使用了 socat:本教程在托管我网站的服务器上设置端口映射器,将特定端口从我的网站域路由到动态 DNS 主机名上的端口 443。这很完美,但它会给 SSL 证书带来问题:
在 RasPi 上,我使用 certbot 为动态 DNS 主机名创建了一个“Let's encrypt”证书,该证书运行正常,连接显示为安全。此外,在我的 Web 服务器上,我为用于端口映射器的域创建了一个类似的证书,该证书本身可以正常工作。但是,当我使用特定的转发端口访问域以访问 RasPi 时,浏览器继续显示包含我的域的 URL,但它会从 RasPi 收到为动态 DNS 主机名颁发的证书。因此,安全检查当然会失败,因为证书是为“错误”的域颁发的。我已经尝试在我的 RasPi 上为我的域颁发证书,但它失败了,并告诉我我“未经授权”。
我该如何解决这个问题?我应该在哪里设置哪种证书?
答案1
为了避免证书错误,您需要 pi 发送与使用的域匹配的证书。有两种方法可以解决此问题:
- 对两个域使用一个证书,安装在 pi 和主服务器上。无论客户端在查询中使用哪个域,证书都会匹配。
- 选择客户端期望的证书并发送。
选项 1 更简单,也是常见的做法。查看 google.com 的证书!pi 和主服务器都将安装相同的证书(针对两个域)。为了从 Let's Encrypt 获取这样的证书,您需要主服务器也为 pi 的动态域运行一个网站,并使用一certbot 命令可同时验证对两个域的控制。dyndns 名称的主服务器站点不需要托管来自 pi 的内容 - 它只是在那里,以便 Let's Encrypt 可以验证您是否控制该站点(您甚至可以在续订之间关闭该站点)。
此示例 Certbot 命令(在主 Web 服务器上运行):
letsencrypt certonly --webroot --csr request.csr -w /http/pisite/www -d mypi.spdyn.de -w /http/mainwebsite/www -d maindomain.de
使用request.csr
任一域作为 CN 并且在 SAN 字段中包含两个域,/http/pisite/www
指的是您将为当前服务器上绑定到 pi 的动态名称的另一个网站创建的本地目录,并且/http/mainwebsite/www
是您主网站的现有目录。
选项 2 更复杂,但会产生“更干净”的结果:客户端获得与他们输入的域匹配的证书。在 Raspberry Pi 上,使用流模块(或等效模块)运行 nginx,当打开 TLS 连接时:检查 SNI 字段(不接受 TLS 连接),并根据其中包含的域,选择将连接转发到哪个上游。这使您可以选择如何处理转发到 Raspberry Pi 的外部端口上对主域发出的请求。您可以将它们发送到主 Web 服务器,就像它们是在正确的端口上发出的一样,您可以将它们发送到 pi 上的其他端口(即 Nextcloud 或其他任何端口),您可以使用相同的 nginx 实例终止它们并显示您喜欢的任何页面,或者只是关闭连接。选择权在您手中。
以下是此方法的示例配置:
stream/sni-switch.conf
# Listen on 443, and on new connection:
# if the SNI is mapped herein, handle it on this Nginx
# else, forward the whole session to 192.168.1.80:443 (TCP passthrough, no decryption)
upstream mainwebserver {
server 192.168.1.80:443;
}
upstream local_https {
server 127.0.0.1:1443;
}
map $ssl_preread_server_name $name {
default mainwebserver;
pisite.spdyn.de local_https;
}
server {
listen 443;
ssl_preread on;
proxy_pass $name;
}
并且在nginx.conf
load_module /usr/lib/nginx/modules/ngx_stream_module.so;
stream {
include /etc/nginx/stream/sni-switch.conf;
}
...
要使用 Apache 执行此操作,请参阅这. 示例配置可能如下所示:
<VirtualHost *:*>
ProxyPreserveHost On
ProxyPass "/" "http://192.168.1.80/"
ProxyPassReverse "/" "http://192.168.1.80/"
ServerName maindomain.de
</VirtualHost>