Fixes #44. Respect DNS TTL for proxies.

https://tenzer.dk/nginx-with-dynamic-upstreams/

Nginx currently does not resolve domains passed to `proxy_pass`. By
using a variable it works around the issue.

This also fixes a bug where fallback proxy match would just match the
first proxy vs the longest.
parent fb0a4954
......@@ -8,7 +8,8 @@ class NginxConfig
encoding: "UTF-8",
clean_urls: false,
https_only: false,
worker_connections: 512
worker_connections: 512,
resolver: "8.8.8.8"
}
def initialize(json_file)
......@@ -18,20 +19,23 @@ class NginxConfig
json["port"] ||= ENV["PORT"] || 5000
json["root"] ||= DEFAULT[:root]
json["encoding"] ||= DEFAULT[:encoding]
index = 0
json["proxies"] ||= {}
json["proxies"].each do |loc, hash|
evaled_origin = NginxConfigUtil.interpolate(hash['origin'], ENV)
if evaled_origin != "/"
json["proxies"][loc].merge!("origin" => evaled_origin + "/")
end
uri = URI(evaled_origin)
uri = URI(evaled_origin)
json["proxies"][loc]["path"] = uri.path
uri.path = ""
json["proxies"][loc]["host"] = uri.to_s
redirect_scheme = uri.scheme == "https" ? "http" : "https"
json["proxies"][loc]["redirect"] = uri.dup.tap {|u| u.scheme = redirect_scheme }.to_s
json["proxies"][loc]["redirect"] += "/" if !uri.to_s.end_with?("/")
json["proxies"][loc]["name"] = "upstream_endpoint_#{index}"
cleaned_path = uri.path
cleaned_path.chop! if cleaned_path.end_with?("/")
json["proxies"][loc]["path"] = cleaned_path
json["proxies"][loc]["host"] = uri.dup.tap {|u| u.path = '' }.to_s
%w(http https).each do |scheme|
json["proxies"][loc]["redirect_#{scheme}"] = uri.dup.tap {|u| u.scheme = scheme }.to_s
json["proxies"][loc]["redirect_#{scheme}"] += "/" if !uri.to_s.end_with?("/")
end
index += 1
end
json["clean_urls"] ||= DEFAULT[:clean_urls]
......@@ -47,6 +51,17 @@ class NginxConfig
json["error_page"] ||= nil
json["debug"] ||= ENV['STATIC_DEBUG']
nameservers = []
if File.exist?("/etc/resolv.conf")
File.open("/etc/resolv.conf", "r").each do |line|
next unless md = line.match(/^nameserver\s*(\S*)/)
nameservers << md[1]
end
end
nameservers << [DEFAULT[:resolver]] unless nameservers.empty?
json["resolver"] = nameservers.join(" ")
json.each do |key, value|
self.class.send(:define_method, key) { value }
end
......
......@@ -28,11 +28,16 @@ module NginxConfigUtil
def self.match_proxies(proxies, uri)
return false unless proxies
proxies.each do |proxy|
return proxy if Regexp.compile("^#{proxy}") =~ uri
matched = proxies.select do |proxy|
Regexp.compile("^#{proxy}") =~ uri
end
false
# return the longest matched proxy
if matched.any?
matched.max_by {|proxy| proxy.size }
else
false
end
end
def self.match_redirects(redirects, uri)
......
......@@ -41,6 +41,9 @@ http {
<% if error_page %>
error_page 404 500 /<%= error_page %>;
<% end %>
<% if proxies.any? %>
resolver <%= resolver %>;
<% end %>
location / {
mruby_post_read_handler /app/bin/config/lib/ngx_mruby/headers.rb cache;
......@@ -78,11 +81,15 @@ http {
<% end %>
<% proxies.each do |location, hash| %>
set $<%= hash['name'] %> <%= hash['host'] %>;
location <%= location %> {
proxy_pass <%= hash['origin'] %>;
rewrite ^<%= location %>/?(.*) <%= hash['path'] %>/$1 break;
proxy_pass $<%= hash['name'] %>;
proxy_ssl_server_name on;
proxy_redirect default;
proxy_redirect <%= hash["redirect"] %> <%= location %>;
# handle Location rewrites from the proxy properly
<% %w(http https).each do |scheme| %>
proxy_redirect <%= hash["redirect_#{scheme}"] %> <%= location %>;
<% end %>
}
<% end %>
......@@ -94,11 +101,13 @@ http {
# fallback proxy named match
<% proxies.each do |location, hash| %>
location @<%= location %> {
rewrite ^<%= location %>(.*)$ <%= hash['path'] %>/$1 break;
proxy_pass <%= hash['host'] %>;
rewrite ^<%= location %>/?(.*)$ <%= hash['path'] %>/$1 break;
# can reuse variable set above
proxy_pass $<%= hash['name'] %>;
proxy_ssl_server_name on;
proxy_redirect default;
proxy_redirect <%= hash["redirect"] %> <%= location %>;
<% %w(http https).each do |scheme| %>
proxy_redirect <%= hash["redirect_#{scheme}"] %> <%= location %>;
<% end %>
}
<% end %>
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment