# NGINX 指令 ssl_password_file 配置详解
Date: 2024-12-03


`ssl_password_file` 是 NGINX 中的一个指令，用于指定一个包含密码的文件，这个文件用于提供 SSL/TLS 私钥的密码。该指令在 NGINX 启动时会读取该文件，并用于加载私钥文件时解锁加密的私钥。如果私钥是加密的，那么 NGINX 需要密码才能使用它，密码错误会导致nginx启动或者重新加载失败。

### 语法

```nginx
Syntax: ssl_password_file file;
Default: —
Context: http, server
This directive appeared in version 1.7.3.

```

- \`\`：指定包含密码的文件路径。这个文件应该包含一个用于解锁 SSL 私钥的密码。
- 指定一个包含密钥密码的文件，每个密码都位于单独的一行。在加载密钥时，密码将按顺序尝试。

### 默认值

- 默认情况下，`ssl_password_file` 指令不被启用，即没有设置密码文件。

### 使用场景

该指令通常在以下情况下使用： 1. **私钥加密**：当生成 SSL/TLS 私钥时，如果你为私钥设置了密码保护，那么每次 NGINX 启动时，都需要提供密码才能加载私钥。

### 配置示例

生成四组自签名证书及私钥， 其中RSA算法两个， ECC算法两个，两组证书中一个带密码，一个不带密码。使用脚本生成

```bash
#!/bin/bash

# Set directory variables
CERTS_DIR="/etc/nginx/ssl"

# Create the certificate directory if it doesn't exist
mkdir -p $CERTS_DIR

# Set passwords for different key types
PASSWORD_RSA_WITH="password123"
PASSWORD_ECC_WITH="password789"

# Create password files for multiple certificates
echo $PASSWORD_RSA_WITH > "$CERTS_DIR/rsa_password.txt"
chmod 600 "$CERTS_DIR/rsa_password.txt"
echo $PASSWORD_ECC_WITH > "$CERTS_DIR/ecc_password.txt"
chmod 600 "$CERTS_DIR/ecc_password.txt"
cat "$CERTS_DIR/rsa_password.txt" "$CERTS_DIR/ecc_password.txt" > "$CERTS_DIR/password_file.txt"
chmod 600 "$CERTS_DIR/password_file.txt"

# Set certificate information
COUNTRY="CN"
STATE="BEIJING"
LOCALITY="BEIJING"
ORG="test"
ORG_UNIT="test-unit"
EMAIL="email@example.com"

# Generate RSA private key with password
openssl genpkey -algorithm RSA -aes256 -out "$CERTS_DIR/rsa_private_key_with_password.pem" -pass pass:$PASSWORD_RSA_WITH
echo "Generated RSA private key with password: rsa_private_key_with_password.pem"

# Generate RSA private key without password
openssl genpkey -algorithm RSA -out "$CERTS_DIR/rsa_private_key_without_password.pem"
echo "Generated RSA private key without password: rsa_private_key_without_password.pem"

# Generate RSA Certificate Signing Request (CSR) with password, avoiding interactive input
COMMON_NAME="example1.com"
openssl req -new -key "$CERTS_DIR/rsa_private_key_with_password.pem" -out "$CERTS_DIR/rsa_csr_with_password.pem" \
-passin pass:$PASSWORD_RSA_WITH \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORG/OU=$ORG_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
echo "Generated RSA CSR with password: rsa_csr_with_password.pem"

# Generate RSA CSR without password, avoiding interactive input
COMMON_NAME="example2.com"
openssl req -new -key "$CERTS_DIR/rsa_private_key_without_password.pem" -out "$CERTS_DIR/rsa_csr_without_password.pem" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORG/OU=$ORG_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
echo "Generated RSA CSR without password: rsa_csr_without_password.pem"

# Use the RSA private key to sign the certificate
openssl x509 -req -in "$CERTS_DIR/rsa_csr_with_password.pem" -signkey "$CERTS_DIR/rsa_private_key_with_password.pem" -out "$CERTS_DIR/rsa_certificate_with_password.pem" -days 365 -passin pass:$PASSWORD_RSA_WITH
openssl x509 -req -in "$CERTS_DIR/rsa_csr_without_password.pem" -signkey "$CERTS_DIR/rsa_private_key_without_password.pem" -out "$CERTS_DIR/rsa_certificate_without_password.pem" -days 365
echo "Generated RSA certificates"

# Generate ECC private key with password
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -aes256 -out "$CERTS_DIR/ecc_private_key_with_password.pem" -pass pass:$PASSWORD_ECC_WITH
echo "Generated ECC private key with password: ecc_private_key_with_password.pem"

# Generate ECC private key without password
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out "$CERTS_DIR/ecc_private_key_without_password.pem"
echo "Generated ECC private key without password: ecc_private_key_without_password.pem"

# Generate ECC CSR with password, avoiding interactive input
COMMON_NAME="example3.com"
openssl req -new -key "$CERTS_DIR/ecc_private_key_with_password.pem" -out "$CERTS_DIR/ecc_csr_with_password.pem" \
-passin pass:$PASSWORD_ECC_WITH \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORG/OU=$ORG_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
echo "Generated ECC CSR with password: ecc_csr_with_password.pem"

# Generate ECC CSR without password, avoiding interactive input
COMMON_NAME="example4.com"
openssl req -new -key "$CERTS_DIR/ecc_private_key_without_password.pem" -out "$CERTS_DIR/ecc_csr_without_password.pem" \
-subj "/C=$COUNTRY/ST=$STATE/L=$LOCALITY/O=$ORG/OU=$ORG_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
echo "Generated ECC CSR without password: ecc_csr_without_password.pem"

