本文参加「自力更生」征文活动;

前言

在互联网上快乐地裸奔了一段时间之后,一张bing搜索的截图让我意识到,原来将本地服务暴露到外网不只是方便自己,还方便了他人随意登门探访。部署一个ssl证书,不让自己的数据在互联网世界明文传输,尽管也可能只是心里安慰,但也是很有必要的。

大部分人的选择应该是NPM(Nginx Proxy Manager),有着对像我这种小白友好的WEB UI,但是不知为何我使用时频频出错,无奈放弃。一番搜寻之下,发现了由LinuxServer.io团队开发和维护的SWAG(Secure Web Application Gateway),除了进行SSL证书的全自动注册与更新之外,还有很多丰富的功能,比如ldap域控验证、fail2ban等。本篇文章只主要讲述其中的SSL部署功能。

安装SWAG

准备条件

运行swag的前置条件:拥有一个属于自己的域名,公网IP,以及能够运行Docker的环境。

域名相对比较好解决,国内的腾讯云(dnspod)、阿里云,国外的namesilo等都可以以低至个位数的价格购买到一年的域名。公网IP则取决于你家的宽带运营商,有需要可以打电话询问。

swag需要通过docker进行部署,如果有对docker还不熟悉的读者,可以参阅别的文章,例如站内的这篇,这里不做赘述,只是推荐使用linux,在windows上使用docker略显麻烦。

docker部署

如果你想在后面配置的时候通过填写docker容器名而不是IP+端口号的形式去访问到其他容器,那么需要,需要首先先使用 docker network create netname 创建自定义桥接网络,让后保证这些容器都与swag在这个netname网络中,后期再想改会变得有点麻烦。

我使用的是unraid的web ui进行docker运行选项的配置,相比命令行的好处就是有着详细的说明也不担心手抖眼花,我们一条条来看:

Unraid上的swag docker配置界面
  • 基本参数:前面几条是容器名、常规的存储库、网络和IP地址等。
  • TZ:时区,填写Asia/Shanghai
  • 固定IP地址:自己指定IP地址总归比随机地址要方便些。
  • WEB UI : 这里请求了2个端口443和80,其中443是为了显示运行成功的界面,80是为了http方式验证时使用。需要注意的是在指定IP上这两个端口没有被占用。
  • URL : 你拥有的二级域名,比如domain.com
  • VALIDATION : 验证方式,需要填写dns或者http。由于我国家用宽带屏蔽了443、80等常用端口,因此只能使用dns方式。
  • SUBDOMAINS:子域名,比如你想使用的是sub.domain.com,那么填写sub,多个用逗号分隔。
  • CERTPROVIDER:证书提供商,默认为Let's Encrypt,有需要可以填写zerossl,这里留空就行。
  • DNSPLUGIN:DNS即域名提供商,我们能接触到的供应商应该都有,这里举几个常见的,例如aliyun/dnspod/azure/cloudflare
  • PROPAGATION:留空即可。
  • EMAIL:如果证书提供商选择ZeroSSL的话需要填写,默认应该留空也没事。
  • ONLY_SUBDOMAINS:是否只认证三级域名。例如你不想为以domain.com结尾的所有网址进行加密(可能是另有证书等原因),只想加密sub.domain.com,那么填写true,反之false。
  • EXTRA_DOMAINS:其他还想进行认证的域名全称,例如extradomain.com,subdomain.anotherdomain.org,*.anotherdomain.org
  • STAGING:默认false就可以。
  • 额外参数:由于swag的fail2ban功能需要控制网络的权限,因此需要添加额外参数--cap-add=NET_ADMIN
  • 其他选项:除此之外,还要设置PUID/PGID/MASK等权限设置。如果想要方便,直接在外部更改swag的配置文件,也可以把容器的/config文件夹映射出来。

那么把上述的设置去掉一些空值和默认值,等效为Docker命令形式就是:

