Split Dns 内网外分别访问 同一个HTTPS服务

small parking
Table of Contents

内外兼修:如何安全地为你的内网服务配置 HTTPS,并实现内外网分别访问

前言

大家部署内网服务的或多或少都有根据用户位置分流的需求。本文将介绍如何使用 Nginx 和 certbot,为你的内网服务配置 HTTPS,并实现内网直接访问内网服务,公网访问公网服务的内外网分离访问模式

我们将以 Gotify 为例,演示如何配置,从而确保内网访问速度和安全性,同时不影响公网用户的访问。

背景

假设你已经:

  • 拥有一个公网域名 gotify.smallparking.eu.org
  • 在内网部署了 Gotify 服务 (http)。
  • 在公网 VPS 上部署了 nginx,并通过 certbot 获取了该域名的 SSL 证书,公网用户通过域名访问该服务 (https)。
  • 现在,你希望在内网也能就近访问gotify服务,并使用 HTTPS 安全地访问它。
  • 核心目标: 内网用户通过 gotify.smallparking.eu.org 访问内网 Gotify 服务(https),公网用户也仍能通过gotify.smallparking.eu.org访问公共的服务(https)。

步骤

  1. 准备工作

    • 确保你已经在内网服务器上安装了 Nginx。
    • 确保你已经安装了 Certbot (或 Lego)。
    • 关键:配置内网 DNS 服务器,将 gotify.smallparking.eu.org 解析到你的内网 Gotify 服务器的 IP 地址。 这是实现内外网分离访问的关键。(可以使用nslookup或dig验证dns解析情况)
    • 确认你的内网服务器可以访问公网(用于certbot 的 DNS 验证)。
  2. 申请内网 SSL 证书

    在你的内网机器上,使用 Certbot (或 Lego) 申请 另一个 SSL 证书。 这是与公网证书隔离的关键一步。 Lego 命令示例:

    export CLOUDFLARE_DNS_API_TOKEN="你的cloudflare api token"
    sudo -E lego --email="[email protected]" --dns cloudflare --domains="gotify.smallparking.eu.org" --path="/etc/lego" run
    
    • --email: 你的邮箱地址。
    • --dns cloudflare: 使用 Cloudflare API 进行 DNS 验证。 需要配置 Cloudflare API 密钥。
    • --domains: 你要申请 SSL 证书的域名。
    • --path: 证书存储路径。

    重点: 由于内网服务器通常无法直接通过 HTTP 验证,我们使用 DNS 验证。Certbot/Lego 会在你的 DNS 服务商(如 Cloudflare)上创建 TXT 记录来验证你对域名的所有权。

  3. 配置 Nginx

    在你的内网 Nginx 配置文件中,配置 HTTPS 相关信息,指向刚刚申请的内网证书。 例如:

    server {
        listen 443 ssl;
        server_name gotify.smallparking.eu.org;
    
        ssl_certificate /etc/lego/certificates/gotify.smallparking.eu.org.crt; # 内网证书路径
        ssl_certificate_key /etc/lego/certificates/gotify.smallparking.eu.org.key; # 内网私钥路径
    
        # 其他 Gotify 相关配置...
        location / {
            proxy_pass http://gotify;
            proxy_http_version 1.1;
            proxy_buffering off;
    
            # Ensuring it can use websockets
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            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;
            proxy_redirect http:// $scheme://;
    
            # The proxy must preserve the host because gotify verifies the host with the origin
            # for WebSocket connections
            proxy_set_header Host $http_host;
    
            # These sets the timeout so that the websocket can stay alive
            proxy_connect_timeout 7m;
            proxy_send_timeout 7m;
            proxy_read_timeout 7m;
            access_log logs/gotify.smallparking.eu.org-access.log;
            error_log logs/gotify.smallparking.eu.org-error.log info;
        }
    }
    
    upstream gotify {
    # Set the port to the one you are using in gotify
    server 192.168.31.175:8114;
    }
    
    map $http_upgrade $connection_upgrade {
        default upgrade;
        '' close;
    }    
    
    • ssl_certificate: 内网 SSL 证书的路径。
    • ssl_certificate_key: 内网 SSL 私钥的路径。
  4. 重启 Nginx

    配置完成后,重启内网 Nginx,使配置生效:

    sudo nginx -s reload
    
  5. 验证

    • 内网验证: 在你的内网机器上,使用 curl 命令验证 HTTPS 连接是否正常。

      curl -v https://gotify.smallparking.eu.org
      

      如果 curl 命令能够成功建立 HTTPS 连接,并且返回内网 Gotify 服务的页面,域名解析到了内网ip,并且证书是内网证书,则说明配置成功。

      结果应该如下:

      ❯ curl -v https://gotify.smallparking.eu.org
      * Uses proxy env variable no_proxy == '127.0.0.1,sf3-cn.feishucdn.com'
      * Host gotify.smallparking.eu.org:443 was resolved.
      * IPv6: (none)
      * IPv4: 192.168.31.175                    #解析到了内网ip
      *   Trying 192.168.31.175:443...
      * ALPN: curl offers h2,http/1.1
      ... ...
      < HTTP/1.1 200 OK                         #服务正常
      
    • 公网验证: 在公网环境下(例如,使用移动网络),通过浏览器访问 https://gotify.smallparking.eu.org, 确保仍然访问的是公网 VPS 上的 Gotify 服务,域名解析到了公网ip,并且显示的是公网证书

  6. 确认一下dns

    dig gotify.smallparking.eu.org
    
    ; <<>> DiG 9.20.9 <<>> gotify.smallparking.eu.org
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 19915
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
    
    ;; QUESTION SECTION:
    ;gotify.smallparking.eu.org.	IN	A
    
    ;; ANSWER SECTION:
    gotify.smallparking.eu.org. 0	IN	A	192.168.31.175 # 这是我的内网服务的ip
    
    ;; Query time: 2 msec
    ;; SERVER: 192.168.31.1#53(192.168.31.1) (UDP)
    ;; WHEN: Sat May 24 19:58:46 CST 2025
    ;; MSG SIZE  rcvd: 86
    
    dig gotify.smallparking.eu.org @223.5.5.5
    
    ; <<>> DiG 9.20.9 <<>> gotify.smallparking.eu.org @223.5.5.5
    ;; global options: +cmd
    ;; Got answer:
    ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25318
    ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
    
    ;; OPT PSEUDOSECTION:
    ; EDNS: version: 0, flags:; udp: 1232
    ;; QUESTION SECTION:
    ;gotify.smallparking.eu.org.	IN	A
    
    ;; ANSWER SECTION:
    gotify.smallparking.eu.org. 1	IN	A	142.171.xxx.xxx # 这是我的公网服务的ip
    
    ;; Query time: 5 msec
    ;; SERVER: 223.5.5.5#53(223.5.5.5) (UDP)
    ;; WHEN: Sat May 24 19:59:23 CST 2025
    ;; MSG SIZE  rcvd: 71
    

遇到的问题与解决方案

  • 问题: 即使 DNS 解析仍然指向公网 IP,内网证书仍然申请成功了。

    • 解决方案: certbot 使用权威 DNS 服务器进行 DNS 挑战验证。 Certbot/Lego 通过 DNS API 在权威 DNS 服务器上添加 TXT 记录完成验证。
  • 问题: 内网访问总是访问公网服务。

    • 解决方案: 这是因为内网 DNS 没有正确配置。 确保你的内网 DNS 服务器将 gotify.smallparking.eu.org 正确解析到你的内网 Gotify 服务器的 IP 地址。

总结

本文详细介绍了如何在内网部署 HTTPS,并实现内外网分别访问不同服务的场景。 核心在于:

  1. 独立的内网证书: 保证内外网证书隔离,提高安全性。
  2. 正确的 DNS 配置: 这是实现内外网分离访问的关键。内网 DNS 解析指向内网 IP,公网 DNS 解析指向公网 IP。

通过合理的配置,你可以在享受 HTTPS 安全性的同时,优化内网访问速度,并且保证内外网服务互不干扰。

希望本文对你有所帮助! 如果你有任何问题,欢迎留言讨论。