前言

约莫着,手头的事情(毕业论文)终于收尾了,做做自己的事情吧,学学前端,顺带把半死不活的博客救一救,还有这些年有的一些技术复盘笔记,都该收拾了。

于是重返阿里云买了一台服务器,还是一样的价格,99¥一年(刚买完师弟就告诉我学生认证免费零半年ECS云服务器,我:??),但前域名已经是大涨价了,只好换了一个新的,总觉得不似曾经那般亲切了,或许离别总是感伤的,一边感慨一边部署完服务器,顺便记录一下Nginx的配置流程。

配置过程

前两节主要是过程分析,有需要可直接跳转至实践开始。

Nginx

首先什么是Nginx?简单解释,Nginx主要是做反向代理,当你服务器运行一个位于http://localhost:4000/网页时,本机是可以直接访问的,但是从公网进入的网页请求会落在80(HTTP)和443(HTTPS)端口,这对不上本机的4000端口,这时Nginx就可以对接从公网进入的端口请求到本地的对应端口,这就是反向代理。
同时Nginx也提供如缓存、压缩、访问日志和安全限制等作用,还可以直接托管静态网页,介于本博客项目使用hexo生成静态网页,所以直接让Nginx托管是很轻松的。

访问流程分析

我的工作流如下示例所示,可以看出我需要使用Nginx直接托管静态网页并做反向代理。

1
2
3
4
5
6
7
Windows编译博客页面
↓
push到gitee
↓
再由服务器pull得到编译后的博客页面
↓
最后由`Nginx`托管博客网页并重定向外部的网页请求。

此时你的访问流程大致如下,大多数DNS解析式这个路线,将域名托管于此DNS解析服务器上,访问域名时由DNS解析服务器给出服务器的真实ip地址,完成访问,这里需要由Nginx载入此域名下的SSL证书密钥来加密以安全访问。

1
2
3
4
5
你的浏览器输入网站访问
↓
DNS解析服务器
↓ 第一层SSL证书,Nginx 在这里发挥作用
我的服务器

但不同的是,我的域名由Cloudflare提供DNS解析和服务,Cloudflare会给其托管的域名做两套安全访问控制,流程如下,也就是说Cloudflare会做中继代理,先确定服务器到Cloudflare是加密的,再加密转发给你。

1
2
3
4
5
6
7
你的浏览器输入网站访问
↓ 第一层SSL证书
Cloudflare DNS解析 → Cloudflare内容分发服务器(替代我的服务器)
↓ 第二层SSL证书,Nginx 在这里发挥作用
我的服务器(主要是网页内容)
↓
缤纷云存储(图片和各种资源)

我在阿里云低价购得域名,再将DNS解析服务器设置为Cloudflare后,Cloudflare会用自己的服务器为接管的域名访问提供免费的CDN加速服务,同时Cloudflare自动为接管的域名颁发第一层SSL证书,这是很省心的,我们只需要申请部署第二层SSL证书到服务器上去就行。

因为我的服务器带宽有限,所以将网页内容和样式文件部署于服务器上有利于及时更新和维护,而图片视频等大体积静态资源放在缤纷云存储,网页加载时会自动获取这些内容而不占用服务器带宽。

那么现在访问流程和路线都清楚了。

Nginx配置与应用

这里主要是证书加载和端口监听以及本地静态网页托管位置的设置,细节如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 更新软件源并安装 Nginx
apt update
apt install nginx -y

# 启动 Nginx、设置开机自启并查看运行状态
systemctl enable --now nginx
systemctl status nginx --no-pager

# 进入 Hexo 项目,安装依赖并生成静态页面
cd 你的项目地址
npm install
umask 022
hexo clean
hexo generate

# 确保 Nginx 可以进入项目目录并读取 public
chmod 711 <你的项目位置>
chmod -R a+rX <你的项目位置>

# 创建 Cloudflare Origin CA 证书的保存目录
mkdir -p /etc/nginx/ssl/mepha.fun
chmod 700 /etc/nginx/ssl/mepha.fun

# 将 Cloudflare 提供的 Origin Certificate 粘贴到这里
nano /etc/nginx/ssl/mepha.fun/origin.pem

