SSL证书完整教程:免费获取与配置指南

作者:痛风少年 发布时间: 2025-12-24 阅读量:8

SSL证书基础知识

什么是SSL证书

SSL(Secure Sockets Layer)证书是一种数字证书,用于:

  • 验证网站身份

  • 加密客户端与服务器之间的数据传输

  • 防止中间人攻击

  • 提升网站SEO排名和用户信任度

SSL证书类型

  1. 域名验证型(DV):验证域名所有权

  2. 组织验证型(OV):验证组织身份

  3. 扩展验证型(EV):最高级别验证

  4. 通配符证书:保护主域名及所有子域名

  5. 多域名证书(SAN):保护多个不同域名

证书格式

  • PEM:文本格式,Base64编码(.pem, .crt, .cer)

  • DER:二进制格式(.der, .cer)

  • PKCS#12:包含私钥和证书(.p12, .pfx)

  • JKS:Java密钥库格式

免费SSL证书提供商

主要免费SSL证书来源

提供商

有效期

自动续期

通配符支持

特点

Let's Encrypt

90天

支持

支持

最流行,完全免费

ZeroSSL

90天

支持

部分支持

提供管理界面

SSL For Free

90天

手动

不支持

基于Let's Encrypt

Cloudflare

永久

自动

支持

需要使用Cloudflare DNS

阿里云免费证书

1年

手动

不支持

每年20个免费额度

腾讯云免费证书

1年

手动

不支持

每年50个免费额度

Let's Encrypt详细教程

Let's Encrypt是目前最受欢迎的免费SSL证书提供商。

使用Certbot(推荐)

1. 安装Certbot

Ubuntu/Debian:

# 更新包管理器
sudo apt update

# 安装snapd
sudo apt install snapd

# 安装certbot
sudo snap install core; sudo snap refresh core
sudo snap install --classic certbot

# 创建软链接
sudo ln -s /snap/bin/certbot /usr/bin/certbot

CentOS/RHEL/Rocky Linux:

# 安装EPEL仓库
sudo dnf install epel-release

# 安装certbot
sudo dnf install certbot python3-certbot-nginx python3-certbot-apache

使用包管理器(较旧方法):

# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx

# CentOS/RHEL
sudo yum install certbot python3-certbot-nginx

2. 获取SSL证书

方法一:Nginx自动配置

# 自动获取证书并配置Nginx
sudo certbot --nginx -d example.com -d www.example.com

# 仅获取证书,不自动配置
sudo certbot certonly --nginx -d example.com -d www.example.com

方法二:Apache自动配置

# 自动获取证书并配置Apache
sudo certbot --apache -d example.com -d www.example.com

方法三:独立模式(Standalone)

# 停止Web服务器
sudo systemctl stop nginx

# 获取证书
sudo certbot certonly --standalone -d example.com -d www.example.com

# 重启Web服务器
sudo systemctl start nginx

方法四:Webroot模式

# 使用现有Web服务器的文档根目录
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com

方法五:DNS验证(通配符证书)

# 手动DNS验证
sudo certbot certonly --manual --preferred-challenges dns -d example.com -d *.example.com

# 使用DNS插件(以Cloudflare为例)
sudo snap install certbot-dns-cloudflare
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/.secrets/cloudflare.ini -d example.com -d *.example.com

3. 自动续期配置

Let's Encrypt证书有效期为90天,需要定期续期。

# 测试续期
sudo certbot renew --dry-run

# 手动续期
sudo certbot renew

# 强制续期
sudo certbot renew --force-renewal

# 续期特定证书
sudo certbot renew --cert-name example.com

设置自动续期:

# 查看现有的cron任务
sudo crontab -l

# 编辑cron任务
sudo crontab -e

# 添加以下行(每天检查两次)
0 12,0 * * * /usr/bin/certbot renew --quiet

使用systemd定时器:

# 检查certbot定时器状态
sudo systemctl status snap.certbot.renew.timer

# 启用定时器
sudo systemctl enable snap.certbot.renew.timer

# 查看定时器详情
sudo systemctl list-timers snap.certbot.renew.timer

使用acme.sh

acme.sh是一个纯Shell实现的ACME客户端。

1. 安装acme.sh

# 安装acme.sh
curl https://get.acme.sh | sh

# 或者使用git安装
git clone https://github.com/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install

# 重新加载shell
source ~/.bashrc

2. 获取证书

