#!/bin/bash
# 自签发SSL证书生成脚本(含加密私钥+密码文件)
# 特点:生成加密私钥时,自动创建密码文件(.key.pass),方便后续配置

###########################################################
# 【核心配置 - 请修改】
###########################################################
KEY_PASSWORD="my_secure_password"  # 私钥加密密码(必须修改!)
DOMAIN="example.com"               # 你的域名
VALID_DAYS=365                     # 有效期(天)
KEY_SIZE=2048                      # 密钥长度(2048/4096)
ENCRYPT_KEY=false                  # 是否加密私钥(true=加密,false=不加密)
OUTPUT_PREFIX="${DOMAIN}"          # 输出文件前缀(默认用域名)

# 证书信息(可选修改)
COUNTRY="CN"
STATE="Beijing"
CITY="Haidian"
ORGANIZATION="MyOrg"
ORG_UNIT="IT"
EMAIL="admin@${DOMAIN}"


###########################################################
# 【文件路径定义】
###########################################################
KEY_FILE="${OUTPUT_PREFIX}.key"        # 加密私钥文件
CRT_FILE="${OUTPUT_PREFIX}.crt"        # 证书文件
PASS_FILE="${OUTPUT_PREFIX}.key.pass"  # 密码文件(仅加密时生成)
CSR_FILE="${OUTPUT_PREFIX}.csr"        # 中间文件(生成后删除)


###########################################################
# 【帮助信息】
###########################################################
show_help() {
    echo "用法: $0 [选项]"
    echo "生成自签发证书,加密私钥时会同时生成密码文件(.key.pass)"
    echo "选项:"
    echo "  -d  域名(覆盖默认DOMAIN)"
    echo "  -y  有效期天数(覆盖VALID_DAYS)"
    echo "  -s  密钥长度(覆盖KEY_SIZE)"
    echo "  -e  启用私钥加密(强制生成密码文件)"
    echo "  -o  输出文件前缀(覆盖OUTPUT_PREFIX)"
    echo "  -h  显示帮助"
}


###########################################################
# 【解析参数】
###########################################################
while [[ $# -gt 0 ]]; do
    case "$1" in
        -d) DOMAIN="$2"; OUTPUT_PREFIX="$2"; shift 2 ;;
        -y) VALID_DAYS="$2"; shift 2 ;;
        -s) KEY_SIZE="$2"; shift 2 ;;
        -e) ENCRYPT_KEY=true; shift ;;
        -o) OUTPUT_PREFIX="$2"; shift 2 ;;
        -h) show_help; exit 0 ;;
        *) echo "未知选项: $1"; show_help; exit 1 ;;
    esac
done


###########################################################
# 【检查依赖】
###########################################################
if ! command -v openssl &> /dev/null; then
    echo "错误:请先安装openssl(yum install openssl 或 apt install openssl)"
    exit 1
fi


###########################################################
# 【生成加密私钥+密码文件(核心逻辑)】
###########################################################
echo "生成私钥文件: $KEY_FILE ..."
if [ "$ENCRYPT_KEY" = true ]; then
    # 生成加密私钥 -aes256 -des3 可修改替换加密方式
    openssl genrsa -aes256 -passout pass:"${KEY_PASSWORD}" -out "$KEY_FILE" "$KEY_SIZE"
    
    # 生成密码文件(仅加密时创建),并设置安全权限(仅所有者可读写)
    echo "${KEY_PASSWORD}" > "$PASS_FILE"
    chmod 600 "$PASS_FILE"  # 关键:限制权限,避免其他用户读取密码
else
    # 生成非加密私钥(不生成密码文件)
    openssl genrsa -out "$KEY_FILE" "$KEY_SIZE"
fi

# 检查私钥是否生成成功
if [ $? -ne 0 ] || [ ! -f "$KEY_FILE" ]; then
    echo "错误:私钥文件生成失败"
    rm -f "$PASS_FILE"  # 清理可能残留的密码文件
    exit 1
