通过 socat 连接家庭服务器的 SSL 证书

通过 socat 连接家庭服务器的 SSL 证书

我在家里的 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 发送与使用的域匹配的证书。有两种方法可以解决此问题:

  1. 对两个域使用一个证书,安装在 pi 和主服务器上。无论客户端在查询中使用哪个域,证书都会匹配。
  2. 选择客户端期望的证书并发送。

选项 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>

相关内容