HTTP验证:

# 使用Nginx
acme.sh --issue -d example.com -d www.example.com --nginx

# 使用Apache
acme.sh --issue -d example.com -d www.example.com --apache

# 使用Webroot
acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html

DNS验证:

# 手动DNS验证
acme.sh --issue --dns -d example.com -d www.example.com

# 自动DNS验证(Cloudflare)
export CF_Key="your-cloudflare-api-key"
export CF_Email="your-email@example.com"
acme.sh --issue --dns dns_cf -d example.com -d *.example.com

# 阿里云DNS
export Ali_Key="your-ali-key"
export Ali_Secret="your-ali-secret"
acme.sh --issue --dns dns_ali -d example.com -d *.example.com

3. 安装证书

# 安装到Nginx
acme.sh --install-cert -d example.com \
--key-file       /etc/nginx/ssl/example.com.key  \
--fullchain-file /etc/nginx/ssl/example.com.pem \
--reloadcmd     "systemctl reload nginx"

# 安装到Apache
acme.sh --install-cert -d example.com \
--cert-file      /etc/httpd/ssl/example.com.cer  \
--key-file       /etc/httpd/ssl/example.com.key  \
--fullchain-file /etc/httpd/ssl/example.com.pem \
--reloadcmd     "systemctl reload httpd"

使用Docker获取Let's Encrypt证书

1. 使用官方Certbot Docker镜像

# 获取证书(独立模式)
docker run -it --rm --name certbot \
-p 80:80 -p 443:443 \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
certbot/certbot certonly --standalone -d example.com

# 使用Webroot模式
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
-v "/var/www/html:/var/www/html" \
certbot/certbot certonly --webroot -w /var/www/html -d example.com

# 续期证书
docker run -it --rm --name certbot \
-v "/etc/letsencrypt:/etc/letsencrypt" \
-v "/var/lib/letsencrypt:/var/lib/letsencrypt" \
certbot/certbot renew

2. 使用docker-compose

创建 docker-compose.yml

version: '3.8'

services:
  certbot:
    image: certbot/certbot:latest
    container_name: certbot
    volumes:
      - ./certbot/etc:/etc/letsencrypt
      - ./certbot/var:/var/lib/letsencrypt
      - ./certbot/logs:/var/log/letsencrypt
      - ./html:/var/www/html
    command: certonly --webroot -w /var/www/html -d example.com --email your-email@example.com --agree-tos --no-eff-email

  nginx:
    image: nginx:alpine
    container_name: nginx
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./html:/var/www/html
      - ./certbot/etc:/etc/letsencrypt:ro
    restart: unless-stopped

其他免费SSL证书获取方法

ZeroSSL

1. 使用ZeroSSL网页界面

  1. 访问 https://zerossl.com

  2. 注册账号并登录

  3. 点击"New Certificate"

  4. 输入域名

  5. 选择验证方式(HTTP、DNS、Email)

  6. 完成验证

  7. 下载证书

2. 使用acme.sh客户端

# 设置ZeroSSL为默认CA
acme.sh --set-default-ca --server zerossl

# 获取证书
acme.sh --register-account -m your-email@example.com --server zerossl
acme.sh --issue -d example.com --nginx --server zerossl

Cloudflare SSL

1. 启用Cloudflare SSL

  1. 将域名添加到Cloudflare

  2. 更改域名DNS服务器到Cloudflare

  3. 在SSL/TLS设置中启用SSL

  4. 选择加密模式(推荐"Full (strict)")

2. 获取Origin证书

# 在Cloudflare面板中:
# SSL/TLS -> Origin Server -> Create Certificate

云服务商免费SSL证书

阿里云免费SSL证书

  1. 登录阿里云控制台

  2. 进入"SSL证书"服务

  3. 选择"免费证书"

  4. 填写域名信息

  5. 选择验证方式

  6. 完成验证并下载证书

腾讯云免费SSL证书

  1. 登录腾讯云控制台

  2. 进入"SSL证书"服务

  3. 申请免费证书

  4. 提交域名验证

  5. 下载证书

使用ACME客户端脚本

创建简单的证书获取脚本

#!/bin/bash
# get-ssl-cert.sh

DOMAIN="example.com"
EMAIL="your-email@example.com"
WEBROOT="/var/www/html"

# 停止Web服务器
systemctl stop nginx

