网站也要身份证:HTTPS 证书申请指南

网站也要身份证:HTTPS 证书申请指南

前言

你有没有想过,为什么浏览器地址栏有些网站显示小锁头?,有些却显示"不安全"?这背后就是 HTTPS 证书在起作用。就像人需要身份证证明身份一样,网站也需要证书来证明"我是我"。

本文将用最通俗的语言,带你搞懂 HTTPS 证书的两种申请方式:适合个人/小团队的免费自动化方案,以及适合企业的正式申请流程。

一、先搞懂几个概念

1.1 HTTPS 到底在保护什么?

想象你在咖啡馆用公共 WiFi 网上银行,如果没有 HTTPS,旁边的人可以轻松看到你的账号密码。HTTPS 就像一个加密管道,让数据在传输过程中变成乱码,只有你和服务器能看懂。

1.2 证书的三要素

1.3 证书类型怎么选?

类型 长什么样 验证什么 适合谁 价格
DV 域名验证 显示小锁头? 证明你拥有这个域名 个人博客、小网站 免费~几十元
OV 组织验证 显示小锁头? 点击可看公司名 证明公司真实存在 企业官网 几百~几千元
EV 扩展验证 显示公司名称 绿色地址栏 严格审核公司资质 银行、金融、电商 几千~上万元

二、免费方案:Let's Encrypt 自动化证书

2.1 为什么推荐 Let's Encrypt?

Let's Encrypt 是一个非营利组织,提供永久免费的 SSL 证书。虽然只有 DV 级别(域名验证),但对于个人网站、博客、小项目来说完全够用。

  • ✅ 完全免费,无隐藏费用
  • ✅ 自动化申请和续期
  • ✅ 支持通配符证书(*.example.com)
  • ✅ 所有主流浏览器信任

唯一的"缺点":证书有效期只有 90 天,但可以通过自动化脚本解决。

2.2 申请流程图解

2.3 验证方式怎么选?

2.4 首次申请:从零开始获取证书

如果你是第一次申请 Let's Encrypt 证书,需要先安装 acme.sh 客户端,然后完成首次申请。以下是完整步骤:

步骤一:安装 acme.sh
bash 复制代码
# 在线安装(推荐)
curl https://get.acme.sh | sh -s email=your-email@example.com

# 或者使用 wget
wget -O -  https://get.acme.sh | sh -s email=your-email@example.com

# 安装后重新加载 shell 环境
source ~/.bashrc

# 验证安装
acme.sh --version
步骤二:选择验证方式申请证书

方式A:HTTP-01 验证(最简单,适合单域名)

bash 复制代码
# 确保你的网站可以通过 HTTP 访问
# acme.sh 会自动在网站根目录放置验证文件

# 申请证书(自动模式)
acme.sh --issue -d example.com --webroot /var/www/html

# 如果使用 nginx,可以自动配置
acme.sh --issue -d example.com --nginx

# 申请多个单域名证书
acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html

方式B:DNS-01 验证(支持通配符)

bash 复制代码
# 手动 DNS 模式(需要手动添加 TXT 记录)
acme.sh --issue -d '*.example.com' -d example.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

# 执行后会输出类似内容:
# Domain: '_acme-challenge.example.com'
# TXT value: 'aBcDeFgHiJkLmNoPqRsTuVwXyZ123456'
#
# 请将此 TXT 记录添加到你的 DNS 解析

# 添加 DNS 记录后,继续验证
acme.sh --renew -d '*.example.com' -d example.com --yes-I-know-dns-manual-mode-enough-go-ahead-please

方式C:自动 DNS API(推荐,全自动)

bash 复制代码
# 如果你使用阿里云 DNS
export Ali_Key="your_access_key"
export Ali_Secret="your_access_secret"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_ali

# 如果你使用腾讯云 DNS
export Tencent_SecretId="your_secret_id"
export Tencent_SecretKey="your_secret_key"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_tencent

# 如果你使用 Cloudflare
export CF_Key="your_api_key"
export CF_Email="your_email@example.com"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_cf
步骤三:安装证书到服务器
bash 复制代码
# 安装证书到 nginx
acme.sh --install-cert -d example.com \
  --cert-file      /etc/nginx/ssl/cert.pem  \
  --key-file       /etc/nginx/ssl/key.pem  \
  --fullchain-file /etc/nginx/ssl/fullchain.pem \
  --reloadcmd     "nginx -s reload"

