Skip to content

Commit f1a9a09

Browse files
authored
Merge pull request #1265 from phoozle/proxy-bind-ip
Add proxy boot_config --publish-ip argument
2 parents 620b132 + 1c8a56b commit f1a9a09

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

lib/kamal/cli/proxy.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ def boot
2323

2424
desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration"
2525
option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
26+
option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces"
2627
option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTP_PORT, desc: "HTTP port to publish on the host"
2728
option :https_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTPS_PORT, desc: "HTTPS port to publish on the host"
2829
option :log_max_size, type: :string, default: Kamal::Configuration::PROXY_LOG_MAX_SIZE, desc: "Max size of proxy logs"
@@ -31,7 +32,7 @@ def boot_config(subcommand)
3132
case subcommand
3233
when "set"
3334
boot_options = [
34-
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port]) if options[:publish]),
35+
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port], options[:publish_host_ip]) if options[:publish]),
3536
*(KAMAL.config.proxy_logging_args(options[:log_max_size])),
3637
*options[:docker_options].map { |option| "--#{option}" }
3738
]

lib/kamal/configuration.rb

+28-2
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,16 @@ def env_tag(name)
249249
env_tags.detect { |t| t.name == name.to_s }
250250
end
251251

252-
def proxy_publish_args(http_port, https_port)
253-
argumentize "--publish", [ "#{http_port}:#{PROXY_HTTP_PORT}", "#{https_port}:#{PROXY_HTTPS_PORT}" ]
252+
def proxy_publish_args(http_port, https_port, bind_ips = nil)
253+
ensure_valid_bind_ips(bind_ips)
254+
255+
(bind_ips || [ nil ]).map do |bind_ip|
256+
bind_ip = format_bind_ip(bind_ip)
257+
publish_http = [ bind_ip, http_port, PROXY_HTTP_PORT ].compact.join(":")
258+
publish_https = [ bind_ip, https_port, PROXY_HTTPS_PORT ].compact.join(":")
259+
260+
argumentize "--publish", [ publish_http, publish_https ]
261+
end.join(" ")
254262
end
255263

256264
def proxy_logging_args(max_size)
@@ -344,6 +352,15 @@ def ensure_valid_kamal_version
344352
true
345353
end
346354

355+
def ensure_valid_bind_ips(bind_ips)
356+
bind_ips.present? && bind_ips.each do |ip|
357+
next if ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex
358+
raise ArgumentError, "Invalid publish IP address: #{ip}"
359+
end
360+
361+
true
362+
end
363+
347364
def ensure_retain_containers_valid
348365
raise Kamal::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1
349366

@@ -375,6 +392,15 @@ def ensure_unique_hosts_for_ssl_roles
375392
true
376393
end
377394

395+
def format_bind_ip(ip)
396+
# Ensure IPv6 address inside square brackets - e.g. [::1]
397+
if ip =~ Resolv::IPv6::Regex && ip !~ /\[.*\]/
398+
"[#{ip}]"
399+
else
400+
ip
401+
end
402+
end
403+
378404
def role_names
379405
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
380406
end

test/cli/proxy_test.rb

+26
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,32 @@ class CliProxyTest < CliTestCase
281281
end
282282
end
283283

284+
test "boot_config set bind IP" do
285+
run_command("boot_config", "set", "--publish-host-ip", "127.0.0.1").tap do |output|
286+
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
287+
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
288+
assert_match "Uploading \"--publish 127.0.0.1:80:80 --publish 127.0.0.1:443:443 --log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output
289+
end
290+
end
291+
end
292+
293+
test "boot_config set multiple bind IPs" do
294+
run_command("boot_config", "set", "--publish-host-ip", "127.0.0.1", "--publish-host-ip", "::1").tap do |output|
295+
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
296+
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
297+
assert_match "Uploading \"--publish 127.0.0.1:80:80 --publish 127.0.0.1:443:443 --publish [::1]:80:80 --publish [::1]:443:443 --log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output
298+
end
299+
end
300+
end
301+
302+
test "boot_config set invalid bind IPs" do
303+
exception = assert_raises do
304+
run_command("boot_config", "set", "--publish-host-ip", "1.2.3.invalidIP", "--publish-host-ip", "::1")
305+
end
306+
307+
assert_includes exception.message, "Invalid publish IP address: 1.2.3.invalidIP"
308+
end
309+
284310
test "boot_config set docker options" do
285311
run_command("boot_config", "set", "--docker_options", "label=foo=bar", "add_host=thishost:thathost").tap do |output|
286312
%w[ 1.1.1.1 1.1.1.2 ].each do |host|

0 commit comments

Comments
 (0)