# 获取证书
certbot certonly \
  --standalone \
  --email $EMAIL \
  --agree-tos \
  --no-eff-email \
  --domains $DOMAIN

# 启动Web服务器
systemctl start nginx

# 检查证书
openssl x509 -in /etc/letsencrypt/live/$DOMAIN/fullchain.pem -text -noout

自签名证书

自签名证书适用于开发环境和内网使用。

使用OpenSSL创建自签名证书

1. 生成私钥

# 生成RSA私钥
openssl genrsa -out private.key 2048

# 生成带密码保护的私钥
openssl genrsa -aes256 -out private.key 2048

# 生成椭圆曲线私钥
openssl ecparam -genkey -name secp384r1 -out private.key

2. 创建证书签名请求(CSR)

# 交互式创建CSR
openssl req -new -key private.key -out certificate.csr

# 非交互式创建CSR
openssl req -new -key private.key -out certificate.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com"

3. 生成自签名证书

# 简单自签名证书
openssl x509 -req -days 365 -in certificate.csr -signkey private.key -out certificate.crt

# 包含SAN(Subject Alternative Names)的证书
openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -config <(
cat <<EOF
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no

[req_distinguished_name]
C = CN
ST = Beijing
L = Beijing
O = MyCompany
CN = example.com

[v3_req]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = example.com
DNS.2 = www.example.com
DNS.3 = api.example.com
IP.1 = 192.168.1.100
EOF
)

4. 一步生成私钥和证书

# 生成自签名证书和私钥
openssl req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes

# 通配符证书
openssl req -x509 -newkey rsa:2048 -keyout wildcard.key -out wildcard.crt -days 365 -nodes -subj "/CN=*.example.com"

创建本地CA

1. 创建根CA

# 生成CA私钥
openssl genrsa -aes256 -out ca.key 4096

# 生成CA证书
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/C=CN/ST=Beijing/L=Beijing/O=Local CA/CN=Local CA"

2. 使用CA签发证书

# 生成服务器私钥
openssl genrsa -out server.key 2048

# 生成证书签名请求
openssl req -new -key server.key -out server.csr -subj "/C=CN/ST=Beijing/L=Beijing/O=MyCompany/CN=example.com"

# 使用CA签发证书
openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

# 验证证书
openssl verify -CAfile ca.crt server.crt

SSL证书配置

Nginx配置

基础SSL配置

server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;

    # SSL证书配置
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # SSL参数配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # SSL会话配置
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 安全头部
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header X-XSS-Protection "1; mode=block" always;

    # DH参数
    ssl_dhparam /etc/nginx/dhparam.pem;

    location / {
        root /var/www/html;
        index index.html index.htm;
    }
}

生成DH参数

# 生成强DH参数(可能需要较长时间)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048

Apache配置

基础SSL配置

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    Redirect permanent / https://example.com/
</VirtualHost>

<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    DocumentRoot /var/www/html

    # SSL配置
    SSLEngine on
    SSLCertificateFile /etc/letsencrypt/live/example.com/cert.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    SSLCertificateChainFile /etc/letsencrypt/live/example.com/chain.pem

    # SSL协议和加密套件
    SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
    SSLCipherSuite 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
    SSLHonorCipherOrder off
    SSLSessionTickets off

    # HSTS
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"

    # OCSP Stapling
    SSLUseStapling on
    SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
</VirtualHost>

Docker容器SSL配置

Nginx + SSL Docker配置

FROM nginx:alpine

# 复制SSL证书
COPY certs/ /etc/nginx/certs/

# 复制Nginx配置
COPY nginx.conf /etc/nginx/nginx.conf

# 暴露端口
EXPOSE 80 443

CMD ["nginx", "-g", "daemon off;"]

docker-compose with SSL

version: '3.8'

services:
  nginx:
    image: nginx:alpine
    container_name: nginx-ssl
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./html:/var/www/html
      - /etc/letsencrypt:/etc/letsencrypt:ro
    restart: unless-stopped

  certbot:
    image: certbot/certbot
    container_name: certbot
    volumes:
      - /etc/letsencrypt:/etc/letsencrypt
      - ./html:/var/www/html
    command: ["--version"]
    profiles: ["certbot"]

证书管理与维护

证书信息查看

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

# 查看证书有效期
openssl x509 -in certificate.crt -noout -dates

# 查看证书主题
openssl x509 -in certificate.crt -noout -subject

# 查看证书指纹
openssl x509 -in certificate.crt -noout -fingerprint -sha256

