在大多数人的印象中,HTTPS似乎是互联网专属的安全协议,但实际上,局域网环境同样面临着多种安全威胁。想象一下,你的办公室Wi-Fi网络可能被不怀好意的人接入,或者同一局域网内的设备可能被恶意软件感染。这些情况下,传统的HTTP明文传输就像在公共场合大声讨论机密信息一样危险。
我曾在多个企业IT项目中遇到过这样的需求:内部管理系统、测试环境、甚至是打印机管理界面,都需要通过HTTPS来保护数据传输。特别是在金融和医疗行业,即使是在内网,合规性要求也强制使用加密通信。通过实践,我发现最稳定可靠的方案就是自签名证书配合Nginx反向代理。
自签名证书与商业CA颁发的证书在加密强度上没有任何区别,它们都使用相同的加密算法(如RSA 2048位)。关键差异在于信任链——自签名证书没有经过第三方CA的验证。这就好比你自己写了一封介绍信,而不是通过公证处认证的。
在局域网环境中,我们可以通过手动将证书安装到客户端的"受信任根证书存储"来解决这个问题。一旦完成这个步骤,自签名证书在安全性上就等同于商业证书了。
Nginx在这里扮演了两个关键角色:
这种架构的另一个好处是,即使后端服务本身不支持HTTPS(比如一些老旧的内部系统),我们也能通过Nginx为其添加加密层。
创建ssl.config文件时,有几个关键点需要注意:
bash复制[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
C = CN
ST = 广东
L = 深圳
O = 内网服务
OU = IT部
CN = 192.168.1.100 # 必须与访问地址完全一致
[v3_ca]
subjectAltName = @alt_names
basicConstraints = CA:TRUE # 关键!声明这是CA证书
keyUsage = digitalSignature, keyEncipherment, keyCertSign
extendedKeyUsage = serverAuth, clientAuth
[alt_names]
IP.1 = 192.168.1.100 # 必须包含所有可能的访问IP
# 如果使用域名访问,需要添加:
# DNS.1 = internal.example.com
重要提示:
CN和subjectAltName必须包含客户端访问时使用的完整地址(IP或域名),否则浏览器会报"证书名称不匹配"错误。
执行以下命令生成证书:
bash复制# 生成私钥(建议保存在安全位置)
openssl genrsa -out server.key 2048
# 生成自签名证书(有效期100年)
openssl req -new -x509 -nodes -key server.key -days 36500 -out server.crt -config ssl.config
在实际项目中,我建议:
server.key)设置为600权限:chmod 600 server.key/etc/nginx/ssl/目录下一个完整的Nginx SSL配置应该包含以下内容:
nginx复制server {
listen 443 ssl;
server_name 192.168.1.100; # 必须与证书中的CN一致
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# 性能优化相关
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_session_tickets off;
# 现代加密套件配置
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 on;
# HSTS增强安全(谨慎使用)
# add_header Strict-Transport-Security "max-age=63072000" always;
# 其他代理设置
location / {
proxy_pass http://localhost:8080; # 实际后端服务
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
ssl_session_cache:启用会话缓存可以显著提高性能,减少SSL握手开销。在测试中,这能使HTTPS请求的响应时间减少30%以上。
TLS版本选择:禁用了不安全的TLSv1和TLSv1.1,只保留v1.2和v1.3。这是目前最安全的选择。
加密套件:选择了前向保密(Forward Secrecy)的加密套件,即使私钥未来被泄露,过去的通信记录也不会被解密。
server.crt文件常见问题:如果安装后仍然提示不安全,可能是:
- 证书中的CN/IP与访问地址不匹配
- 没有重启浏览器(某些浏览器会缓存证书状态)
- 系统时间不正确(证书有效期检查失败)
bash复制# 将证书复制到系统证书目录
sudo cp server.crt /usr/local/share/ca-certificates/internal.crt
# 更新证书存储
sudo update-ca-certificates
虽然可以直接使用IP,但更专业的做法是:
code复制192.168.1.100 internal.example.com
ini复制CN = internal.example.com
DNS.1 = internal.example.com
nginx复制server_name internal.example.com;
这样配置后,访问https://internal.example.com会更加专业,也避免了IP变更带来的问题。
虽然我们设置了100年有效期,但更安全的做法是:
renew_cert.sh):bash复制#!/bin/bash
openssl req -new -x509 -nodes -key /etc/nginx/ssl/server.key -days 365 -out /etc/nginx/ssl/server.crt -config /etc/nginx/ssl/ssl.config
nginx -s reload
bash复制0 0 1 * * /path/to/renew_cert.sh
通过SAN(Subject Alternative Name)扩展,可以让一个证书支持多个域名/IP:
ini复制[alt_names]
IP.1 = 192.168.1.100
IP.2 = 192.168.1.101
DNS.1 = service1.example.com
DNS.2 = service2.example.com
然后在Nginx中为每个server块使用相同的证书即可。
可能原因及解决方案:
常见错误:
code复制nginx: [emerg] SSL_CTX_use_PrivateKey_file("/path/to/key") failed (SSL: error:0B080074:x509 certificate routines:X509_check_private_key:key values mismatch)
这说明证书和私钥不匹配,需要重新生成。
通过以下命令测试SSL配置:
bash复制openssl s_client -connect 192.168.1.100:443 -servername internal.example.com -tlsextdebug -status
关注输出中的:
私钥保护:
chmod 600 server.keyOCSP装订:
虽然自签名证书没有OCSP,但可以模拟实现:
nginx复制ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 valid=300s;
定期轮换证书:
即使设置了长有效期,也建议每年更换一次证书。
禁用旧协议:
在确认所有客户端支持后,可以只保留TLSv1.3:
nginx复制ssl_protocols TLSv1.3;
在实际部署中,我发现这套方案不仅能满足基本的安全需求,还能为内部服务提供企业级的HTTPS支持。特别是在需要与移动App对接时,自签名证书配合证书锁定(Certificate Pinning)能提供非常高的安全性。