$ docker create  --name=swag  --net=NETNAME  --ip=192.168.x.x  -e TZ=Asia/Shanghai  -p 443:443  -p 80:80  -e URL=domain.com  -e VALIDATION=dns  -e SUBDOMAINS=sub  -e DNSPLUGIN=dnspod  -e ONLY_SUBDOMAINS=true  -e STAGING=false  -e PUID=1000  -e PGID=100  -v /YOUR/PATH/swag:/config  --cap-add=NET_ADMIN --restart unless-stopped linuxserver/swag

创建成功后,使用 docker start swag 来运行容器。

配置填写

容器启动之后,使用 docker logs swag -f 来查看日志。在初始化完成后,我们会发现在验证过程中发生了一些错误,这是正常的,因为我们尚未配置域名提供商的凭据,换言之,swag需要一些手段来确认你填写的域名确实是你的。

如果你之前把/config文件夹映射出来,那么直接去你映射的目录下面寻找相关文件就行,也可以通过docker exec -it swag bash命令进入swag容器中直接寻找。

我们可以在容器的/config/dns-conf 里找到对应的文件,填写相关的凭据即可。比如我使用的是托管在腾讯云的域名,那么就打开文件夹下的dnspod.ini,可以看到有两个选项需要填写,分别是你腾讯云注册账号的邮箱和dnspod的api token。
 

DNSPod(腾讯云)的配置文件

其他供应商的配置项并不清楚,但是腾讯云有两点值得一提:

  1. 安全中心中的密钥分为腾讯云 API 密钥和DNSPod Token两类,一般和域名相关操作要求的都是使用DNSPod Token
  2. dns_dnspod_api_token这一栏需以“ID,Token”的形式填写,比如“123456,abcde123abc"。

修改成功后,使用 docker restart swag 来重启容器,并再次查看日志。如果设置没错的话,可以看到其在进行各种操作。等到 Server ready出现后,web服务器就准备就绪了。此时访问你为swag指定的IP(例如192.168.1.10),应该就能看到如下页面:

搭建成功后可以看到swag的页面

端口转发

现在swag已经有了进行https代理的能力,但是暂时只能管自己的一亩三分地,我们还要做的就是决定将哪些流量经过它,又由它如何处理。和我之前一样裸奔的读者,应该比较熟悉如何使用路由器进行端口转发了,现在只不过是要再加一层swag中转,如图所示。

swag工作示意图

如果你已经很熟悉nginx了,那么可以随心所欲地玩弄网络,对swag内的nginx进行配置。但如果你是和我类似的小白,没有什么配置网络的经验,swag也很贴心地准备了让你照抄的示例。

打开容器的/config/nginx文件夹,我们主要关注的是里面的proxy-conf文件夹、site-conf文件夹以及nginx.conf文件。在nginx.conf文件代码块末尾加上一行