# 检查远程服务器证书
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | openssl x509 -text -noout

# 检查证书和私钥是否匹配
openssl x509 -noout -modulus -in certificate.crt | openssl md5
openssl rsa -noout -modulus -in private.key | openssl md5

证书格式转换

# PEM转DER
openssl x509 -in certificate.crt -outform DER -out certificate.der

# DER转PEM
openssl x509 -in certificate.der -inform DER -outform PEM -out certificate.crt

# 创建PKCS#12文件
openssl pkcs12 -export -in certificate.crt -inkey private.key -out certificate.p12

# 从PKCS#12提取证书和私钥
openssl pkcs12 -in certificate.p12 -clcerts -nokeys -out certificate.crt
openssl pkcs12 -in certificate.p12 -nocerts -nodes -out private.key

批量证书管理脚本

#!/bin/bash
# ssl-manager.sh - SSL证书管理脚本

CERT_DIR="/etc/letsencrypt/live"
LOG_FILE="/var/log/ssl-manager.log"
EMAIL="admin@example.com"

# 日志函数
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a $LOG_FILE
}

# 检查证书过期时间
check_expiry() {
    local domain=$1
    local cert_file="$CERT_DIR/$domain/cert.pem"
    
    if [[ -f $cert_file ]]; then
        local expiry_date=$(openssl x509 -in $cert_file -noout -enddate | cut -d= -f2)
        local expiry_epoch=$(date -d "$expiry_date" +%s)
        local current_epoch=$(date +%s)
        local days_left=$(( (expiry_epoch - current_epoch) / 86400 ))
        
        log "$domain 证书剩余 $days_left 天"
        
        if [[ $days_left -lt 30 ]]; then
            log "警告: $domain 证书将在 $days_left 天内过期"
            echo "$domain 证书将在 $days_left 天内过期" | mail -s "SSL证书过期警告" $EMAIL
        fi
    else
        log "错误: 未找到 $domain 的证书文件"
    fi
}

# 自动续期
renew_certificates() {
    log "开始自动续期证书"
    certbot renew --quiet --no-self-upgrade
    
    if [[ $? -eq 0 ]]; then
        log "证书续期成功"
        systemctl reload nginx
    else
        log "证书续期失败"
        echo "证书续期失败,请检查日志" | mail -s "SSL证书续期失败" $EMAIL
    fi
}

# 获取新证书
get_certificate() {
    local domain=$1
    local webroot=$2
    
    log "为 $domain 获取新证书"
    certbot certonly --webroot -w $webroot -d $domain --email $EMAIL --agree-tos --no-eff-email
    
    if [[ $? -eq 0 ]]; then
        log "$domain 证书获取成功"
        systemctl reload nginx
    else
        log "$domain 证书获取失败"
    fi
}

