Nginx-HTTPS

简介
SSL 是一种网络安全协议,用于数据加密,确保数据在传输过程中的安全性和完整性。
Https 是基于Shttp 协议使用 SSL 加密后的网络通信协议。https 在建立连接时使用非对称加密,往后的通信使用对称加密。
如果网站不适用 https ,浏览器将提示不安全,实际上也确实不安全。所以有必要为你的服务提供 https 配置。nginx 可以很好的实现这一目标。
实现原理是:
http的默认端口号是 80 ,https 的默认端口号是 443 , nginx 通过监听 443 端口,将请求代理转发给业务服务,避免业务服务直接暴露。很多时候用户输入域名时,并不会输入 https ,为了安全需要将 http 强制转换为 https ,也即监听 80 端口并转发到 443 端口。
1. 获取证书
首先 SSL 认证是基于域名的,而不是 ip 。需要为你的域名申请合法证书,所谓合法就是指被 CA 机构信任的证书,CA 机构 相当于第三方公正的法官,很遗憾的是这不是免费的。
在本地使用,建议用 mkcert 这个工具获取证书。我在这里有介绍怎么使用 mkcert-局域网https证书认证工具
2. 配置nginx
# 将 http 请求强制转发到 https
server {
listen 80;
server_name blog.systemcaller.cloud; # 替换为你的域名
rewrite ^(.*) <https://$host$1> permanent;
}
server{
listen 443 ssl http2; # 监听 443 端口
server_name blog.systemcaller.cloud; # 替换为你的域名
ssl_certificate /etc/nginx/certs/blog.systemcaller.cloud.pem; # SSL证书
ssl_certificate_key /etc/nginx/certs/blog.systemcaller.cloud-key.pem; # SSL密钥
ssl_session_cache shared:SSL:1m; # 缓存 SSL/TLS 会话,缓存大小为 1MB
ssl_session_timeout 5m; # 会话参数在缓存中最多保存 5 分钟。
ssl_protocols TLSv1.2 TLSv1.3; # 优先使用服务器配置的加密套件,防止客户端使用弱密码套件。
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on; # 优先使用服务器配置的加密算法,防止客户端使用弱密码算法。
location / {
proxy_pass <http://192.168.1.7:8080>; # 替换为你要转发的地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto https;
}
}
# 只能通过配置好的域名访问,否则直接拒绝 SSL 认证。
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on;
}
详细解释下以上配置每一项,我见他分成几个段来解释。
http强转https
server {
listen 80;
server_name blog.systemcaller.cloud; # 替换为你的域名
rewrite ^(.*) <https://$host$1> permanent;
}
这是一个完整的 server 配置,它将监听 80 端口的 http 请求重写成 https 请求。
假设客户端请求的 URL 是 http://example.com/path/to/file
。
- 匹配: 正则表达式
^(.*)
匹配整个 URL。 - 捕获: 捕获组
(.*)
捕获到/path/to/file
,并将其存储在$1
中。 - 重写:
$host
被替换为example.com
。$1
被替换为/path/to/file
。
- 最终的 URL:
https://example.com/path/to/file
。 - permanent 标志表示永久重定向,浏览器会缓存这个重定向,下次访问时直接跳转到新的 URL。
有时候你还在其他地方看到过这样的写法
server {
listen 80;
server_name mdb.test www.mdb.test;
return 301 https://mdb.test$request_uri;
}
它并不是改写请求的 url ,而是直接告诉浏览器重定向到某个地址。$request_uri 表示当前请求的 URI,即域名后面的部分。
两种方式的核心区别:
- return: 直接返回一个 HTTP 状态码(301 永久重定向)和新的 URI,终止当前的请求处理。
-
rewrite: 对 URI 进行重写,然后继续处理重写后的 URI,直到匹配到下一个 location 或 server 块。而且这种方式实际上更灵活,你可以根据需要做任何你希望的重写。比如说
-
你对资源进行了迁移,希望用户访问原来的地址,通过重写能转发给新的地址,用户感知不到变化
-
permanent
这个是会改变浏览器地址的哟。不加就浏览器的就不会变。 -
A/B 测试:将部分流量重定向到不同的版本
location / { if ($random > 0.5) { rewrite ^/(.*)$ /version_a/$1; } }
-
将动态 URL 改写成静态 URL
location / { # 匹配所有以 /product.php?id= 开头的 URL 并捕获 id 的值。将匹配到的 URL 重写为 /product/id 这种静态URL rewrite ^/product\\.php\\?id=(\\d+)$ /product/$1 permanent; }
-
证书配置和请求转发
server{
listen 443 ssl http2; # 监听 443 端口
server_name blog.systemcaller.cloud; # 替换为你的域名
ssl_certificate /etc/nginx/certs/blog.systemcaller.cloud.pem; # SSL证书
ssl_certificate_key /etc/nginx/certs/blog.systemcaller.cloud-key.pem; # SSL密钥
ssl_session_cache shared:SSL:1m; # 缓存 SSL/TLS 会话,缓存大小为 1MB
ssl_session_timeout 5m; # 会话参数在缓存中最多保存 5 分钟。
ssl_protocols TLSv1.2 TLSv1.3; # 优先使用服务器配置的加密套件,防止客户端使用弱密码套件。
ssl_ciphers ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
ssl_prefer_server_ciphers on; # 优先使用服务器配置的加密算法,防止客户端使用弱密码算法。
location / {
proxy_pass <http://192.168.1.7:8080>; # 替换为你要转发的地址
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Proto https;
}
}
- listen 443 ssl http2; 监听 443 端口,并启用 SSL/TLS,确保连接加密。支持 HTTP/2 协议,提高传输效率。
- server_name 指定服务器的域名,用于匹配请求。
- sl_certificate 和 ssl_certificate_key:分别指定 SSL 证书和密钥文件的路径。这两个文件是开启 HTTPS 服务必备的。
- nginx 是 docker 容器的注意了,这必须是在容器内的目录。
- ssl_session_cache 和 ssl_session_timeout:用于配置 SSL/TLS 会话缓存,可以减少握手次数,提高性能。
- ssl_protocols:指定支持的 SSL/TLS 协议版本。建议使用这几个版本,其他的低版本有安全漏洞不建议用。
- ssl_ciphers:指定支持的加密套件,这里配置了比较安全的加密套件。就是加密算法。
- ECDHE-ECDSA-AES256-GCM-SHA384 五个算法为一组,每组之间用冒号隔开,写在前面的组优先级高。
- ssl_prefer_server_ciphers:强制服务器使用配置的加密套件,提高安全性。
- location /: 匹配所有请求。
- proxy_pass: 将请求代理到后端服务器。
- proxy_set_header 系列指令:实际上你可以添加任何你需要的请求头信息
- Host: 将 Host 头设置为原始请求的 Host。在经过多个代理服务器时可能发生变化。
- X-Real-IP:将客户端的真实 IP 地址传递给后端服务器。
- X-Forwarded-For:将客户端的 IP 地址和代理服务器的 IP 地址传递给后端服务器。
- Upgrade:用于支持 WebSocket 等协议的升级。
- X-Forwarded-Host 和 X-Forwarded-Proto:分别传递原始请求的 Host 和协议给后端服务器。通常在经过多个代理服务器时,X-Forwarded-Host 会包含多个域名,用逗号分隔。
禁止通过ip或者其他域名访问
1.使用背景
比如我们网站配置的域名是 blog.systemcaller.cloud ,某些人绕过域名通过 ip 对我们进行攻击。因为域名是被 SSL 认证了的,很安全。ip 通常是不安全的。 还有可能通过伪造其他域名,来访问我们的网站。这些都是安全风险。
总之就是让用户只能通过我们经过 SSL 认证的域名才能访问站点。其他的都哒咩!
默认的情况下,比如我在 host 文件中添加 blog2.systemcaller.cloud 和 服务器 ip 的DNS映射。就能绕过安全域名访问到站点了。也可以直接通过 ip 进行访问。
添加了配置后,就无法访问了,浏览器报错 ERR_SSL_UNRECOGNIZED_NAME_ALERT 就是 SSL 域名认证失败的意思。
2.配置讲解
server {
listen 80 default_server;
listen 443 ssl default_server;
server_name _;
ssl_reject_handshake on;
}
- listen 80 default_server; 监听 80 端口并其他 server 块没有匹配到请求,
- servername ; 表示匹配所有请求,无论主机名是什么。这通常用于默认配置或捕获未匹配到的请求。
- ssl_reject_handshake on; 拒绝 SSL 握手。这可以防止一些扫描和攻击。
3.注意事项
- 配置顺序: 由于
default_server
的存在,这个配置块通常应该放在其他 server 块的后面,以确保其他更具体的配置优先匹配。 ssl_reject_handshake
的影响: 如果你的网站有多个域名,且每个域名都有对应的证书,那么开启ssl_reject_handshake
可能导致某些请求被拒绝。
servername 和 default_server 的区别
- servername :
- 匹配任何主机名。
- 当一个请求到来时,如果没有任何其他 server 块的
server_name
匹配该请求的主机名,那么这个配置块就会被匹配到。 - 它就像一个兜底的配置,用于处理那些无法匹配到其他配置的请求。
- default_server:
- 表示当多个 server 块都监听同一个端口时,如果其他 server 块的
server_name
都没有匹配到,那么这个配置块就会被作为默认的 server 块。 - 它通常用于处理没有明确指定主机名的请求,或者当其他配置都无法匹配时。
- 表示当多个 server 块都监听同一个端口时,如果其他 server 块的