|
本帖最后由 tedaz 于 2024-12-26 16:50 编辑
看了kn69968的帖子DIY 家庭小主机 AIO (10)——将私服暴露到公网, 安全便利地回家及无缝网络服务,其中通过创建并启用授信证书,解决浏览器提示自建https服务器证书无效问题深深地吸引了我。
于是开始了下面的折腾。
特别感谢kn69968、elvba、jimmy203308的讨论、帮助和支持!
现况
- 家庭服务器宿主:Windows Server 2016 Data Center版。
- Hyper-V虚拟机:Ubuntu Server 22.04,ip=192.168.1.24,按照官方手册安装ownCloud,启用https,禁用http。
- 局域网通过 https://192.168.1.24 访问,提示https证书无效,但可以点击忽略风险,继续使用。
- 路由上将公网 7777 端口映射到 192.168.1.24 的 443 端口,公网通过 https://ted.ddns.net:7777 进行访问,同样会提示证书无效,但可以使用。
- 安卓版ownCloud app可以通过 https://ted.ddns.net:7777 添加并访问,添加时提示证书无效,但可以使用。
- 考虑到ddns服务器的不稳定性,实际上在路由器上绑定了多个不同服务商的ddns域名,当一个域名暂时挂掉时,可以继续使用其他域名正常访问ownCloud。多个域名均已经添加到ownCould的添加trusted_domains中了。
安卓版Moon+ Reader通过“Sync to cloud”的“Sync via WebDav”同步读书进度 和/或 电子书时,会因为证书无效,直接被Moon+ Reader拒绝,没有忽略风险的选项。这个问题困扰我多年,多次尝试过不同的解决方案,均为成功。
直到看到kn69968的帖子,开始再次尝试。
题外话
个人一直不倾向于使用“一键脚本”、“无敌汇总大全docker”等解决方案;而是倾向于使用命令逐步自己完成各项设置。
脚本主要是为了海量、多次部署减轻工作量;不一定真的可以让啥都不懂的电脑小白“一键升天”。
实际上,尝试过很多脚本、集成大包、docker等,都没有成功,而且出现的问题很难解决,因为看不明白脚本中到底写的是什么,给出的错误信息也不知道到底属于哪个软件、程序,想查官方手册都不知道从哪里入手。
我的需求
- 通过生成、启用有效的数字证书,解决https访问时证书无效的问题,达成安卓版Moon+ Reader通过“Sync to cloud”的“Sync via WebDav”同步读书进度 和/或 电子书。
- 添加一个新的有效数字证书的域名来访问ownCloud;同时保持目前路由器端口转发(正向代理)可以继续访问ownCloud。
- 在浏览器地址栏可以看到ownCloud的完整URL而不仅仅是域名(不需要重写URL)。
- 在访问域名时附带端口号。
- 所有服务器、功能、软件均分布在不同的虚拟机上,确保明白每个命令的原理、影响,方便远期维护、更新。
- 尽量不使用手机号码、微信才能注册的服务(比如阿里系列)。
- 不依赖公网VPS(中转对速度影响太大;与其中转,不如直接在公网VPS建立服务了)。
前提条件
- 家庭宽带需要有动态公网ipv4;不需要ipv4的80、443端口;不需要ipv6。
- 家庭服务器,可以开启多个虚拟机(方便测试和折腾)。
- ddns服务商支持添加TXT记录,以便在公网ipv4的80、443端口不可用的情况下,完成Let's Encrypt证书的申请。
- 不需要手机号码注册,不需要微信注册。
- 不需要公网服务器。
- 无需域名备案等流程。
- 有折腾的意愿和时间。
Let's Encrypt有两种验证方式
- 在本地服务器创建一个URL,然后Let's Encrypt通过访问https://ted.ddns.net/test-string的方式完成域名验证。因为这是Let's Encrypt发起的访问,所以无法自定义https的端口,也就是必然会使用默认的443端口访问。我之前就是在这个步骤卡了几年,一直没找到解决方案。
- 在ddns域名服务商那边设置,添加一个TXT记录,然后Let's Encrypt通过访问https://test-string.ted.ddns.net来完成域名验证。这样就不需要用到本地服务器的80、443端口了,因为仅用了域名解析,没有访问本地服务器。
| 优点 | 缺点 | 第一种验证方式 | 对ddns服务没有要求(不是所有ddns服务都可以创建TXT记录)。 | 需要本地服务器(公网ipv4)的80、443端口可用。 | 第二种验证方式 | 无需本地服务器(公网ipv4)的80、443端口(目前几乎所有家庭宽带的公网ipv4的80、443端口均已封闭)。 | 需要ddns服务支持创建TXT记录。 |
综上,如果ddns服务不支持创建TXT记录,同时公网ipv4也封闭了80、443端口,那就没戏了,放弃吧。或者根本就没有动态公网ipv4也可以放弃了(虽然依然可以用各种神奇的穿透、反代,但都不是本文的讨论范文了)。
实施:第一步 申请Let's Encrypt证书
新建一台Ubuntu 24.04虚拟机,使用root用户登录,运行命令安装certbot
运行certbot命令,开始申请证书。其中“--preferred-challenges dns”的意思是本地ownCloud服务器的80、443端口不可用(也就是家庭宽带的动态公网ipv4的80、443端口不可用),需要通过域名验证方式完成证书申请。
- certbot certonly --manual --preferred-challenges dns -d "ted.ddns.net"
复制代码
按照提示输入真实邮箱地址(邮箱用于后续证书更新,Let's Encrypt证书需要每90天更新一次)后,会提示
- Account registered.
- Requesting a certificate for ted.ddns.net
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Please deploy a DNS TXT record under the name:
- _acme-challenge.ted.ddns.net.
- with the following value:
- 1rd_7j4uhZDBY_iiQOheE2QvwSU7h47tVi-GoqRLCyk
- Before continuing, verify the TXT record has been deployed. Depending on the DNS
- provider, this may take some time, from a few seconds to multiple minutes. You can
- check if it has finished deploying with aid of online tools, such as the Google
- Admin Toolbox: https://toolbox.googleapps.com/apps/dig/#TXT/_acme-challenge.ted.ddns.net.
- Look for one or more bolded line(s) below the line ';ANSWER'. It should show the
- value(s) you've just added.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Press Enter to Continue
复制代码 这段话的主要意思是,到你的ddns服务商创建一个TXT记录,以便Let's Encrypt验证这个域名确实属于你:
Hostname = _acme-challenge.ted.ddns.net
Type = TXT
Data = 1rd_7j4uhZDBY_iiQOheE2QvwSU7h47tVi-GoqRLCyk
在ddns服务商那里创建好TXT记录后,可以用nslookup验证下TXT记录解析是否成功:
- nslookup _acme-challenge.ted.ddns.net
- 回显:
- Server: 127.0.0.53
- Address: 127.0.0.53#53
- Non-authoritative answer:
- Name: _acme-challenge.ted.ddns.net
- Address: 911.911.911.911
复制代码 TXT记录解析成功了。
在Let's Encrypt的脚本界面按回车继续,完成域名验证、证书创建成功。
证书在/etc/letsencrypt/live/ted.ddns.net文件夹中。
实施:第二步 更新ownCloud配置文件
修改ownCloud的配置文件/var/www/owncloud/config/config.php,添加trusted_domains。
不需要写http、https等前缀,也不需要写端口号。
- 'trusted_domains' =>
- array (
- 0 => 'localhost',
- 1 => '192.168.1.24',
- 2 => 'ted.facebook.net',
- 3 => 'ted.twitter.net',
- 4 => 'ted.youtube.net',
- 5 => 'ted.ddns.net',
- ),
复制代码 这样设置后,可以用本地ip地址和多个域名访问ownCloud,而且每个域名既可以用主路由上的端口映射的7777、6666等端口访问;也可以用Nginx反向代理的有授信证书的https访问端口8888、9999等。
重启apache2服务,使修改后的配置文件生效:
- systemctl restart apache2
复制代码
可以不用,但不能没有:保留多种访问方式,可以最大程度的提高灵活度。比如Nginx被玩崩了,依然可以用端口转发访问存在ownCloud上的《TCP/IP详解》、《用TCP/IP进行网际互联》、《TCP/IP指南》、《TCP/IP路由技术》 等书籍,学习网络知识,修复Nginx。
端口转发等安不安全不是最重要的,毕竟ownCloud上只是存了一些TCP/IP电子书,和Moon+Reader的读书进度,不怕泄露,不怕攻击。废了就重建,还能顺便复习Nginx教程。
ownCloud的配置文件中,不需要添加trusted_proxies。不需要更改overwrite.cli.url,我这里是
- 'overwrite.cli.url' => 'https://192.168.1.24/',
复制代码
重要:
- 在ownCloud已经部署正常的情况下,除了修改trusted_domains,绝对不要为了Nginx更改ownCloud的其他任何东西。
- 记住,只要在端口转发状态下ownCloud工作正常,在Nginx反向代理的情况就应该一切正常,就不需要改ownCloud。
- 要改的是Nginx。
千万不要用乱七八糟的正则表达式去重写URL等骚操作,那样也许可以暂时解决某些问题,但是ownCloud的功能和代码太复杂了,很可能有的页面、有的功能就不正常了。
特别的,当后期ownCloud版本升级后,可能需要新的URL重写规则,不是顶级高手,不要重写URL;不要乱改ownCloud的配置,确保未来ownCloud可以正常升级和使用。
实施:第三步 配置、运行Nginx
新建Windows虚拟机,ip=192.1681.2。
下载Windows版Nginx,解压缩到C:\。
编辑配置文件nginx-1.27.3\conf\nginx.conf
添加一个server块,注意端口不要冲突。
- server {
- listen 443 ssl; #Nginx监听443端口
- server_name ted.ddns.net; #ddns域名
- ssl_certificate fullchain.pem; #certbot生成的证书文件
- ssl_certificate_key privkey.pem; #certbot生成证书的key
- location / {
- proxy_pass https://192.168.1.24; # 指向内网ownCloud地址
- proxy_set_header Host $host:8888; # 传递请求的 Host
- proxy_set_header X-Real-IP $remote_addr; # 传递真实客户端 IP
- }
- }
复制代码 这里最重要的是proxy_set_header Host $host:8888,这个端口号非常重要,这是公网https访问时使用的端口号。这里不写端口,会导致Nginx跳转后的URL缺少端口号。
重要:不要用各种顶级高手的正则表达式overwrite URL。用最小化修改实现的功能往往是最全面最完整的。修改越多,可能埋的雷越多。
ownCloud的配置文件中,不需要添加trusted_proxies。不需要更改overwrite.cli.url,我这里是
- 'overwrite.cli.url' => 'https://192.168.1.24/',
复制代码
小结
至此,应该可以在公网用浏览器访问ownCloud了,且https的证书是Let's Encrypt的有效证书。
访问时的流程:
- 浏览器访问网址https://ted.ddns.net:8888;
- ddns服务将ted.ddns.net域名指向家庭宽带的公网动态ipv4;
- 主路由收到访问请求后,依照端口映射规则,将来自公网8888端口的请求转发至内网Nginx服务器(ip=192.168.1.2)的443端口;
- Nginx使用Let's Encrypt证书响应,并将请求转发至内网的ownCloud服务器(ip=192.168.1.24)的443端口;
- ownCloud服务器上的apache2提供服务。
关于证书自动更新
Let's Encrypt的证书有效期只有90天,需要定期更新。
手动更新是可以的,但是不方便。
目前用Ubuntu+lego+nginx搞定了证书自动更新:每天检查;证书到期前10天更新证书。
暂时dry run通过了,就看80天后自动更新的效果了。
等有时间写自动更新的部分。
|
|