# 主函数
main() {
    case $1 in
        check)
            if [[ -n $2 ]]; then
                check_expiry $2
            else
                for domain_dir in $CERT_DIR/*/; do
                    domain=$(basename $domain_dir)
                    check_expiry $domain
                done
            fi
            ;;
        renew)
            renew_certificates
            ;;
        get)
            if [[ -n $2 && -n $3 ]]; then
                get_certificate $2 $3
            else
                echo "用法: $0 get <domain> <webroot>"
                exit 1
            fi
            ;;
        *)
            echo "用法: $0 {check|renew|get} [domain] [webroot]"
            echo "  check [domain] - 检查证书过期时间"
            echo "  renew          - 续期所有证书"
            echo "  get <domain> <webroot> - 获取新证书"
            exit 1
            ;;
    esac
}

main "$@"

故障排除

常见问题及解决方案

1. Let's Encrypt速率限制

# 错误信息:too many certificates already issued
# 解决方案:
# 1. 使用测试环境
certbot --staging -d example.com

# 2. 等待一周后重试
# 3. 使用不同的域名变体

2. DNS验证失败

# 检查DNS记录
dig _acme-challenge.example.com TXT

# 等待DNS传播
host _acme-challenge.example.com

# 手动添加DNS记录后重试
certbot --manual --preferred-challenges dns -d example.com

3. 证书链不完整

# 检查证书链
openssl s_client -connect example.com:443 -servername example.com

# 使用完整证书链
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;

4. 权限问题

# 设置正确的证书权限
sudo chown -R root:ssl-cert /etc/letsencrypt/
sudo chmod -R 640 /etc/letsencrypt/archive/
sudo chmod -R 644 /etc/letsencrypt/live/

证书验证工具

SSL Labs测试

# 使用SSL Labs API测试
curl "https://api.ssllabs.com/api/v3/analyze?host=example.com"

本地证书测试

#!/bin/bash
# test-ssl.sh - SSL配置测试脚本

DOMAIN=$1

if [[ -z $DOMAIN ]]; then
    echo "用法: $0 <domain>"
    exit 1
fi

echo "测试 $DOMAIN 的SSL配置..."

# 检查证书有效性
echo "=== 证书信息 ==="
echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -text | grep -A3 "Validity"

# 检查证书链
echo "=== 证书链验证 ==="
echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -issuer

# 检查支持的TLS版本
echo "=== TLS版本支持 ==="
for version in ssl3 tls1 tls1_1 tls1_2 tls1_3; do
    echo -n "Testing $version: "
    echo | timeout 3 openssl s_client -connect $DOMAIN:443 -servername $DOMAIN -$version 2>/dev/null
    if [[ $? -eq 0 ]]; then
        echo "支持"
    else
        echo "不支持"
    fi
done

# 检查证书过期时间
echo "=== 证书过期时间 ==="
echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -dates

# 检查HSTS头部
echo "=== HSTS检查 ==="
curl -I https://$DOMAIN 2>/dev/null | grep -i strict-transport-security

echo "SSL配置测试完成"

最佳实践

安全配置建议

1. 使用强加密算法

# 推荐的Nginx SSL配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;

2. 启用安全头部

# 安全头部配置
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;

3. 证书透明度监控

#!/bin/bash
# ct-monitor.sh - 证书透明度监控脚本

DOMAIN="example.com"
CT_LOG_URL="https://crt.sh/?q=${DOMAIN}&output=json"

# 获取最新证书信息
latest_cert=$(curl -s "$CT_LOG_URL" | jq -r '.[0] | .id')

if [[ $latest_cert != "null" ]]; then
    echo "发现新证书: $latest_cert"
    # 发送通知
    curl -X POST -H 'Content-type: application/json' \
        --data "{\"text\":\"域名 $DOMAIN 发现新证书: $latest_cert\"}" \
        YOUR_WEBHOOK_URL
fi

自动化部署流程

完整的SSL自动化脚本

#!/bin/bash
# ssl-automation.sh - SSL证书自动化部署脚本

set -euo pipefail

# 配置变量
DOMAIN="${1:-example.com}"
EMAIL="${2:-admin@example.com}"
WEBROOT="${3:-/var/www/html}"
NGINX_CONFIG="/etc/nginx/sites-available/$DOMAIN"
BACKUP_DIR="/backup/ssl"

# 日志函数
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a /var/log/ssl-automation.log
}

# 创建备份
backup_config() {
    log "备份当前配置..."
    mkdir -p $BACKUP_DIR
    cp $NGINX_CONFIG $BACKUP_DIR/nginx_${DOMAIN}_$(date +%Y%m%d_%H%M%S).conf
}

# 检查域名解析
check_dns() {
    log "检查域名解析..."
    if ! dig +short $DOMAIN | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+ > /dev/null; then
        log "错误: 域名 $DOMAIN 解析失败"
        exit 1
    fi
    log "域名解析正常"
}

# 获取SSL证书
get_certificate() {
    log "获取SSL证书..."
    
    # 检查是否已有证书
    if [[ -f "/etc/letsencrypt/live/$DOMAIN/fullchain.pem" ]]; then
        log "证书已存在,检查是否需要续期..."
        certbot renew --cert-name $DOMAIN --deploy-hook "systemctl reload nginx"
    else
        log "获取新证书..."
        certbot certonly \
            --webroot \
            -w $WEBROOT \
            -d $DOMAIN \
            -d www.$DOMAIN \
            --email $EMAIL \
            --agree-tos \
            --no-eff-email \
            --deploy-hook "systemctl reload nginx"
    fi
}

# 配置Nginx
configure_nginx() {
    log "配置Nginx SSL..."
    
    cat > $NGINX_CONFIG << EOF
# HTTP重定向到HTTPS
server {
    listen 80;
    server_name $DOMAIN www.$DOMAIN;
    return 301 https://\$server_name\$request_uri;
}

# HTTPS配置
server {
    listen 443 ssl http2;
    server_name $DOMAIN www.$DOMAIN;

    # 网站根目录
    root $WEBROOT;
    index index.html index.htm index.php;

    # SSL证书配置
    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/$DOMAIN/chain.pem;

    # SSL参数
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
    ssl_prefer_server_ciphers off;

    # SSL会话
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets off;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;
    resolver_timeout 5s;

    # 安全头部
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options nosniff always;
    add_header X-Frame-Options DENY always;
    add_header X-XSS-Protection "1; mode=block" always;

    # Let's Encrypt验证
    location /.well-known/acme-challenge/ {
        root $WEBROOT;
    }

    # 主要内容
    location / {
        try_files \$uri \$uri/ =404;
    }

    # PHP支持(如果需要)
    location ~ \.php\$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    }

    # 静态文件缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }
}
EOF

    # 测试配置
    nginx -t
    
    if [[ $? -eq 0 ]]; then
        log "Nginx配置测试通过"
        # 启用站点
        ln -sf $NGINX_CONFIG /etc/nginx/sites-enabled/
        systemctl reload nginx
        log "Nginx配置已重载"
    else
        log "错误: Nginx配置测试失败"
        exit 1
    fi
}

# 验证SSL配置
verify_ssl() {
    log "验证SSL配置..."
    
    # 等待服务启动
    sleep 5
    
    # 检查HTTPS连接
    if curl -s --max-time 10 https://$DOMAIN > /dev/null; then
        log "HTTPS连接正常"
    else
        log "错误: HTTPS连接失败"
        exit 1
    fi
    
    # 检查证书有效性
    expiry_date=$(echo | openssl s_client -connect $DOMAIN:443 -servername $DOMAIN 2>/dev/null | openssl x509 -noout -enddate | cut -d= -f2)
    log "证书有效期至: $expiry_date"
}

# 设置监控
setup_monitoring() {
    log "设置证书监控..."
    
    # 创建监控脚本
    cat > /usr/local/bin/ssl-monitor-$DOMAIN.sh << EOF
#!/bin/bash
DOMAIN="$DOMAIN"
CERT_FILE="/etc/letsencrypt/live/\$DOMAIN/cert.pem"
EMAIL="$EMAIL"

if [[ -f \$CERT_FILE ]]; then
    EXPIRY=\$(openssl x509 -in \$CERT_FILE -noout -enddate | cut -d= -f2)
    EXPIRY_EPOCH=\$(date -d "\$EXPIRY" +%s)
    CURRENT_EPOCH=\$(date +%s)
    DAYS_LEFT=\$(( (EXPIRY_EPOCH - CURRENT_EPOCH) / 86400 ))
    
    if [[ \$DAYS_LEFT -lt 30 ]]; then
        echo "警告: \$DOMAIN SSL证书将在 \$DAYS_LEFT 天内过期" | mail -s "SSL证书过期警告" \$EMAIL
    fi
fi
EOF
    
    chmod +x /usr/local/bin/ssl-monitor-$DOMAIN.sh
    
    # 添加到crontab
    (crontab -l 2>/dev/null; echo "0 6 * * * /usr/local/bin/ssl-monitor-$DOMAIN.sh") | crontab -
    
    log "证书监控已设置"
}

# 主函数
main() {
    log "开始SSL自动化部署: $DOMAIN"
    
    # 检查依赖
    command -v certbot >/dev/null 2>&1 || { log "错误: certbot未安装"; exit 1; }
    command -v nginx >/dev/null 2>&1 || { log "错误: nginx未安装"; exit 1; }
    
    # 执行部署步骤
    backup_config
    check_dns
    get_certificate
    configure_nginx
    verify_ssl
    setup_monitoring
    
    log "SSL自动化部署完成!"
    log "访问 https://$DOMAIN 验证配置"
}

# 脚本入口
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi

多域名批量部署

#!/bin/bash
# batch-ssl-deploy.sh - 批量SSL部署脚本

DOMAINS_FILE="domains.txt"
EMAIL="admin@example.com"
WEBROOT="/var/www/html"
LOG_FILE="/var/log/batch-ssl-deploy.log"

# 域名配置文件格式:
# domain.com,/var/www/domain1
# example.org,/var/www/domain2

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}

deploy_domain() {
    local domain=$1
    local webroot=$2
    
    log "开始部署 $domain"
    
    # 获取证书
    certbot certonly \
        --webroot \
        -w $webroot \
        -d $domain \
        -d www.$domain \
        --email $EMAIL \
        --agree-tos \
        --no-eff-email \
        --non-interactive
    
    if [[ $? -eq 0 ]]; then
        log "$domain 证书获取成功"
        
        # 生成Nginx配置
        generate_nginx_config $domain $webroot
        
        # 测试并重载配置
        if nginx -t; then
            systemctl reload nginx
            log "$domain Nginx配置已更新"
        else
            log "错误: $domain Nginx配置测试失败"
        fi
    else
        log "错误: $domain 证书获取失败"
    fi
}

generate_nginx_config() {
    local domain=$1
    local webroot=$2
    local config_file="/etc/nginx/sites-available/$domain"
    
    cat > $config_file << EOF
server {
    listen 80;
    server_name $domain www.$domain;
    return 301 https://\$server_name\$request_uri;
}

server {
    listen 443 ssl http2;
    server_name $domain www.$domain;
    root $webroot;
    index index.html index.htm;

    ssl_certificate /etc/letsencrypt/live/$domain/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$domain/privkey.pem;
    
    include /etc/nginx/snippets/ssl-params.conf;
    
    location / {
        try_files \$uri \$uri/ =404;
    }
}
EOF
    
    ln -sf $config_file /etc/nginx/sites-enabled/
}

# 创建SSL参数片段
create_ssl_snippet() {
    cat > /etc/nginx/snippets/ssl-params.conf << EOF
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;

add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options nosniff always;
add_header X-Frame-Options DENY always;
add_header X-XSS-Protection "1; mode=block" always;
EOF
}

main() {
    log "开始批量SSL部署"
    
    if [[ ! -f $DOMAINS_FILE ]]; then
        log "错误: 域名配置文件 $DOMAINS_FILE 不存在"
        exit 1
    fi
    
    create_ssl_snippet
    
    while IFS=',' read -r domain webroot; do
        # 跳过空行和注释
        [[ $domain =~ ^#.*$ ]] && continue
        [[ -z $domain ]] && continue
        
        # 使用默认webroot(如果未指定)
        [[ -z $webroot ]] && webroot=$WEBROOT
        
        deploy_domain "$domain" "$webroot"
        
        # 等待一段时间避免速率限制
        sleep 10
        
    done < $DOMAINS_FILE
    
    log "批量SSL部署完成"
}

main "$@"

生产环境部署检查清单

SSL部署检查清单

## SSL证书部署检查清单

### 部署前检查
- [ ] 域名DNS解析正确
- [ ] Web服务器配置正确
- [ ] 防火墙端口80/443开放
- [ ] 备份现有配置

### 证书获取
- [ ] 选择合适的证书提供商
- [ ] 验证域名所有权
- [ ] 下载完整证书链
- [ ] 验证私钥和证书匹配

### 服务器配置
- [ ] 配置SSL/TLS协议版本
- [ ] 设置安全的加密套件
- [ ] 启用HSTS
- [ ] 配置OCSP Stapling
- [ ] 添加安全头部

### 部署后验证
- [ ] HTTPS连接正常
- [ ] HTTP自动重定向到HTTPS
- [ ] 证书链完整
- [ ] SSL Labs评级A+
- [ ] 移动端兼容性测试

### 监控和维护
- [ ] 设置证书过期监控
- [ ] 配置自动续期
- [ ] 定期安全扫描
- [ ] 备份证书和私钥

总结

本教程涵盖了SSL证书的完整生命周期管理,从获取免费证书到生产环境部署。主要要点包括:

免费SSL证书推荐方案

  • 个人网站: Let's Encrypt + Certbot

  • 企业应用: Let's Encrypt + acme.sh + 自动化脚本

  • 快速部署: 云服务商免费证书

  • 开发测试: 自签名证书

关键最佳实践

  1. 自动化: 使用脚本自动获取和续期证书

  2. 监控: 设置证书过期提醒和健康检查

  3. 安全: 使用强加密配置和安全头部

  4. 备份: 定期备份证书和配置文件

常用工具对比

  • Certbot: 官方推荐,功能完整

  • acme.sh: 轻量级,支持更多DNS提供商

  • 云服务: 简单易用,与云平台集成好

选择合适的方案并按照本教程的步骤进行部署,可以确保网站的安全性和可靠性。记住定期检查和更新SSL配置,保持与最新安全标准同步。