fi


###########################################################
# 【生成证书】
###########################################################
echo "生成证书签名请求(CSR)..."
if [ "$ENCRYPT_KEY" = true ]; then
    openssl req -new -key "$KEY_FILE" -passin pass:"${KEY_PASSWORD}" \
        -out "$CSR_FILE" \
        -subj "/C=${COUNTRY}/ST=${STATE}/L=${CITY}/O=${ORGANIZATION}/OU=${ORG_UNIT}/CN=${DOMAIN}/emailAddress=${EMAIL}"
else
    openssl req -new -key "$KEY_FILE" -out "$CSR_FILE" \
        -subj "/C=${COUNTRY}/ST=${STATE}/L=${CITY}/O=${ORGANIZATION}/OU=${ORG_UNIT}/CN=${DOMAIN}/emailAddress=${EMAIL}"
fi

if [ $? -ne 0 ]; then
    echo "错误:CSR生成失败,已清理文件"
    rm -f "$KEY_FILE" "$PASS_FILE"
    exit 1
fi


echo "生成自签名证书: $CRT_FILE ..."
if [ "$ENCRYPT_KEY" = true ]; then
    openssl x509 -req -days "$VALID_DAYS" -in "$CSR_FILE" \
        -signkey "$KEY_FILE" -passin pass:"${KEY_PASSWORD}" \
        -out "$CRT_FILE"
else
    openssl x509 -req -days "$VALID_DAYS" -in "$CSR_FILE" \
        -signkey "$KEY_FILE" -out "$CRT_FILE"
fi

if [ $? -ne 0 ] || [ ! -f "$CRT_FILE" ]; then
    echo "错误:证书生成失败,已清理文件"
    rm -f "$KEY_FILE" "$CRT_FILE" "$PASS_FILE"
    exit 1
fi


###########################################################
# 【清理与输出结果】
###########################################################
rm -f "$CSR_FILE"  # 只删除中间文件

echo "----------------------------------------"
echo "生成成功!以下文件已保存:"
echo "1. 私钥文件: $KEY_FILE"
if [ "$ENCRYPT_KEY" = true ]; then
    echo "   (已加密)"
    echo "2. 密码文件: $PASS_FILE"
    echo "   (权限已设置为600,仅所有者可读写)"
else
    echo "   (未加密,无密码文件)"
fi
echo "3. 证书文件: $CRT_FILE"
echo "----------------------------------------"
echo "后续配置示例(以Nginx为例):"
if [ "$ENCRYPT_KEY" = true ]; then
    echo "server {"
    echo "    listen 443 ssl;"
    echo "    server_name $DOMAIN;"
    echo "    ssl_certificate     $CRT_FILE;"
    echo "    ssl_certificate_key $KEY_FILE;"
    echo "    ssl_password_file   $PASS_FILE;  # 自动读取密码,无需手动输入"
    echo "}"
fi

第一步:准备脚本并修改核心配置(最关键)
保存脚本:把脚本复制到服务器,用 vim 或 nano 保存为 generate_ssl.sh(比如用 vim generate_ssl.sh,粘贴内容后按 ESC 输入 :wq 保存)。
修改必须配置的参数:打开脚本,找到「核心配置」部分,必须修改以下 2 项(其他项可选):

KEY_PASSWORD="my_secure_password"  # 把这里改成你的密码(比如 "mypass_2024",越复杂越好)
DOMAIN="example.com"               # 改成你的域名(比如 "test.com"、"api.mydomain.com")

其他可选配置(根据需要改):
VALID_DAYS=365:证书有效期(比如改 730 为 2 年)
KEY_SIZE=2048:密钥长度(4096 更安全,可选)
ENCRYPT_KEY=false:默认不加密,想默认加密可以改成 true

第二步:赋予脚本执行权限
脚本需要 “可执行” 权限才能运行,在服务器上执行以下命令:
chmod +x generate_ssl.sh