# 将 Cloudflare 提供的 Private Key 粘贴到这里,私钥不要上传至 Git
nano /etc/nginx/ssl/mepha.fun/origin.key

chmod 644 /etc/nginx/ssl/mepha.fun/origin.pem
chmod 600 /etc/nginx/ssl/mepha.fun/origin.key

# 创建站点配置
nano /etc/nginx/sites-available/mepha.fun

站点配置如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
server {
#自动将HTTP访问转到HTTPS
listen 80;
listen [::]:80;

server_name mepha.fun www.mepha.fun;

return 301 https://$host$request_uri;
}

server {
#对于HTTPS协议的监听
listen 443 ssl http2;
listen [::]:443 ssl http2;

server_name mepha.fun www.mepha.fun;

root <你的项目位置>;
index index.html;


ssl_certificate /etc/nginx/ssl/mepha.fun/origin.pem;
ssl_certificate_key /etc/nginx/ssl/mepha.fun/origin.key;

ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;

access_log /var/log/nginx/mepha.fun.access.log;
error_log /var/log/nginx/mepha.fun.error.log;

location / {
try_files $uri $uri/ =404;
}

location ~* \.(jpg|jpeg|png|gif|webp|svg|ico|css|js|woff|woff2|ttf)$ {
expires 7d;
add_header Cache-Control "public";
try_files $uri =404;
}
}

保存配置后启用站点,并检查 Nginx 配置。只有 nginx -t 检查成功后才重新加载服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
# 启用站点并移除 Nginx 默认页面
ln -s /etc/nginx/sites-available/mepha.fun /etc/nginx/sites-enabled/mepha.fun
rm -f /etc/nginx/sites-enabled/default

# 检查语法并加载配置
nginx -t
systemctl reload nginx

# 确认 80 和 443 端口已经监听
ss -lntp | grep -E ':80|:443'

# 测试服务器本机的 HTTPS 响应
curl -Ik --resolve mepha.fun:443:127.0.0.1 https://mepha.fun/

还需要在阿里云安全组中放行 TCP 80 和 443,随后在 Cloudflare 的 DNS 页面添加以下记录:

1
2
A      @      <服务器公网 IPv4>    Proxied
CNAME www mepha.fun Proxied

配置完成后,可以测试完整的公网访问链路:

1
2
curl -I http://mepha.fun
curl -I https://mepha.fun

正常情况下,HTTP 会返回 301 并跳转到 HTTPS,HTTPS 会返回 200。此后更新博客不需要运行 hexo s,也不需要重启 Nginx,只需拉取代码并重新生成 public:

1
2
3
4
cd <你的项目位置>
git pull
hexo clean
hexo generate

这样就完成了。

后记

在服务器配置完成后不久,Cloudflare开始报525错误,我观察到阿里云开始有意阻部分访问接入,因为mepha.fun域名尚未完成ICP备案。为了保证临时的可访问性,我进行了下面的测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
浏览器直连源站:- 携带 SNI=mepha.fun
- TLS 握手成功
- 网站可以访问

Windows curl --resolve 直连源站:- 同样携带 SNI=mepha.fun
- ClientHello 到达服务器前后出现异常 RST
- TLS 握手失败

Cloudflare 橙云回源:- 返回 525
- 说明 Cloudflare 到源站的 TLS 握手失败

服务器同步抓包:- 真实客户端报文 TTL 约为 111
- 提前到达的 RST 报文 TTL 约为 55,而且 TOS、IP ID 也不同
- 很像链路中的设备伪造客户端身份注入 RST,并非 Nginx主动拒绝

Nginx、本地证书、443 监听均正常,并且其他来源能够完成 TLS 会话。

阿里云的官方文档提示域名指向阿里云中国内地服务器时,未备案,或已在其他服务商备案但未接入阿里云,都会导致访问被阻断。那么当前仅能先行使用关闭Cloudflare的橙云代理,直接部署完整的SSL证书到服务器,待ICP备案完成后才能进行下一步操作了。

免责声明:这是一次故障排查和临时直连方案,国内服务器面向公网提供网站服务时,应遵守备案要求。