# 安装通配符证书
acme.sh --install-cert -d '*.example.com' \
  --cert-file      /etc/nginx/ssl/wildcard.crt  \
  --key-file       /etc/nginx/ssl/wildcard.key  \
  --fullchain-file /etc/nginx/ssl/wildcard.fullchain.crt \
  --reloadcmd     "nginx -s reload"
步骤四:配置 Nginx 使用证书
nginx 复制代码
server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    
    # SSL 优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000" always;
    
    location / {
        # 你的网站配置
    }
}

# HTTP 跳转 HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

2.5 自动续期:让证书永不过期

Let's Encrypt 证书有效期只有 90 天,但 acme.sh 会自动设置续期任务。你也可以手动管理续期:

bash 复制代码
# 查看已安装的证书
acme.sh --list

# 手动续期某个证书
acme.sh --renew -d example.com

# 强制续期(忽略有效期检查)
acme.sh --renew -d example.com --force

# 查看自动续期任务
crontab -l | grep acme

以下是一个生产环境使用的完整续期脚本:

bash 复制代码
#!/bin/bash
# ============================================================
# Let's Encrypt 通配符证书续期脚本
# 域名: *.example.com + example.com
# ============================================================

set -e  # 遇错即停

# 配置
ACME="/root/.acme.sh/acme.sh"
CERT_DIR="/etc/nginx"
CERT_FILE="${CERT_DIR}/wildcard.crt"
KEY_FILE="${CERT_DIR}/wildcard.key"

# 是否强制续期
FORCE=""
[ "$1" = "--force" ] && FORCE="--force"

echo "========================================"
echo "  Let's Encrypt 通配符证书续期"
echo "========================================"

# 检查当前证书状态
echo "[检查] 当前证书状态:"
openssl x509 -in ${CERT_FILE} -noout -subject -dates 2>/dev/null || echo "  未找到现有证书"

# 智能判断是否需要续期(30天内过期才续)
if [ -z "$FORCE" ] && [ -f "$CERT_FILE" ]; then
    if openssl x509 -in ${CERT_FILE} -noout -checkend 2592000 >/dev/null 2>&1; then
        echo "证书有效期还有30天以上,无需续期。"
        echo "如需强制续期: bash $0 --force"
        exit 0
    fi
    echo "证书将在30天内过期,开始续期..."
fi

