故事是这样的:
有一台内网服务器,电信宽带有动态的公网IP,所以我配置了DDNS域名,这样公网就可以通过域名访问到家中的内网服务器。
因为电信宽带封禁了常见的80/443端口,所以我在阿里云服务器上配置了nginx做反向代理,但是发现经常502错误,只有重启nginx才能恢复,此时内网服务工作正常。
1 原因
究其原因,在于nginx反向代理解析DDNS域名时,只会在Nginx启动解析配置文件的时候解析1次,此后就会一直拿着解析到的IP连接upstream。因此,当我的电信公网IP变化后,nginx并不会重新去解析DDNS域名,导致连接一个错误的IP。
反向代理nginx配置文件大概是这样的:
server { listen 443 ssl; server_name www.xlsys.cn; ssl_certificate /etc/nginx/ssl/7836194.pem; ssl_certificate_key /etc/nginx/ssl/7836194.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!ECDHE+3DES:!MD5:!ADH:!RC4; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; charset utf-8; allow all; location / { #转发 proxy_pass http://cdn.xlsys.cn:8899; # proxy_http_version 1.1; # proxy_connect_timeout 10s; #proxy_read_timeout 86400s; #proxy_send_timeout 80s; proxy_redirect off; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; client_body_buffer_size 1024k; client_max_body_size 1000M; }
阿里云www.xlsys.cn反向代理给http://cdn.xlsys.cn:8899;,然而http://cdn.xlsys.cn:8899;的IP地址一旦变化就会导致无法连接。
2解决方法
我希望每次proxy行为都重新解析IP地址,或者至少可以控制缓存的时间。
要实现这个效果,必须把http://cdn.xlsys.cn:8899;作为变量,这样nginx启动时则不会解析IP,而是运行时解析。
nginx配置文件修改如下:
server { listen 443 ssl; server_name www.xlsys.cn; ssl_certificate /etc/nginx/ssl/7836194.pem; ssl_certificate_key /etc/nginx/ssl/7836194.key; ssl_session_timeout 5m; ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!ECDHE+3DES:!MD5:!ADH:!RC4; ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3; ssl_prefer_server_ciphers on; charset utf-8; allow all; #关键配置--------------- #指定 DNS IP,并设置缓存 1-60 秒。 resolver 114.114.114.114 valid=1s; resolver_timeout 3s; set $proxy_pass_url http://cqsd.f3322.net:8011; #关键配置--------------- location / { #转发配置 proxy_pass $proxy_pass_url; # proxy_http_version 1.1; # proxy_connect_timeout 10s; #proxy_read_timeout 86400s; #proxy_send_timeout 80s; proxy_redirect off; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; client_body_buffer_size 1024k; client_max_body_size 1000M; }
但这种方法无法作用于 upstream 里的域名。
3使用模块nginx-upstream-dynamic-servers
模块地址: nginx-upstream-dynamic-servers
该模块在第一次启动的时候会进行一次解析,解析完后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,过期后会再次发起解析请求
使用方法
http {
resolver 114.114.114.114;
upstream backend{
server example.com resolve;
}
}
使用这种方法的时候,DNS TTL 时间需要设置短一些。
4 使用模块 ngx_upstream_jdomain
文档地址: domain_resolve
ngx_upstream_jdomain
模块是一个依赖 DNS 解析实现的 upstream
负载均衡,该模式下,允许使用域名来写 upstream
后端。该模块默认情况下,会每秒做一次 DNS 解析,使用方法如下
http {
resolver 8.8.8.8;
resolver_timeout 10s;
upstream backend {
jdomain www.baidu.com port=80 interval=5; # 每 5 秒解析一次
}
server {
listen 8080;
location / {
proxy_pass http://backend;
}
}
}
微信扫描下方的二维码阅读本文