nginx 使用 SSL证书配置 HTTPS
生成 D-H 密钥文件
生成 Diffie-Hellman (D-H) 密钥文件:
sudo openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048
配置 nginx
创建 SSL 通用配置
检查 nginx 版本:
sudo nginx -v
nginx version: nginx/1.22.1
检查 OpenSSL 版本:
sudo openssl version
OpenSSL 3.0.15 3 Sep 2024 (Library: OpenSSL 3.0.15 3 Sep 2024)
创建一个用于保存 nginx 通用配置的目录:
sudo mkdir -p /etc/nginx/common
创建一个适合大多数场景的 SSL 通用配置文件:
sudo vim /etc/nginx/common/ssl.intermediate.conf
插入配置:
# ssl.intermediate.conf
# Needs nginx nginx 1.22.1, OpenSSL 3.0.15
# Supports Firefox 27, Android 4.4.2, Chrome 31, Edge, IE 11 on Windows 7, Java 8u31, OpenSSL 1.0.1, Opera 20, Safari 9
# intermediate configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
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:DHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# see also ssl_session_ticket_key alternative to stateful session cache
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# HSTS (ngx_http_headers_module is required)
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload' always;
创建一个兼容性更好(会降低安全性)的 SSL 通用配置文件:
sudo vim /etc/nginx/common/ssl.old.conf
插入配置:
# ssl.old.conf
# Needs nginx nginx 1.22.1, OpenSSL 3.0.15
# Supports Firefox 1, Android 2.3, Chrome 1, Edge 12, IE8 on Windows XP, Java 6, OpenSSL 0.9.8, Opera 5, Safari 1
# old configuration
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ecdh_curve X25519:prime256v1:secp384r1;
ssl_ciphers @SECLEVEL=0: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:DHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA256:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA;
ssl_prefer_server_ciphers on;
# see also ssl_session_ticket_key alternative to stateful session cache
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m; # about 40000 sessions
ssl_session_tickets off;
# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# HSTS (ngx_http_headers_module is required)
add_header Strict-Transport-Security 'max-age=31536000; includeSubdomains; preload' always;
网站引入 SSL 配置
编辑网站 nginx 配置文件:
sudo vim /etc/nginx/sites-available/avinzheng.com.conf
根据需要引入合适的 SSL 通用配置文件:
# avinzheng.com
server {
listen 443 ssl http2;
server_name avinzheng.com;
root /var/wwwroot/avinzheng.com;
index index.html;
# ssl
include /etc/nginx/common/ssl.intermediate.conf;
ssl_certificate /etc/ssl/web/fullchain.pem;
ssl_certificate_key /etc/ssl/web/key.pem;
# OCSP stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/ssl/web/ca.pem;
resolver 127.0.0.1 valid=300s;
resolver_timeout 10s;
}
# redirect http to https
server {
listen 80;
server_name avinzheng.com;
return 301 https://$http_host$request_uri;
}
ssl_certificate
填写 PEM 格式(文件后缀可能为.crt
/.cer
/.pem
)的证书文件路径,文件内容一般包含域名证书 + 中间证书 + 根证书(可选)。如果使用的是 acme.sh 生成的证书,需要使用--fullchain-file
对应的fullchain.pem
证书文件。ssl_certificate_key
填写 PEM 格式(文件后缀可能为.key
/.pem
)的证书私钥的文件路径(如果 SSL 证书只有一个.pem
文件,则可能同时包含了证书和私钥,使用同一个文件)。ssl_trusted_certificate
填写 PEM 格式(文件后缀可能为.crt
/.cer
/.pem
)的中间证书路径(文件内容需要包含所有的中间证书),如果ssl_certificate
配置的证书文件内容中已经包含了所有的中间证书,该配置项可省略。
部分 CA 证书服务商已经不再支持 OCSP(如 Let’s Encrypt),生成的证书内容将不再包含 OCSP URI 信息,配置 OCSP Stapling 将无效,如果需要使用 OCSP 功能,需要更换 CA 证书服务商。
检查证书是否支持 OCSP:
openssl x509 -noout -ocsp_uri -in /etc/ssl/web/fullchain.pem
如果无内容输出则表示证书不包含 OCSP URI 信息,不支持 OCSP(支持 OCSP 的证书会输出 OCSP URL 地址)。
配置 AppArmor
如果配置了 nginx 的 AppArmor 规则,需要修改规则文件:
sudo vim /etc/apparmor.d/usr.sbin.nginx
需要添加相应文件路径:
#include <tunables/global>
/usr/sbin/nginx {
...
#include <abstractions/openssl>
...
/etc/nginx/common/** r,
/etc/ssl/certs/dhparam.pem r,
/etc/ssl/web/* r,
/var/cache/nginx/ocsp/** rw,
}
加载 AppArmor 配置文件:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
重启 nginx 服务
验证 nginx 配置是否正确:
sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
重启 nginx 服务:
sudo systemctl restart nginx
检查 OCSP Stapling
如果证书支持 OCSP 并且配置了 OCSP Stapling,可检查是否生效:
openssl s_client -connect <domain>:443 -status -servername <domain> | grep -A 17 "OCSP response"
<domain>
为可以通过 HTTPS 正常访问的需要检查的域名。
正常输出信息中应包含以下内容:
OCSP Response Status: successful (0x0)
配置防火墙
UFW 防火墙
Debian / Ubuntu 等系统一般使用的是 UFW 防火墙。
UFW 防火墙添加对应的端口号:
sudo ufw allow 443/tcp
重新加载防火墙规则:
sudo ufw reload
查看防火墙状态:
sudo ufw status verbose
VPS 如果自带了网络防火墙服务,需要在防火墙中添加 443/tcp
端口。
FirewallD 防火墙
CentOS 等系统一般使用的是 FirewallD 防火墙。
查看 FirewallD 当前默认区域永久配置:
sudo firewall-cmd --permanent --list-all
public
target: default
icmp-block-inversion: no
interfaces:
sources:
services: http ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
可见 services
中没有启用 https
服务,ports
中没有添加 443/tcp
端口。
永久启用 https
服务(443/tcp):
sudo firewall-cmd --permanent --add-service=https
查看下次重启(防火墙重新加载、服务器重启或者系统重启)之后永久生效的服务:
sudo firewall-cmd --permanent --list-service
http https ssh
重载防火墙规则:
sudo firewall-cmd --reload
VPS 如果自带了网络防火墙服务,需要在防火墙中添加 443/tcp
端口。
SSL 安全检测
检测地址:https://www.ssllabs.com/ssltest/
输入域名,正常情况下检测结果应为 A+
。