有些问题,真的不是证书没有装上,而是“它到底被谁在用”没有弄清楚。 前几天我在整理几个子域名的时候,就碰到了一件很容易让人迷糊的事:明明宝塔里已经装好了 SSL 证书,面板上看起来也一切正常,可浏览器依然提示“您的连接不是私密连接”。后来顺着 Nginx 配置和证书路径一点点看,才发现问题并不在“有没有证书”,而是在“当前 Nginx 实际引用的是哪一份证书文件”。
这篇文章,我想把整个过程梳理一遍。 如果你也正好在折腾:
– 域名解析
– 免费 SSL 证书
– Nginx 反向代理
– 宝塔面板 SSL 配置
– 阿里云前置证书和源站证书的区别
那希望这篇文章能帮你少走一点弯路。
先理解一个核心问题:浏览器看到的证书,不一定是源站证书
这是最容易踩坑的地方,也是很会绕很久的地方。 如果你的访问链路是这样的: `用户浏览器 -> 阿里云 CDN / WAF / 负载均衡 -> Nginx 源站` 那么浏览器优先校验的,是**阿里云前面这一层返回的证书**,而不是源站 Nginx 里的那张证书。 也就是说:
– 阿里云前置层证书过期了,浏览器会报错。
– 即使源站宝塔里的证书是新的,浏览器也可能依然提示“不安全”。
– 如果你直接访问的是源站,才会真正用到源站 Nginx 配置的那份证书。
所以后面排障时,一定要先问自己一句:
当前这个域名,到底是直连 Nginx,还是前面还有阿里云那一层在处理 HTTPS? 这一步想明白了,很多问题就不会越修越乱。
域名解析是什么,A 记录又是什么
在开始配置网站前,域名解析一定要先做好。
A 记录是什么
A 记录就是把一个域名指向服务器的 IPv4 地址。 比如:
– `www.example.cn -> 111.15.17.29`
– `ai.example.cn -> 111.15.17.29`
当浏览器访问相应的域名时,会先通过 DNS 查到这个 IP,然后再去连接这台服务器。 也就是说,A 记录负责“让人找到服务器”。
TXT 记录是什么
TXT 记录不是拿来访问网站的,它更像是一张“说明纸条”。 常见用途有:
– 证书签发时做 DNS 验证
– 域名归属验证
– 邮件系统 SPF / DKIM / DMARC 配置
– 某些平台的接入验证
比如:
– `_acme-challenge.xxx`
– `_dnsauth.xxx`
这类 TXT 记录通常都是为了验证域名控制权,不负责网站访问。
你可以这样记:
– A 记录:告诉大家“网站在哪台服务器(IP)”
– TXT 记录:告诉平台“这个域名确实是我的”
纯 Nginx 环境:不安装宝塔,如何配置 SSL 证书和反向代理
如果你没有安装宝塔,其实也完全可以把 HTTPS 和反向代理配好。 而且这种方式更清晰,更适合喜欢自己掌控配置的人。
安装 Nginx
以 Debian / Ubuntu 为例:
sudo apt update
sudo apt install -y nginx
安装完成后,可以先检查一下:
nginx -v
systemctl status nginx
准备域名解析
在域名解析后台添加 A 记录,例如:
主机记录:git(主域名前的次级域名,如git.example.cn)
记录类型:A
记录值:你的服务器公网 IP
如果你要配置多个站点,就分别添加:
git -> 你的公网 IP
www -> 你的公网 IP
ai -> 你的公网 IP
注意两点: 1. 域名必须已经解析到当前服务器; 2. 80 和 443 端口需要放行
通过终端配置Let's Encrypt 免费 SSL 证书
更建议直接在服务器上使用 `acme.sh` 或 `certbot` 申请 Let’s Encrypt 免费证书。下面以 `acme.sh` 为例。
curl https://get.acme.sh | sh -s email=my@example.com
source ~/.bashrc
设置默认证书机构为 Let’s Encrypt:
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt
使用 webroot 方式签发证书
假设你的网站目录是:
/www/wwwroot/www.example.cn
执行:
~/.acme.sh/acme.sh --issue -d www.example.cn --webroot /www/wwwroot/www.example.cn
把证书安装到指定目录
把证书统一放在:
/etc/nginx/ssl/域名/
# 先创建目录:
mkdir -p /etc/nginx/ssl/www.example.cn
# 然后安装到该目录
~/.acme.sh/acme.sh --install-cert -d git.ganglitm.cn \
--key-file /etc/nginx/ssl/git.ganglitm.cn/privkey.pem \
--fullchain-file /etc/nginx/ssl/git.ganglitm.cn/fullchain.pem \
--reloadcmd "systemctl reload nginx"
这样做的好处是: 路径统一 、续期后自动覆盖、Nginx 不需要反复改路径
从阿里云申请的免费证书
阿里云服务器每年给了一定额度的免费证书,证书有效期3个月。
直接在阿里云的数字证书管理服务控制台申请免费的证书(个人测试证书),选择创建证书,填入:
域名: 如 www.example.cn
选择快捷签发,填写信息即可。等到审核完成,下载ssl证书,对于nginx服务,选择nginx对应的证书,里面包括后缀为key和pem的文件,接下来进行证书的安装。
在服务器终端输入:
nginx -t
里面包含了nginx的默认目录,即nginx.conf的目录,一般的路径为/etc/nginx/nginx.conf,那么/etc/nginx/就是需要安装证书的位置,在这个目录下创建cert文件夹并上传证书文件:
cd /etc/nginx/
# 创建cert文件夹
mkdir -p cert
将证书(key和pem)上传到cert目录下。在nginx.conf文件里面写入:
cd /etc/nginx/
vim nginx.conf
# 填入以下内容
server {
listen 80;
server_name www.example.cn; # 修改为自己的域名
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name www.example.cn; # 修改为自己的域名
ssl_certificate /etc/nginx/cert/www.example.cn/xxx.key; # 修改为自己的文件名
ssl_certificate_key /etc/nginx/cert/www.example.cn/xxx.pem;# 修改为自己的文件名
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
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 $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
保存后检查配置:
nginx -t
没有报错就重载:
systemctl reload nginx
宝塔面板环境:配置 SSL 证书和反向代理时,要特别注意证书路径
如果安装的是宝塔面板,那么很多事情会更省心一点。宝塔可以直接给网站设置ssl证书。但也正因为它帮我们做了很多自动化,所以路径问题特别容易被忽略。
宝塔的 SSL 证书为什么会“看起来装了,实际上没生效”
这类问题最常见的原因有两个:
– 站点配置文件仍然引用旧证书路径
– 宝塔重新申请了新证书,但 Nginx 实际用的不是宝塔维护的那份文件
比如一种容易踩坑的写法:
ssl_certificate /www/server/nginx/conf/cert/www.example.cn;
ssl_certificate_key /www/server/nginx/conf/cert/www.example.cn;
这种写法不一定绝对错误,但它很容易出现下面的情况:
– 文件还是旧的
– 不是宝塔续期时维护的文件
– 路径和面板里的当前证书不一致
如果之前是在服务器里面申请的ssl证书,那么在nginx里面的证书文件路径配置需要惊醒修改。
宝塔自动申请证书时,更推荐使用面板实际维护的路径
如果证书是宝塔自动签发、自动部署的,那么更稳妥的方式,是引用宝塔当前站点实际使用的证书目录。 例如类似这样的路径(实际上这些都可以,随便选择一种即可):
/www/server/panel/vhost/letsencrypt/www.example.cn/fullchain.pem;
/www/server/panel/vhost/letsencrypt/www.example.cn/privkey.pem;
/www/server/panel/vhost/cert/www.example.cn/fullchain.pem;
/www/server/panel/vhost/cert/www.example.cn/privkey.pem;
/www/server/panel/vhost/ssl/www.example.cn/fullchain.pem;
/www/server/panel/vhost/ssl/www.example.cn/privkey.pem;
这个时候需要在nginx.conf文件里面修改相应的部分为:
server
{
listen 80;
server_name www.example.cn;
# 将 HTTP 请求重定向到 HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
server
{
listen 443 ssl;
http2 on;
server_name www.example.cn;
ssl_certificate /www/server/panel/vhost/letsencrypt/www.example.cn/fullchain.pem; # 修改为自己的域名,路径可任意选择一个(见上面部分)
ssl_certificate_key /www/server/panel/vhost/letsencrypt/www.example.cn/privkey.pem; # 修改为自己的域名,路径可任意选择一个(见上面部分)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers on;
location ^~ /.well-known/acme-challenge/ {
root /www/wwwroot/www.example.cn; # 换成你这个站点的真实目录
try_files $uri =404;
default_type text/plain;
}
location / {
proxy_pass http://127.0.0.1:13000/;
proxy_ssl_server_name on;
proxy_ssl_name 127.0.0.1;
# WebSocket(必需)
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# 转发头(含前缀)
proxy_set_header Host $host;
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 $scheme;
client_max_body_size 200m;
# proxy_set_header X-Forwarded-Prefix /jellyfin;
# 播放长连
proxy_read_timeout 3600;
proxy_send_timeout 3600;
proxy_buffering off;
proxy_request_buffering off;
# 不让上游改写 Location
proxy_redirect off;
}
}
# 保存后检查配置:
nginx -t
# 重载
systemctl reload nginx
宝塔环境下正确的检查思路
打开站点配置,检查:
ssl_certificate
ssl_certificate_key
是不是都指向当前有效证书。并检查对应目录是否存在证书文件。
改完后重新加载 Nginx
如果改了路径却没重载,浏览器看到的还是旧内容。
怎么判断当前网站到底返回的是哪张证书
打开域名网站后,查看证书详情(可在浏览器里面网站的前端有个锁(不安全时会有红线)的图标,点击即可查看连接安全部分),重点看:
– 证书主题(Subject / CN)
– 颁发者(Issuer)
– 到期时间(Not After)
– SHA-256 指纹
