使用HTTPS保护Nginx:逐步指南
在本全面逐步指南中,学习如何使用HTTPS保护您的Nginx Web服务器。我们涵盖了使用Certbot从Let's Encrypt获取免费SSL/TLS证书、配置Nginx进行加密连接以及实施HSTS等基本安全措施。通过正确配置HTTPS,保护您的数据、建立用户信任并改善SEO。
使用HTTPS保护Nginx:逐步指南
使用HTTPS保护Nginx通常是一项小任务,但它是那种小错误会引发大问题的工作。缺少证书文件会导致Nginx无法重新加载。忘记防火墙规则会使网站看起来无法访问。匆忙设置的HSTS标头可能会让用户长时间锁定在错误的HTTPS配置中,超出您的预期。
好消息是,常规路径很简单。您将DNS指向服务器,确保Nginx在端口80上响应,使用Certbot请求Let's Encrypt证书,测试生成的Nginx配置,重新加载,然后验证续期。这就是本指南遵循的路径。
下面我将使用example.com和www.example.com。请将它们替换为您的真实域名,并且在重新加载Nginx之前不要跳过检查步骤。
在请求证书之前
在接触Certbot之前,请确认那些繁琐的部分。大多数证书问题来自DNS、防火墙或未响应所请求域名的服务器块。
从服务器外部检查DNS:
dig +short example.com
dig +short www.example.com
两个名称都应解析为能够到达您的Nginx主机或负载均衡器的公共地址。
确保端口80和443在每一层都是开放的:云安全组、主机防火墙、网络防火墙以及主机前的任何负载均衡器。
sudo ss -tulnp | grep nginx
sudo ufw status
在云虚拟机上,还要检查提供商控制台。我见过很多干净的Nginx配置失败,因为实例防火墙允许443,但云安全组仍然阻止了它。
最后,确认Nginx已经通过普通HTTP为域名提供服务:
curl -I http://example.com
curl -I http://www.example.com
响应不需要很漂亮。它可以是一个占位页面。只需要证明对该主机名的请求到达了这个Nginx服务器。
安装Certbot
对于Debian/Ubuntu:
sudo apt update
sudo apt install certbot python3-certbot-nginx
对于RHEL兼容系统:
sudo dnf install certbot python3-certbot-nginx
较旧的CentOS系统可能使用yum,并且可能需要先启用EPEL。软件包名称也因发行版版本而异,因此如果这些命令找不到插件,请使用您的发行版的软件包文档。
请求证书
Nginx插件可以请求证书并编辑匹配的服务器块:
sudo certbot --nginx -d example.com -d www.example.com
Certbot会要求提供电子邮件地址、同意条款,有时还会询问是否将HTTP重定向到HTTPS。对于普通的公共网站,选择重定向。对于API或内部服务,请先检查客户端。一些较旧的客户端或健康检查可能仍然调用http://并期望特定的响应。
如果Certbot说找不到匹配的服务器块,请检查server_name。像这样的块为Certbot提供了清晰的工作基础:
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
在要求Certbot编辑任何内容之前,运行语法检查:
sudo nginx -t
如果当前配置已经损坏,请先修复它。
Nginx配置应该是什么样子
成功运行后,您通常会看到一个HTTP块(用于重定向)和一个HTTPS块(用于服务网站):
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
root /var/www/example.com/public;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
不要盲目地将此复制到生产配置中。保留您现有的location规则、代理设置、日志和上传限制。重要的部分是listen 443 ssl、证书路径以及端口80上的重定向行为。
测试、重新加载和验证
在重新加载之前始终进行测试:
sudo nginx -t
然后重新加载:
sudo systemctl reload nginx
从命令行检查:
curl -I http://example.com
curl -I https://example.com
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -dates
如果选择了重定向选项,HTTP请求应该重定向。HTTPS请求应返回预期状态。openssl命令应显示一个证书,其主题或主题备用名称覆盖域名,并且日期是当前的。
浏览器测试仍然很重要。在隐私窗口中打开网站,并单击锁图标检查证书。如果您的网站从旧的http:// URL加载资源,即使主证书没问题,页面也可能显示混合内容警告。在应用程序、CMS或模板层修复这些资源URL。
续期
Let's Encrypt证书有效期短,因此续期必须无需您记住即可工作。Certbot通常会安装一个systemd定时器或cron作业。检查它:
systemctl list-timers | grep certbot
sudo certbot renew --dry-run
试运行是有用的部分。它执行续期模拟,并捕获常见问题,如损坏的HTTP验证、DNS更改、缺少插件或无法重新加载的配置。
如果您在负载均衡器或CDN上终止TLS,而不是直接在Nginx主机上,续期可能需要DNS挑战或不同的部署路径。如果公共流量从未到达此服务器,不要假设默认的HTTP挑战会起作用。
值得检查的TLS设置
对于大多数现代公共网站,TLS 1.2和TLS 1.3是实用的基线:
ssl_protocols TLSv1.2 TLSv1.3;
除非您知道原因,否则避免手动调整密码套件列表。Certbot包含的options-ssl-nginx.conf和Mozilla SSL配置生成器是比从旧博客文章复制的密码字符串更好的起点。密码指导随时间变化,公共营销网站和内部遗留API之间的兼容性要求也不同。
HSTS很有用,但需要谨慎:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
在测试期间从短值开始:
add_header Strict-Transport-Security "max-age=300" always;
仅当每个子域都能提供有效的HTTPS时,才使用includeSubDomains。如果old.example.com、mail.example.com或客户特定的子域尚未准备好,该选项可能会破坏真实用户。
常见失败
如果Certbot无法验证域名,首先检查DNS,然后检查端口80,再检查Nginx服务器块。HTTP-01挑战需要Let's Encrypt能够访问/.well-known/acme-challenge/下的令牌。正确配置时重定向没问题,但代理、CDN或通配块可能会意外地将挑战发送到其他地方。
如果Certbot更改后Nginx无法重新加载,请运行:
sudo nginx -t
sudo journalctl -u nginx -n 80 --no-pager
语法测试通常会告诉您确切的文件和行。常见原因是重复的listen 443 ssl块、证书路径被删除或包含的片段路径在此服务器上不存在。
如果HTTPS在本地工作但对用户无效,请检查公共路径。负载均衡器可能仍指向旧的目标组。CDN可能缓存了重定向。IPv6 DNS可能指向与IPv4不同的主机。测试两者:
curl -4 -I https://example.com
curl -6 -I https://example.com
最干净的HTTPS设置是平淡无奇的:DNS指向正确的位置,Nginx为域名提供一个明显的服务器块,Certbot续期在试运行中通过,并且仅在基础工作正常后才添加标头。