# 申请/续期证书
if ${ACME} --renew -d '*.example.com' -d 'example.com' \
    --yes-I-know-dns-manual-mode-enough-go-ahead-please \
    --server letsencrypt ${FORCE} 2>&1; then
    
    # 安装证书
    echo "[安装] 复制证书到nginx目录..."
    cp /root/.acme.sh/*.example.com_ecc/fullchain.cer ${CERT_FILE}
    cp /root/.acme.sh/*.example.com_ecc/*.example.com.key ${KEY_FILE}
    chmod 644 ${CERT_FILE}
    chmod 600 ${KEY_FILE}  # 私钥权限要严格
    
    # 重载nginx
    nginx -t && nginx -s reload
    
    echo "[完成] 新证书信息:"
    openssl x509 -in ${CERT_FILE} -noout -subject -dates
    echo "续期成功!"
else
    # 需要更新DNS验证
    echo "============================================"
    echo "  需要更新DNS TXT记录!"
    echo "============================================"
    echo "1. 登录DNS服务商管理后台"
    echo "2. 更新 _acme-challenge 的TXT记录值"
    echo "3. 等待1-2分钟DNS生效"
    echo "4. 验证: dig TXT _acme-challenge.example.com"
    echo "5. 重新运行: bash $0 --force"
    exit 1
fi

2.5 设置自动续期定时任务

bash 复制代码
# 编辑 crontab
crontab -e

# 添加以下内容(每月1号凌晨3点检查续期)
0 3 1 * * /root/web/script/renew_cert.sh >> /var/log/cert-renew.log 2>&1

三、企业方案:CSR 证书申请流程

3.1 什么时候需要走企业流程?

以下情况需要使用企业级证书申请流程:

  • ? 公司内部 PKI 系统,需要提交 CSR 给安全团队
  • ? 金融、医疗等行业,需要 OV/EV 级别证书
  • ? 合规要求,证书需要正式审批流程
  • ? 需要证书显示公司名称(OV/EV 特性)

3.2 CSR 是什么?

CSR(Certificate Signing Request)证书签名请求,就像一份"申请书",包含:

  • 你的公钥
  • 域名信息(CN 和 SAN)
  • 组织信息(公司名、部门、城市等)

私钥你自己保留,CSR 提交给 CA,CA 验证后用它的私钥签名,返回正式证书。

3.3 企业证书申请流程图

3.4 首次申请:生成 CSR 并提交

企业级证书申请的第一步是生成 CSR(证书签名请求)。CSR 包含你的公钥和身份信息,提交给 CA 后,CA 会验证并签发证书。

步骤一:准备申请信息

在生成 CSR 之前,需要准备以下信息:

字段 说明 示例
C (Country) 国家代码(两位) CN、US、DE
S (State) 省/州 Beijing、Shanghai
L (Locality) 城市 Beijing、Shenzhen
O (Organization) 公司/组织名称 Your Company Ltd
OU (Organizational Unit) 部门 IT Department
CN (Common Name) 主域名 portal.example.com
SAN (Subject Alternative Name) 所有需要覆盖的域名 多个域名列表
步骤二:生成密钥对和 CSR

以下是完整的 CSR 生成脚本:

bash 复制代码
#!/bin/bash
# ============================================================
# 企业级证书申请脚本 - CSR 生成
# ============================================================

# ========== 配置区域 ==========
PASSWORD="your_secure_password"      # 密钥库密码(妥善保管)
DOMAIN_NAME="example.com"             # 主域名
JKS_FILE="${DOMAIN_NAME}.jks"        # Java KeyStore
PFX_FILE="${DOMAIN_NAME}.pfx"        # PKCS#12 格式
KEY_FILE="${DOMAIN_NAME}.key"        # PEM 私钥
CSR_FILE="${DOMAIN_NAME}.csr"        # 证书签名请求
CERT_ALIAS="server_cert"              # 证书别名

# 证书主题信息(根据实际情况修改)
CN_NAME="portal.example.com"         # 主域名(Common Name)

# SAN 扩展 - 证书覆盖的所有域名
SAN_LIST="dns:portal.example.com,dns:portal.qa.example.com,dns:portal.dev.example.com,dns:api.example.com"

# ========== 步骤1:生成密钥对 ==========
echo ">>> 生成 4096 位 RSA 密钥对..."
keytool -genkey \
    -alias $CERT_ALIAS \
    -keyalg RSA \
    -keysize 4096 \
    -keystore $JKS_FILE \
    -keypass $PASSWORD \
    -storepass $PASSWORD \
    -ext san=$SAN_LIST \
    -dname "C=CN,S=Beijing,L=Beijing,O=YourCompany,OU=IT,CN=$CN_NAME"

# ========== 步骤2:转换为 PKCS#12 格式 ==========
echo ">>> 转换为 PKCS#12 格式..."
keytool -v -importkeystore \
    -srckeystore $JKS_FILE \
    -srcstoretype jks \
    -srcstorepass $PASSWORD \
    -destkeystore $PFX_FILE \
    -deststoretype pkcs12 \
    -deststorepass $PASSWORD \
    -destkeypass $PASSWORD

# ========== 步骤3:提取 PEM 私钥 ==========
echo ">>> 提取 PEM 格式私钥..."
openssl pkcs12 \
    -password pass:$PASSWORD \
    -in $PFX_FILE \
    -nocerts \
    -nodes \
    -out $KEY_FILE

# ========== 步骤4:生成 CSR ==========
echo ">>> 生成证书签名请求..."
keytool -certreq \
    -sigalg SHA256withRSA \
    -storepass $PASSWORD \
    -alias $CERT_ALIAS \
    -keystore $JKS_FILE \
    -file $CSR_FILE \
    -ext san=$SAN_LIST

# ========== 步骤5:验证 CSR ==========
echo ">>> CSR 内容验证:"
openssl req -text -noout -verify -in $CSR_FILE

# ========== 步骤6:打包 ==========
echo ">>> 打包所有文件..."
zip ${DOMAIN_NAME}.zip $JKS_FILE $PFX_FILE $KEY_FILE $CSR_FILE

echo ""
echo "========================================"
echo "  CSR 生成完成!"
echo "========================================"
echo "请将 ${CSR_FILE} 提交给证书管理员"
echo "私钥文件请妥善保管,不要泄露!"

3.5 生成的文件用途

3.6 收到证书后如何导入?

CA 签发后会返回:服务器证书、中间证书、根证书。需要按顺序导入:

bash 复制代码
# 方法1:导入到 JKS(Java 应用)
# 按顺序:根证书 → 中间证书 → 服务器证书
keytool -import -alias root -keystore server.jks -file root.crt -trustcacerts
keytool -import -alias intermediate -keystore server.jks -file intermediate.crt
keytool -import -alias server -keystore server.jks -file server.crt

# 方法2:创建 PEM 证书链(Nginx/Apache)
# 合并服务器证书和中间证书
cat server.crt intermediate.crt > fullchain.crt

# Nginx 配置
# ssl_certificate     /path/to/fullchain.crt;
# ssl_certificate_key /path/to/server.key;

3.7 证书续期:企业证书如何更新

企业级证书通常有效期 1-2 年,到期前需要续期。续期流程与首次申请类似,但有一些注意事项:

续期时机
bash 复制代码
# 检查证书剩余有效期
openssl x509 -in server.crt -noout -dates

# 计算剩余天数
echo "证书将在 $(($(date -d "$(openssl x509 -in server.crt -noout -enddate | cut -d= -f2)" +%s) - $(date +%s))) 秒后过期"

# 建议:证书过期前 30 天开始续期流程
续期方式选择
方式 说明 适用场景
复用私钥 使用原有私钥重新生成 CSR 快速续期,无需重新部署密钥
新建密钥 生成新的密钥对和 CSR 更安全,推荐做法
自动续期 部分 CA 提供自动续期服务 减少运维工作量
续期脚本示例
bash 复制代码
#!/bin/bash
# ============================================================
# 企业级证书续期脚本
# ============================================================

DOMAIN_NAME="example.com"
OLD_CERT="server.crt"
CSR_FILE="renew_${DOMAIN_NAME}.csr"

# 检查证书是否需要续期(30天内过期)
check_renewal() {
    if openssl x509 -in $OLD_CERT -noout -checkend 2592000 2>/dev/null; then
        echo "证书有效期充足,暂不需要续期"
        exit 0
    fi
    echo "证书将在30天内过期,开始续期流程..."
}

# 方式1:复用现有私钥生成 CSR(快速续期)
renew_with_existing_key() {
    # 从现有证书提取公钥信息
    openssl x509 -in $OLD_CERT -noout -text | grep -A1 "Subject Alternative Name"
    
    # 使用现有私钥生成新 CSR
    openssl req -new \
        -key server.key \
        -out $CSR_FILE \
        -subj "/C=CN/ST=Beijing/L=Beijing/O=YourCompany/OU=IT/CN=portal.example.com"
    
    echo "CSR 已生成: $CSR_FILE"
    echo "请提交给证书管理员"
}

# 方式2:生成新的密钥对(推荐)
renew_with_new_key() {
    # 生成新私钥
    openssl genrsa -out server_new.key 4096
    
    # 生成新 CSR
    openssl req -new \
        -key server_new.key \
        -out $CSR_FILE \
        -subj "/C=CN/ST=Beijing/L=Beijing/O=YourCompany/OU=IT/CN=portal.example.com" \
        -addext "subjectAltName=DNS:portal.example.com,DNS:api.example.com"
    
    echo "新密钥和 CSR 已生成"
    echo "私钥: server_new.key (请妥善保管)"
    echo "CSR: $CSR_FILE (提交给证书管理员)"
}

# 执行续期检查
check_renewal

# 选择续期方式
echo "请选择续期方式:"
echo "1) 复用现有私钥(快速)"
echo "2) 生成新密钥对(更安全,推荐)"
read -p "请输入选项 [1/2]: " choice

case $choice in
    1) renew_with_existing_key ;;
    2) renew_with_new_key ;;
    *) echo "无效选项"; exit 1 ;;
esac
续期后部署
bash 复制代码
# 收到新证书后,替换旧证书
cp server.crt server.crt.bak  # 备份旧证书
cp new_server.crt server.crt

# 如果生成了新私钥,也要更新
cp server_new.key server.key

# 验证证书和私钥是否匹配
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# 两个 MD5 值应该相同

# 重启服务
nginx -t && nginx -s reload
# 或
systemctl restart tomcat

四、两种方案对比总结

4.1 一图看懂差异

4.2 如何选择?

你的场景 推荐方案 原因
个人博客、作品集 Let's Encrypt 免费、自动、够用
小团队项目、测试环境 Let's Encrypt 快速部署、零成本
企业官网 OV 证书 显示公司名,更专业
金融、支付系统 EV 证书 最高信任级别
内网系统、企业PKI CSR 模式 符合企业安全规范
需要通配符证书 Let's Encrypt 免费支持通配符

五、实用技巧与常见问题

5.1 证书安全最佳实践

bash 复制代码
# 1. 私钥权限:只有 root 可读
chmod 600 private.key
chown root:root private.key

# 2. 证书权限:所有人可读
chmod 644 server.crt
chown root:root server.crt

# 3. 检查证书有效期
openssl x509 -in server.crt -noout -dates

# 4. 验证证书链完整性
openssl verify -CAfile ca-bundle.crt server.crt

# 5. 查看证书详细信息
openssl x509 -in server.crt -text -noout

5.2 常见问题解答

Q1: 通配符证书为什么必须 DNS 验证?

因为通配符证书覆盖所有子域名,CA 需要验证你对整个域名的控制权。HTTP 验证只能证明你控制某个特定主机,无法证明对整个域名的所有权。

Q2: CSR 可以重复使用吗?

不建议。每次申请新证书时应生成新的 CSR 和新的私钥,这样更安全,也能避免密钥泄露风险。

Q3: 证书链是什么?为什么重要?

浏览器需要完整的信任链来验证证书。如果缺少中间证书,浏览器会报"证书不可信"错误。

Q4: JKS 和 PKCS#12 怎么互转?

bash 复制代码
# JKS → PKCS#12
keytool -importkeystore \
    -srckeystore server.jks -srcstoretype JKS \
    -destkeystore server.p12 -deststoretype PKCS12

# PKCS#12 → JKS
keytool -importkeystore \
    -srckeystore server.p12 -srcstoretype PKCS12 \
    -destkeystore server.jks -deststoretype JKS

Q5: 如何测试 HTTPS 配置?

bash 复制代码
# 测试 SSL 配置
openssl s_client -connect example.com:443 -servername example.com

# 在线测试工具
# https://www.ssllabs.com/ssltest/

六、总结

选择证书方案,就像选择出行方式:

  • ? Let's Encrypt = 骑共享单车,免费、方便、适合短途(个人项目)
  • ? OV 证书 = 开私家车,正式、体面、适合商务(企业官网)
  • ? EV 证书 = 坐头等舱,顶级配置、严格审核(金融电商)

对于大多数个人开发者和小团队,Let's Encrypt 提供的免费自动化方案已经完全够用。企业场景则根据合规要求和信任级别选择合适的证书类型。

记住:私钥是核心机密,证书是公开身份,CSR 是申请书。搞懂这三者的关系,证书管理就不再神秘了。


原文链接: [网站也要身份证:HTTPS 证书申请指南](www.bthlt.com/note/369625... 证书申请指南) 作者: 王梓 | 葫芦的运维日志

相关推荐
stark张宇5 小时前
MySQL 核心内幕:从索引原理、字段选型到日志机制与外键约束,一篇打通数据库任督二脉
数据库·mysql·架构
兆子龙5 小时前
【React】19 深度解析:掌握新一代 React 特性
前端·架构
无双_Joney5 小时前
心路散文 - 转职遇到AI浪潮,AIGC时刻人的价值是什么?
前端·后端·架构
嚴寒7 小时前
前端配环境配到崩溃?这个一键脚手架让我少掉了一把头发
前端·react.js·架构
老迟聊架构7 小时前
说说Vibe Coding的适应范围
人工智能·程序员·架构
看晴天了7 小时前
新框架electronbun项目入门指南,解决electron体积大的难题,Electrobun:Electron 的轻量级革命 —— 12MB 应用 +
前端·架构
sTone873757 小时前
web后端开发概念: VO 和 PO
java·后端·架构
裴云飞7 小时前
Compose原理十一之手势协程化,从回调到挂起的桥接艺术
架构
裴云飞7 小时前
Compose原理十之事件分发
架构