1. 项目概述
最近接手了一个基于区块链的教育评价系统平台,在部署上线时遇到了SSL证书配置的问题。作为一个长期从事Web开发的工程师,我深知HTTPS对于现代网站的重要性——它不仅关乎数据安全,更是影响搜索引擎排名和用户信任度的关键因素。这次我尝试使用腾讯云的QClaw AI助手来完成整个SSL部署过程,记录下从零开始到最终解决问题的完整经历。
这个平台运行在阿里云Ubuntu 22.04服务器上,使用宝塔面板管理,Nginx作为Web服务器。系统包含三个主要入口:手机端、电脑端管理后台和独立的API服务。最初所有服务都运行在HTTP协议下,现在需要全站升级到HTTPS。
2. 环境准备与工具选型
2.1 服务器环境确认
在开始之前,QClaw首先对服务器环境进行了全面检测:
bash复制nginx -v # 输出:nginx/1.26.3(宝塔自带版本)
certbot --version # 输出:未安装
检测发现服务器上同时存在两套Nginx:
- 系统自带的Nginx(通常位于/usr/sbin/nginx)
- 宝塔安装的Nginx(位于/www/server/nginx)
这种双重环境是使用宝塔面板的典型特征,也是后续证书申请需要特别注意的地方。
2.2 Certbot工具选择
Let's Encrypt是目前最流行的免费SSL证书颁发机构,而Certbot是其官方推荐的客户端工具。在Ubuntu系统上安装Certbot非常简单:
bash复制apt-get install -y certbot python3-certbot-nginx
这里特别选择了python3-certbot-nginx插件,因为它提供了对Nginx配置的自动修改支持。不过在实际使用中我们会发现,在宝塔环境下这个插件并不能直接使用。
3. 证书申请与配置
3.1 域名验证方式选择
Certbot支持多种验证域名所有权的方式,常见的有:
- HTTP验证(--webroot模式)
- DNS验证(--dns模式)
- 独立Web服务器验证(--standalone模式)
在宝塔环境下,80端口已被占用,standalone模式无法使用。DNS验证虽然可行,但需要API密钥等额外配置。因此最合适的选择是webroot模式,它通过在网站根目录下创建特定文件来验证域名所有权。
3.2 主域名证书申请
首先确保验证路径可访问:
bash复制mkdir -p /www/wwwroot/.well-known/acme-challenge
echo "test" > /www/wwwroot/.well-known/acme-challenge/test.txt
curl http://yourdomain.com/.well-known/acme-challenge/test.txt
确认测试文件可以正常访问后,执行证书申请命令:
bash复制certbot certonly --webroot \
-w /www/wwwroot \
-d yourdomain.com \
--non-interactive --agree-tos \
--email admin@yourdomain.com
成功后会显示证书保存路径和过期时间:
code复制Certificate is saved at: /etc/letsencrypt/live/yourdomain.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/yourdomain.com/privkey.pem
This certificate expires on 2026-06-14.
3.3 Nginx HTTPS配置
在宝塔面板中,每个网站都有独立的配置文件。我们需要修改对应的Nginx配置来启用HTTPS:
nginx复制server {
listen 80;
server_name yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name yourdomain.com;
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
# 手机端配置
location ^~ /mobile/ {
alias /www/wwwroot/web/mobile/dist/;
try_files $uri $uri/ /mobile/index.html;
}
# 电脑端配置
location ^~ /admin/ {
alias /www/wwwroot/web/admin/dist/;
try_files $uri $uri/ /admin/index.html;
}
}
配置完成后,需要测试并重载Nginx:
bash复制/www/server/nginx/sbin/nginx -t # 配置检查
/www/server/nginx/sbin/nginx -s reload
4. Mixed Content问题排查与解决
4.1 问题现象
HTTPS部署完成后,用户反馈登录页验证码无法加载。浏览器控制台显示Mixed Content错误:
code复制Mixed Content: The page at 'https://yourdomain.com/admin/login' was loaded
over HTTPS, but requested an insecure XMLHttpRequest endpoint
'http://api.yourdomain.com/system/auth/captcha'.
This request has been blocked.
4.2 原因分析
现代浏览器出于安全考虑,会阻止HTTPS页面加载HTTP资源。我们的前端页面已经升级到HTTPS,但API服务仍然使用HTTP协议,因此被浏览器安全策略拦截。
4.3 API子域名SSL部署
解决方法是给API子域名也部署SSL证书:
bash复制certbot certonly --webroot \
-w /www/wwwroot/education-server-master \
-d api.yourdomain.com \
--non-interactive --agree-tos \
--email admin@yourdomain.com
然后更新API的Nginx配置:
nginx复制server {
listen 80;
server_name api.yourdomain.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
http2 on;
server_name api.yourdomain.com;
ssl_certificate /etc/letsencrypt/live/api.yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.yourdomain.com/privkey.pem;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
4.4 前端资源修复
服务端配置完成后,发现前端打包的JS文件中仍然硬编码了HTTP协议的API地址。使用以下命令查找并替换:
bash复制find /www/wwwroot/web/ -name "*.js" \
| xargs grep -l "http://api.yourdomain.com" \
| xargs sed -i 's|http://api\.yourdomain\.com|https://api.yourdomain.com|g'
验证替换结果:
bash复制grep -r "http://api.yourdomain.com" /www/wwwroot/web/ -l | wc -l
# 输出0表示全部替换完成
5. 证书自动续期配置
Let's Encrypt证书有效期为90天,需要设置自动续期。编辑crontab:
bash复制crontab -e
添加以下内容(每周一凌晨3点检查续期):
code复制0 3 * * 1 /usr/bin/certbot renew --quiet --post-hook "/www/server/nginx/sbin/nginx -s reload"
6. 安全加固建议
完成基础HTTPS部署后,还可以进一步加固安全性:
6.1 启用HSTS
在Nginx配置中添加以下指令,强制浏览器始终使用HTTPS:
nginx复制add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
6.2 配置CSP
内容安全策略可以防止XSS攻击:
nginx复制add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-ancestors 'none';";
6.3 优化SSL配置
使用更安全的加密套件:
nginx复制ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers on;
7. 经验总结与避坑指南
7.1 宝塔环境下的特殊处理
在标准Linux环境下,可以使用certbot --nginx自动完成证书申请和配置。但在宝塔环境下,由于Nginx的特殊安装位置和配置管理方式,必须使用--webroot模式手动申请证书,然后手动修改Nginx配置。
7.2 全站HTTPS的必要性
很多开发者只为主域名部署SSL证书,忽略了子域名和API接口。实际上,只要前端页面中有任何HTTP资源请求,都会触发Mixed Content警告。因此,所有相关的域名和子域名都需要同步升级到HTTPS。
7.3 前端资源的协议问题
现代前端项目通常会将API地址打包进JS文件。即使服务端配置了HTTPS,如果前端代码中硬编码了HTTP地址,仍然会导致问题。解决方法包括:
- 使用相对协议(//api.example.com)
- 通过环境变量注入API地址
- 部署后使用sed等工具批量替换
7.4 自动化运维的价值
这次使用QClaw AI助手的体验让我深刻感受到自动化运维的效率提升。传统方式下,完成这样一个HTTPS部署至少需要2-3小时,而借助智能工具,整个过程缩短到30分钟以内,且避免了人为操作失误。