# Use the ECC private key to sign the certificate
openssl x509 -req -in "$CERTS_DIR/ecc_csr_with_password.pem" -signkey "$CERTS_DIR/ecc_private_key_with_password.pem" -out "$CERTS_DIR/ecc_certificate_with_password.pem" -days 365 -passin pass:$PASSWORD_ECC_WITH
openssl x509 -req -in "$CERTS_DIR/ecc_csr_without_password.pem" -signkey "$CERTS_DIR/ecc_private_key_without_password.pem" -out "$CERTS_DIR/ecc_certificate_without_password.pem" -days 365
echo "Generated ECC certificates"

# Print the generated file paths
echo "RSA Certificate (with password): $CERTS_DIR/rsa_certificate_with_password.pem"
echo "RSA Private Key (with password): $CERTS_DIR/rsa_private_key_with_password.pem"
echo "RSA Certificate (without password): $CERTS_DIR/rsa_certificate_without_password.pem"
echo "RSA Private Key (without password): $CERTS_DIR/rsa_private_key_without_password.pem"
echo "ECC Certificate (with password): $CERTS_DIR/ecc_certificate_with_password.pem"
echo "ECC Private Key (with password): $CERTS_DIR/ecc_private_key_with_password.pem"
echo "ECC Certificate (without password): $CERTS_DIR/ecc_certificate_without_password.pem"
echo "ECC Private Key (without password): $CERTS_DIR/ecc_private_key_without_password.pem"

```

`ssl_password_file` 来指定该文件：

```nginx
user root;
worker_processes 1;

error_log logs/error.log debug;

#pid logs/nginx.pid;

events {
worker_connections 1024;
}

http {
#large_client_header_buffers 4 16k;

# Global settings for SSL password file
ssl_password_file /etc/nginx/ssl/password_file.txt;

# Default SSL settings for all server blocks
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;

# Server block for example1.com using RSA certificate with password
server {
listen 443 ssl;
server_name example1.com;

ssl_certificate /etc/nginx/ssl/rsa_certificate_with_password.pem;
ssl_certificate_key /etc/nginx/ssl/rsa_private_key_with_password.pem;

# Other SSL-related settings
#ssl_password_file /etc/nginx/ssl/rsa_password.txt;

location / {
# Custom location settings for example1.com
#root /var/www/html;
#index index.html;
return 200 "This is the response for example1.com\n";
}
}

# Server block for example2.com using RSA certificate without password
server {
listen 443 ssl;
server_name example2.com;

ssl_certificate /etc/nginx/ssl/rsa_certificate_without_password.pem;
ssl_certificate_key /etc/nginx/ssl/rsa_private_key_without_password.pem;

# Other SSL-related settings
#ssl_password_file /etc/nginx/ssl/rsa_password_without.txt;

location / {
# Custom location settings for example2.com
#root /var/www/html;
#index index.html;
return 200 "This is the response for example2.com\n";
}
}

# Server block for example3.com using ECC certificate with password
server {
listen 443 ssl;
server_name example3.com;

ssl_certificate /etc/nginx/ssl/ecc_certificate_with_password.pem;
ssl_certificate_key /etc/nginx/ssl/ecc_private_key_with_password.pem;

# Other SSL-related settings
#ssl_password_file /etc/nginx/ssl/ecc_password.txt;

location / {
# Custom location settings for example3.com
#root /var/www/html;
#index index.html;
return 200 "This is the response for example3.com\n";
}
}

# Server block for example4.com using ECC certificate without password
server {
listen 443 ssl;
server_name example4.com;

ssl_certificate /etc/nginx/ssl/ecc_certificate_without_password.pem;
ssl_certificate_key /etc/nginx/ssl/ecc_private_key_without_password.pem;

# Other SSL-related settings
#ssl_password_file /etc/nginx/ssl/ecc_password_without.txt;

location / {
# Custom location settings for example4.com
#root /var/www/html;
#index index.html;
return 200 "This is the response for example4.com\n";
}
}

}

```

在这个配置中，http 级 `ssl_password_file` 指向脚本合并后的 `/etc/nginx/ssl/password_file.txt`（由 `rsa_password.txt` 与 `ecc_password.txt` 拼接）。NGINX 启动时读取该文件中的密码行，用于解锁各 server 中加密的私钥。各 server 内被注释掉的 `#ssl_password_file .../rsa_password.txt`（或 ecc）行是可选的替代写法：若改为在 server 内单独指定，则不必再合并为 `password_file.txt`。

### 安全性注意事项

- 确保 `ssl_password_file` 文件的权限设置非常严格，因为它包含私钥的密码。如果设置启动用户为 nginx， 可以设置用户限制只有 nginx 用户才能读取该文件。例如，你可以使用以下命令来限制文件权限（与配置中的路径保持一致）：

```bash
chmod 600 /etc/nginx/ssl/password_file.txt
chown nginx:nginx /etc/nginx/ssl/password_file.txt
```

### 小结

- `ssl_password_file` 是加载加密私钥的有效工具，可提高自动化部署效率。
- 确保密码文件权限设置正确，以免泄露私钥密码。
- 在部署中建议结合密码管理工具，进一步提升安全性。

### 图片from [**Mike Lin**](https://www.facebook.com/groups/474930279315210/user/1392559178/?__cft__[0]=AZX0WeveEUqv9FABZanUQsxQr7A_tbA5-dG-2HvrOZiV2AjsurDYbe7bRhKwtEii18OaFIG6COmvLm8FDMmPRf-X2Dleq2IBxOs9GbRmOxYqr2nU8Xd1bqHHubgW3iGofHD0Cm6cYImcw5K04OUy6XO1lPsfyh97ZG-69dpdSOfj9x8yPatakOP74Vgfi6EnnwLbFwTVMSJitUZ0Vr6cqg0N&__tn__=-UC%2CP-R)