include /config/nginx/site-confs/*.conf;

,即使得site-conf文件夹里面所有的config生效。proxy-conf里面是大量的sample,也就是说如果里面有你使用的服务,完全可以从里面复制一份到site-conf文件夹,去掉后面的sample尾缀,调整一下其中的ip请求等,再将路由器中原本指向服务的转发改为指向swag。

当然,总归有样例中没有你的服务的时候,其实也都大差不差,我以转发microbin为例,随便复制一个最小单元的配置文件,顺便说一下里面的含义。

    listen 12345 ssl http2;
    listen [::]:12345 ssl http2;

    server_name microbin.*;

前两行表示监听ipv4和ipv6的12345端口并启用 SSL 和 HTTP/2,server_name一栏表示监听访问的三级域名为microbin的请求。

location / {
	...
        set $upstream_app microbin;
        set ...
        proxy_pass $upstream_proto://$upstream_app:$upstream_port;
    }

location /表示块中逻辑对根路径生效。块中除了启用了两个配置以外,就是设置各种变量将请求转发到上游协议为http,地址为microbin(网络没设置好的话须填容器所在ip),端口为8080的地址。

写完之后保存退出,在swag内部使用命令nginx -s reload刷新配置,再在路由器界面设置将外界对端口12345的请求都转到swag所在ip的12345端口,此时通过域名访问,就可以看见域名前面变成了https,大功告成!

设置成功后变成了https访问

一些举手之劳

当然,可能有人还是要说了,为了一个不知道有什么用的https而搞七搞八,甚至每次新建服务都要新建修改配置文件,配置路由器转发,实在太麻烦啦!但我又不想纯裸奔,多少弄片叶子遮着,有什么几分钟就能做到的保护措施呢?以下便是我一些浅薄的经验:

  1. 所有暴露在外的主动页面设置权限或密码。比如microbin这种临时文件存储,未登录用户只能浏览或下载,防止一些路过的手贱。
  2. 以影音、阅读服务等单纯接收信息且较少个人隐私信息的服务为主。和上一条类似,万一真被扫到了就当分享书单了,密码库或者日记暴露在外面纯属勾引人犯罪。
  3. 不使用原端口号和1000以下端口号。转发时换换端口也不花钱。
  4. 实在需要远程访问的重要页面使用zerotier等内网穿透服务。举例:NAS的管理web界面。
  5. 访问途径和用途较为固定的设置请求白名单。举个场景:在公司里偶尔需要访问家里的一些私密服务作辅助,而办公电脑又不方便内网穿透,公司的出口ip固定,那么路由可以只接受从这个ip来的请求。
  6. 不要使用重复密码。很惭愧地说这条我并没有完全做到,但是多用几个不同的密码能在你某个服务不幸中招时大大降低其他服务沦陷的几率。

当然了,更有实力的、安全要求更高的,还可以通过设置fail2ban防暴力破解、划分vlan故障隔离等等方式来构筑一个滴水不漏的堡垒。鉴于我也只是初窥门径,就不继续露怯了。

按需安全

在论坛上我曾看见过一些讨论,大意就是:使用这种外部工具进行反向代理并不能做到非常可靠,遑论把外部工具构建在系统内部形成循环依赖了。

对此我是相对认可的,如果你的服务真的非常重要,比如暗恋对象会用你的emby看电影或者上级会从你的gitea拉代码,以至于关键时刻一两小时的无法访问都是无法接受的,那么一个能和nas一起升天的外部工具确实不是个明智的选择。

但是假如你和我一样,并不是非常在乎24*7的稳定,出问题了会晚上回家慢吞吞看日志,看不出来就删容器重建,那么这种懒人软件就非常合适,稍微研究几小时就能给自己足够的安全感。我相信swag单独出问题的几率微乎其微,也远小于其他笨重粗糙的屎山。万一是nas整体的问题,所有服务都无法工作,那么就算swag还在坚挺又有什么意义呢(笑

我的意思是,在上马各种安全改造前,可以先审视一下自己的需求(和水平),自己真正想要保护的究竟是什么,从而有一个优先级。如果是珍贵回忆,就多买硬盘弄几个异地备份;如果是敏感隐私,那就先加密再备份;如果是想要外网流畅访问,建议先找靠谱的解析服务提供商(dnspod属实不行),然后花钱升级宽带路由网卡;实在没啥好搞的,再来审视自己的网络拓扑可靠性也不迟。

尾声

一开始只是想介绍一下发现的实用软件,然而其功能丰富,我所讲述的不过冰山一角,内容未免有些干瘪,因此结尾没忍住又说了点鼓捣自托管过程中浮现的想法。

有时候也不免会泄气,感觉自己弄的都是半吊子无用功,未见得比大公司兜售的服务更好用、更安全、更廉价,甚至未必更私密(起码迅雷下载界面不能直接搜出来)。驱使我的究竟是什么呢?我想,可能是掌控欲再加上一点点的求知欲吧~