第三步:运行脚本(3 种常用场景)
根据是否需要加密私钥(以及是否生成密码文件),有 3 种常用运行方式:

场景 1:生成加密私钥 + 密码文件(推荐,最常用)
如果需要加密私钥,并且自动生成密码文件(方便后续配置),运行时加 -e 参数:

./generate_ssl.sh -e
运行后会看到类似输出:
plaintext
生成私钥文件: example.com.key ...
生成证书签名请求(CSR)...
生成自签名证书: example.com.crt ...
----------------------------------------
生成成功!以下文件已保存:
1. 私钥文件: example.com.key(已加密)
2. 密码文件: example.com.key.pass(权限已设置为600,仅所有者可读写)
3. 证书文件: example.com.crt
----------------------------------------
后续配置示例(以Nginx为例):
server {
    listen 443 ssl;
    server_name example.com;
    ssl_certificate     example.com.crt;
    ssl_certificate_key example.com.key;
    ssl_password_file   example.com.key.pass;  # 自动读取密码,无需手动输入
}


场景 2:自定义域名 / 有效期等参数(临时修改)
如果想临时改域名、有效期,不需要修改脚本,直接用参数覆盖即可。例如:生成 blog.test.com 的证书,有效期 1 年(365 天),4096 位密钥,且加密私钥:
./generate_ssl.sh -d blog.test.com -y 365 -s 4096 -e

参数说明:
-d:指定域名(覆盖脚本中的 DOMAIN)
-y:有效期天数(覆盖 VALID_DAYS)
-s:密钥长度(覆盖 KEY_SIZE)
-e:启用加密(强制生成密码文件)

场景 3:生成不加密的私钥(无需密码文件)
如果不需要加密私钥(比如测试环境临时用),直接运行脚本(不加 -e):
./generate_ssl.sh

此时不会生成密码文件,输出中会显示 “未加密,无密码文件”。

第四步:验证生成的文件
运行脚本后,会在当前目录生成以下文件(以 example.com 为例):
文件名    作用    权限(重要)
example.com.key    加密的私钥文件    默认 -rw-r--r--
example.com.key.pass    私钥的密码文件    已自动设置为 rw-------(600 权限,仅你能读写)
example.com.crt    自签名证书文件    默认 -rw-r--r--
检查文件是否存在:运行 ls 命令查看:

ls example.com.*  # 替换成你的域名前缀
检查密码文件权限(确保安全):

ls -l example.com.key.pass
输出应显示 rw-------(只有你能读写,其他人无权访问)。

第五步:后续配置(以 Nginx 为例,自动加载密码)
生成的文件可以直接用于 Nginx、Apache 等服务器,这里以 Nginx 为例,教你如何配置(无需手动输入密码):
把文件放到服务器证书目录(推荐,方便管理):

# 创建证书目录(如果没有)
mkdir -p /etc/nginx/ssl
# 移动文件到目录
mv example.com.key example.com.key.pass example.com.crt /etc/nginx/ssl/
修改 Nginx 配置文件(比如 /etc/nginx/conf.d/default.conf):加入以下 SSL 配置(关键是引用 3 个文件):

nginx
server {
    listen 443 ssl;
    server_name example.com;  # 你的域名

    # 引用证书文件
    ssl_certificate     /etc/nginx/ssl/example.com.crt;
    # 引用加密私钥文件
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    # 引用密码文件(自动读取密码,无需手动输入)
    ssl_password_file   /etc/nginx/ssl/example.com.key.pass;

    # 可选:添加SSL安全配置
    ssl_protocols TLSv1.2 TLSv1.3;  # 支持的TLS版本
    ssl_ciphers HIGH:!aNULL:!MD5;   # 加密算法
}
验证 Nginx 配置并重启:

nginx -t  # 检查配置是否正确
systemctl restart nginx  # 重启Nginx
此时 Nginx 会自动读取密码文件,启动时不会提示输入密码,直接运行~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