Skip to content

Commit

Permalink
Merge pull request #1000 from kpumuk/hosts
Browse files Browse the repository at this point in the history
Allow specifying multiple hosts for kamal-proxy via an array
  • Loading branch information
djmb authored Sep 30, 2024
2 parents 7f6095c + e75365c commit b4bcf35
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/kamal/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ def ensure_one_host_for_ssl_roles
end

def ensure_unique_hosts_for_ssl_roles
hosts = roles.select(&:ssl?).map { |role| role.proxy.host }
hosts = roles.select(&:ssl?).flat_map { |role| role.proxy.hosts }
duplicates = hosts.tally.filter_map { |host, count| host if count > 1 }

raise Kamal::ConfigurationError, "Different roles can't share the same host for SSL: #{duplicates.join(", ")}" if duplicates.any?
Expand Down
9 changes: 6 additions & 3 deletions lib/kamal/configuration/docs/proxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@
# `proxy: true` or providing a proxy configuration.
proxy:

# Host
# Hosts
#
# The hosts that will be used to serve the app. The proxy will only route requests
# to this host to your app.
#
# If no hosts are set, then all requests will be forwarded, except for matching
# requests for other apps deployed on that server that do have a host set.
#
# Specify one of `host` or `hosts`.
host: foo.example.com
# If multiple hosts are needed, these can be specified by comma-separating the hosts.
host: foo.example.com,bar.example.com
hosts:
- foo.example.com
- bar.example.com

# App port
#
Expand Down
6 changes: 3 additions & 3 deletions lib/kamal/configuration/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ def ssl?
proxy_config.fetch("ssl", false)
end

def host
proxy_config["host"]
def hosts
proxy_config["hosts"] || proxy_config["host"]&.split(",") || []
end

def deploy_options
{
host: proxy_config["host"],
host: hosts,
tls: proxy_config["ssl"] ? true : nil,
"deploy-timeout": seconds_duration(config.deploy_timeout),
"drain-timeout": seconds_duration(config.drain_timeout),
Expand Down
6 changes: 5 additions & 1 deletion lib/kamal/configuration/validator/proxy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ def validate!
unless config.nil?
super

if config["host"].blank? && config["ssl"]
if config["host"].blank? && config["hosts"].blank? && config["ssl"]
error "Must set a host to enable automatic SSL"
end

if (config.keys & [ "host", "hosts" ]).size > 1
error "Specify one of 'host' or 'hosts', not both"
end
end
end
end
16 changes: 16 additions & 0 deletions test/commands/app_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,22 @@ class CommandsAppTest < ActiveSupport::TestCase
new_command.deploy(target: "172.1.0.2").join(" ")
end

test "deploy with SSL" do
@config[:proxy] = { "ssl" => true, "host" => "example.com" }

assert_equal \
"docker exec kamal-proxy kamal-proxy deploy app-web --target \"172.1.0.2:80\" --host \"example.com\" --tls --deploy-timeout \"30s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\"",
new_command.deploy(target: "172.1.0.2").join(" ")
end

test "deploy with SSL targeting multiple hosts" do
@config[:proxy] = { "ssl" => true, "hosts" => [ "example.com", "anotherexample.com" ] }

assert_equal \
"docker exec kamal-proxy kamal-proxy deploy app-web --target \"172.1.0.2:80\" --host \"example.com\" --host \"anotherexample.com\" --tls --deploy-timeout \"30s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\"",
new_command.deploy(target: "172.1.0.2").join(" ")
end

test "remove" do
assert_equal \
"docker exec kamal-proxy kamal-proxy remove app-web",
Expand Down
15 changes: 15 additions & 0 deletions test/configuration/proxy_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,26 @@ class ConfigurationProxyTest < ActiveSupport::TestCase
assert_equal true, config.proxy.ssl?
end

test "ssl with multiple hosts passed via host" do
@deploy[:proxy] = { "ssl" => true, "host" => "example.com,anotherexample.com" }
assert_equal true, config.proxy.ssl?
end

test "ssl with multiple hosts passed via hosts" do
@deploy[:proxy] = { "ssl" => true, "hosts" => [ "example.com", "anotherexample.com" ] }
assert_equal true, config.proxy.ssl?
end

test "ssl with no host" do
@deploy[:proxy] = { "ssl" => true }
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
end

test "ssl with both host and hosts" do
@deploy[:proxy] = { "ssl" => true, host: "example.com", hosts: [ "anotherexample.com" ] }
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
end

test "ssl false" do
@deploy[:proxy] = { "ssl" => false }
assert_not config.proxy.ssl?
Expand Down
11 changes: 11 additions & 0 deletions test/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -377,4 +377,15 @@ class ConfigurationTest < ActiveSupport::TestCase

assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
end

test "two proxy ssl roles with same host in a hosts array" do
@deploy_with_roles[:servers]["web"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "hosts" => [ "foo.example.com", "bar.example.com" ] } }
@deploy_with_roles[:servers]["workers"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "hosts" => [ "www.example.com", "foo.example.com" ] } }

exception = assert_raises(Kamal::ConfigurationError) do
Kamal::Configuration.new(@deploy_with_roles)
end

assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
end
end

0 comments on commit b4bcf35

Please sign in to comment.