有一个自己的项目需要上线,域名解析完成后,发现只能使用 http 协议,这在浏览器上会限制,提示用户不安全,所以需要把 HTTP 升级成 HTTPS 协议,但又不想花钱。
前提条件:
已经配置好 Nginx 服务器
域名已解析到您的服务器 IP
已开放 80 和 443 端口(可在阿里云控制台的安全组设置中配置)
获取证书
我们先获取证书,我使用的是「Let's Encrypt」,这是一家为6亿多个网站提供免费 TLS 证书的非营利组织。
Let's Encrypt 提供免费的证书,有效期为 90 天,可以自动续期。
安装证书
我们需要先安装 Certbot 和 Nginx 插件:
# 安装 EPEL 仓库
sudo yum install epel-release -y
# 安装 Certbot 和 Nginx 插件
sudo yum install certbot python3-certbot-nginx -y
获取,然后安装证书
sudo certbot --nginx -d your-domain.com
在操作过程中,Certbot 会询问几个问题:
输入您的邮箱地址(用于紧急续期通知和安全公告)
同意服务条款
是否愿意共享邮箱(可选)
是否希望将所有 HTTP 流量重定向到 HTTPS(建议选择 2,完全重定向)
配置 Nginx
提供一个 AI 反馈的 Nginx 配置:
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /path/to/your/certificate.crt;
ssl_certificate_key /path/to/your/private.key;
# 其他 SSL 配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384;
# 网站根目录等配置
root /var/www/html;
index index.html;
# 其他配置...
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
另外提供一个 Apache 的配置
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile /path/to/your/certificate.crt
SSLCertificateKeyFile /path/to/your/private.key
# 其他配置
DocumentRoot /var/www/html
# 其他设置...
</VirtualHost>
# HTTP 重定向到 HTTPS
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / <https://example.com/>
</VirtualHost>
检查 Nginx 配置
配置好以后,您可以检查 Nginx 的配置,
sudo cat /etc/nginx/conf.d/your-config-file.conf
我服务器上 Nginx 的内容如下:
server {
listen 80;
listen [::]:80;
server_name your-domain.com;
# 添加网站根目录
root /usr/share/nginx/your-domain;
# 为 Let's Encrypt 验证添加特殊处理
location /.well-known/acme-challenge/ {
allow all;
}
# 其他请求继续重定向到 HTTPS
location / {
return 301 https://$server_name$request_uri;
}
}
# HTTPS server
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name your-domain.com;
client_max_body_size 50M;
# 下载优化
proxy_buffer_size 128k; # 代理响应的缓冲区大小
proxy_buffers 4 256k; # 缓冲区数量和大小
proxy_busy_buffers_size 256k; # 繁忙时缓冲区大小
proxy_temp_file_write_size 256k; # 临时文件写入大小
# 开启 gzip 压缩
gzip on;
gzip_min_length 1k;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
# 修改证书路径为 Let's Encrypt 的证书路径
ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers PROFILE=SYSTEM;
ssl_prefer_server_ciphers on;
# 添加反向代理配置
location / {
proxy_pass <http://localhost:3100>;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /40x.html {
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
}
}
自动续期脚本
如果到期怎么办?
我们可以设置自动续期的脚本:
确认当前状态
# 检查 Certbot 版本
certbot --version
# 查看当前证书信息
sudo certbot certificates
测试续期功能
# 执行干运行测试,不实际更新证书
sudo certbot renew --dry-run
创建脚本
sudo nano /usr/local/bin/renew-letsencrypt.sh
添加内容:
#!/bin/bash
# 日志文件
LOG_FILE="/var/log/letsencrypt-renewal.log"
DATE=$(date "+%Y-%m-%d %H:%M:%S")
# 记录开始信息
echo "[$DATE] 开始证书续期检查..." >> $LOG_FILE
# 执行续期操作并记录输出
RENEWAL_OUTPUT=$(certbot renew --quiet 2>&1)
RENEWAL_STATUS=$?
# 检查续期状态
if [ $RENEWAL_STATUS -eq 0 ]; then
echo "[$DATE] 证书检查/续期成功" >> $LOG_FILE
# 检查是否有证书被实际更新
if echo "$RENEWAL_OUTPUT" | grep -q "renewal"; then
echo "[$DATE] 检测到证书已更新,重新加载 Nginx" >> $LOG_FILE
systemctl reload nginx
NGINX_STATUS=$?
if [ $NGINX_STATUS -eq 0 ]; then
echo "[$DATE] Nginx 重新加载成功" >> $LOG_FILE
else
echo "[$DATE] 错误:Nginx 重新加载失败,返回码: $NGINX_STATUS" >> $LOG_FILE
fi
else
echo "[$DATE] 没有证书需要更新" >> $LOG_FILE
fi
else
echo "[$DATE] 错误:证书续期失败,返回码: $RENEWAL_STATUS" >> $LOG_FILE
echo "[$DATE] 错误详情: $RENEWAL_OUTPUT" >> $LOG_FILE
fi
echo "[$DATE] 证书续期流程完成" >> $LOG_FILE
echo "----------------------------------------" >> $LOG_FILE
设置执行权限
sudo chmod +x /usr/local/bin/renew-letsencrypt.sh
创建任务
sudo crontab -e
添加以下内容:
# 每天凌晨 2:15 和下午 2:15 运行证书续期
15 2,14 * * * /usr/local/bin/renew-letsencrypt.sh
验证任务设置
sudo crontab -l
设置每周运行一次
sudo chmod +x /usr/local/bin/renew-letsencrypt.sh
sudo crontab -e
每周检查一次
# 每周一上午9点检查证书状态
0 9 * * 1 /usr/local/bin/renew-letsencrypt.sh
手动续签脚本
# 执行脚本
sudo /usr/local/bin/renew-letsencrypt.sh
# 检查文件输出
sudo tail -f /var/log/letsencrypt-renewal.log
查看证书信息
sudo certbot certificates
会显示出「已安装证书的域名、存储位置、到期日期、续期设置」证书有效期
比如:从 2025-04-21 到 2025-07-20(共 90 天,符合 Let's Encrypt 标准)。
Certbot 会在到期前 30 天(即 2025-06-20 左右)自动尝试续期(你之前的 -dry-run 测试已确认续期配置正常)。
无需手动操作,除非续期失败。