细心的朋友可能发现博客的域名变了. 笔者最近买了一个域名, 让它映射到我的 Github Pages 上. 然后我还在搬瓦工买了一个廉价 VPS 用于搭建一些服务, 比如 RSSHub 和 TTRSS, 同样把域名映射到这上面. 为什么要用域名而不直接使用 IP 地址呢? 一是域名要比 IP 地址好记, 可以使用主机名区分不同的服务 (而不是端口); 二是可以使用 HTTPS. SSL 证书通常很贵, 这里我使用 Cloudflare 的免费代理服务实现免费 HTTPS. 这篇文章总结一下我是怎么做的.
Cloudflare 代理 {#cloudflare-代理}
HTTPS 证书实在是太贵了, 一个通配符域名证书一年要至少花上一两千. 那么如何满足广大人民群众建站需求呢? Cloudflare 就是一个很好的选择. Cloudflare 是一家 CDN 提供商, 可以为网站提供反向代理. 它的做法是, 将域名解析到 Cloudflare 的服务器 (或者说代理) 上, 然后浏览器使用 Cloudflare 的证书与代理建立 SSL 连接; 接着代理会与目标服务器使用自签名的证书建立 SSL 连接, 接下来的数据都由代理转发. Cloudflare 会信任这个自签名证书, 所以整个过程都是没问题的. cloudflare
由于浏览器到代理的连接和代理到服务器的连接都是加密认证的, 所以这两个连接都是安全的, 不怕窃听和篡改. 唯一的问题就是, Cloudflare 成了中间人. 鉴于我们搭建的只是用于个人用途的小网站, 且 Cloudflare 也是跨国大公司, 我们可以认为这个中间人是信得过的. 事实上, 有大量的网站都在使用 Cloudflare, 包括 V2EX, 萌娘百科, TTRSS 官网等. 我们在网上冲浪的时候时常会看到的如下的错误信息, 就是因为站点使用了 Cloudflare 作代理, 但是代理背后的目标服务器挂掉了. server error
域名与 DNS 解析服务 {#域名与-dns-解析服务}
首先需要注册一个域名, 可以在阿里云或者腾讯云等平台注册. 域名相对比较便宜, 笔者的这个域名 69 元人民币 3 年. 需要说明的是, 域名与 DNS 解析服务是不一样的, 注册域名只是向机构交钱把这个域名注册到你名下, 为了把域名映射到 IP 地址, 还需要 DNS 解析服务. 不过现在的各大平台都提供免费的 DNS 解析服务, 比如在阿里云购买域名之后, 点击 "解析" 进入阿里云的域名解析控制台, 就可以看到虽然基础的解析服务是免费的, 但还是有一些高级功能需要额外付费的. 不过这不重要, 因为我们要使用 Cloudflare 的 DNS 解析服务.
首先注册一个 Cloudflare 账号, 然后输入你的域名, 选择免费计划 (土豪随意), 然后它会要你到你的域名注册商将 DNS 解析服务地址改为 Cloudflare 的 DNS 地址. 以阿里云为例, 进入域名控制台, 选择 "DNS 修改" 并点击 "修改 DNS 服务器" 把原来的阿里云的 DNS 服务器修改为 Cloudflare 的 DNS 服务器. 修改生效需要等待一段时间, 完成后 Cloudflare 会以邮件通知你修改生效了.
将域名解析到 Github Pages {#将域名解析到-github-pages}
进入 Cloudflare 的 DNS 控制台, 我们就可以为域名添加解析记录了. 为了将域名解析到 Github Pages, 我们添加一条 CNAME 记录, 将内容设为对应的 Github Pages 的域名, 比如说: server error
Again, Cloudflare 会为我们的服务做代理, 所以无论是 A 记录还是 CNAME 记录, 实际都会解析到 Cloudflare 的代理服务器上. 这个时候如果我们直接那这个域名访问, Github Pages 是会返回 404 的. 因为这样的话 HTTP 请求的 HOST 首部是我们的自定义域名, Github Pages 不认. 所以我们还要在 Github Pages 的设置中告诉 Github 使用自定义域名: server error
这样就可以使用我们的域名访问 Github Pages 了. 为了提高安全性, 还应该在 Cloudflare 的 SSL/TLS 设置中开启 Always Use HTTPS.
将域名解析到 VPS {#将域名解析到-vps}
在 Cloudflare 的 DNS 控制台中添加一条 A 记录将内容设置为 VPS 的 IP 地址即可把域名解析到对应的 VPS 了. 不过在此之前, 我们还应该在 VPS 上搭建 HTTP 服务, 要不然解析了也没东西可访问. 这里笔者使用 Nginx. 稍后可以看到, 我们会配置 Nginx 为 RSSHub 和 TTRSS 作反向代理. 直接使用源码编译 Nginx 有时是个好主意, 因为这样比较好控制.
|---------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13
| hljs bash # install dependencies apt update apt install -y gcc make zlib1g-dev libpcre3-dev libssl-dev # download nginx wget http://nginx.org/download/nginx-1.18.0.tar.gz # replace with any version you like tar -zxvf nginx-1.18.0.tar.gz cd nginx-1.18.0 # build mkdir -p /data/nginx # installation directory ./configure --prefix=/data/nginx --with-http_ssl_module make && make install
|
然后启动 Nginx, 在浏览器中用 IP 地址访问, 看到 "Welcome to nginx!" 就说明安装成功了.
接下来我们让 Cloudflare 将域名解析到 VPS. 正如前面提到的, 我们要让 Cloudflare 与 VPS 之间建立 SSL 连接. 首先要创建证书. 在 SSL/TLS 下选择 Origin Server, 点击 Create Certificate. 这里我直接让 Cloudflare 生成私钥和证书, 然后设置好域名和有效期, 点击下一步就能生成私钥和证书了. 将私钥(Private key)存为文件 cert.key
并将证书(Origin Certificate)存为文件 cert.pem
, 都放在 Nginx 的 conf
目录下, 然后编辑 Nginx 配置文件配置一个 HTTPS 服务:
|------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| hljs conf server { listen 443 ssl; server_name localhost; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { root html; index index.html index.htm; } }
|
然后在 Cloudflare 的 DNS 控制台添加一条 A 记录将内容设置为 VPS 的 IP 地址就可以了. 这样在浏览器中使用域名访问也能看到熟悉的 "Welcome to nginx!" 了.
最后要注意的是, 一定要打开防火墙. 在 Ubuntu 上通常使用 ufw 防火墙.
|-------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5
| hljs bash apt install ufw # install ufw ufw default deny # default deny all ufw allow 22/tcp # allow ssh ufw allow 443/tcp # allow https ufw enable # enable ufw
|
可以使用 ufw status verbose
查看防火墙状态.
|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12
| hljs vbnet # ufw status verbose Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), deny (routed) New profiles: skip To Action From -- ------ ---- 22/tcp ALLOW IN Anywhere 443/tcp ALLOW IN Anywhere 22/tcp (v6) ALLOW IN Anywhere (v6) 443/tcp (v6) ALLOW IN Anywhere (v6)
|
搭建 RSSHub 和 TTRSS 服务 {#搭建-rsshub-和-ttrss-服务}
最简单的做法就是使用 Docker 了. 首先安装好 Docker, 对于 RSSHub, 可参照官方文档, 下载它的 docker-compose.yml
然后执行 docker-compose up -d
即可. 且慢! 这里有一个大问题, Docker 是有坑的, 它开放的端口会绕过防火墙规则, 非常危险. 可以在 /etc/docker/daemon.json
配置 "iptables": false
来规避这一问题, 但是这会导致容器中的 DNS 无法解析, 进而导致 RSSHub 无法使用. 这里笔者暂时没有找到解决办法, 如果有同学有更好的办法麻烦告知我. 这里笔者的做法是修改 docker-compose.yml
让容器的端口不对外开放. 接下来我们修改 Nginx 的配置添加一个到 RSSHub 的反向代理:
|---------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| hljs conf server { listen 443 ssl; server_name rsshub.luyuhuang.tech; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_pass http://127.0.0.1:1200; } }
|
这里 RSSHub 的域名是 rsshub.luyuhuang.tech
, 因此只需要添加一条 A 记录将域名指向这台主机即可.
对于 TTRSS, 同样参照官方文档, 得到 Docker 相关的文件, 然后编辑 .env
设置域名, URL 等必要的环境变量. TTRSS 似乎要求 URL 必须是 */tt-rss/
, 这里笔者暂时也没找到修改它的办法, 只能先这样配置, 如果有同学有更好的办法麻烦告知我.
|---------------|-----------------------------------------------------------------------------------------------------------------------------|
| 1 2 3
| hljs bash HTTP_HOST=ttrss.luyuhuang.tech SELF_URL_PATH=https://ttrss.luyuhuang.tech/tt-rss/ HTTP_PORT=127.0.0.1:8280
|
接着执行 docker-compose up -d
启动容器. 然后同样地, 配置 Nginx 添加一个到 TTRSS 的反向代理:
|------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| hljs conf server { listen 443 ssl; server_name ttrss.luyuhuang.tech; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { proxy_pass http://127.0.0.1:8280/tt-rss/; proxy_set_header HOST ttrss.luyuhuang.tech; } location /tt-rss/ { rewrite ^/tt-rss/(.*)$ /$1 permanent; } }
|
因为我非常不想让 URL 带一个 /tt-rss/
, 于是在 Nginx 这边做了点处理. 此外还需要将 HOST 首部设置为相应的域名以骗过 TTRSS, 否则它还是会报 SELF_URL_PATH
配置错误.
同样在 DNS 控制台中添加一条 A 记录将域名指向这台主机. Nginx 会根据域名的不同转发给不同的服务.
最后, 最好禁用掉 IP 访问. 编辑 Nginx 配置, 在这两个 server 的上面添加一个不限定 server_name
但直接拒绝所有请求的 server 配置:
|------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| hljs conf server { listen 443 ssl; ssl_certificate cert.pem; ssl_certificate_key cert.key; ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m; ssl_ciphers HIGH:!aNULL:!MD5; ssl_prefer_server_ciphers on; location / { deny all; } }
|
总结 {#总结}
最后整个服务的架构图如下: server error