0x01 前言
我配置所有的服务都喜欢在前面套一个nginx,然后加上SSL以保安全。在这过程中有一种情况比较特殊,就是upstream使用DDNS进行解析。
正好前两天发现有位V友也问了这个问题,在解答之后我将这个问题记录在这里,V站链接如下:
这种使用方式也挺常见的,例如后端放在家里或其他没有固定IP的网络中,又需要将这个服务暴露在公网,可是不希望每次访问都输入端口号,这时候就需要反向代理。
0x02 BUG
nginx的反向代理需要配置一个upstream,而upstream支持众多协议,这里以http协议为例:
[root@web conf.d]# cat zabbix.t.com.ngx.conf server { listen 80; server_name zabbix.t.com; root /usr/local/services_data/html/zabbix.t.com/public_html/; access_log /usr/local/services_data/html/zabbix.t.com/logs/ngx_access.log; location / { index index.php index.html; proxy_pass http://127.0.0.1:8080; } }
以上是我家zabbix作为后端,nginx作为前端的配置文件,其中proxy_pass使用http协议访问127.0.0.1:8080这个后端地址。
以上配置一般不会出现问题,如果后端的IP地址出现了变更,那么就需要手动修改nginx的配置文件并reload。
如果proxy_pass使用了域名,如下:
proxy_pass http://zabbix-upstream.t.com:8080;
而且这个域名使用DDNS动态解析的方式,就会有一个问题:
nginx只会在nignx启动的时候解析域名并缓存,如果域名的解析变了,nignx也不会有任何动作。
这样会导致这个服务再也无法访问。
0x03 DEBUG
解决方法很简单,只需要将proxy_pass部分做一些改造:
server { ... resolver [DNS IP 地址] valid=5s; set $[变量名] "http://ddns.domain.com:4430"; proxy_pass $[变量名]; ... }
例如:
server { ... resolver 114.114.114.114 valid=5s; set $upstream "http://ddns.domain.com:4430"; proxy_pass $upstream; ... }
这里用了set变量这种方式,使用set这种指定变量的方式有一个特点:每次访问都会出发 {} 符号内的set。
这也就是说,每次访问都对运行一遍set。
而上面的proxy_pass配置会强制每一次访问都进行解析,同时使用resolver参数指定DNS和TTL。
resolver参数所指定的TTL优先级最高,可以覆盖DNS的TTL。如果DNS默认的TTL为60s,那么上面的配置会将TTL修改为5s。
这里还有个需要注意的地方,如果不是必要,不要再server段设定set,这在大流量的情况下会引发性能下降,如果可以,将set放置在location段会更好。
0x04 结语
问题解决,如果不是使用DDNS解析的域名作为upstream,请不要使用上述方法配置proxy_pass。另外要尽量减少set变量。