basecamp/kamal · error · Kamal::ConfigurationError
Different roles can't share the same host for SSL: #{duplica
Error message
Different roles can't share the same host for SSL: #{duplicates.join(", ")} What it means
Kamal::Configuration#ensure_unique_hosts_for_ssl_roles collects the proxy hosts of every role with `ssl: true`, tallies them, and raises if any host appears more than once. When a host runs the proxy for multiple SSL roles, the roles would fight over certificates and proxy configuration, so Kamal requires each SSL-enabled role's proxy hosts to be unique across roles.
Source
Thrown at lib/kamal/configuration.rb:403
if hooks.any?
raise Kamal::ConfigurationError, "Found #{hooks.join(", ")}, these should be renamed to (pre|post)-proxy-reboot"
end
true
end
def ensure_one_host_for_ssl_roles
roles.each(&:ensure_one_host_for_ssl)
true
end
def ensure_unique_hosts_for_ssl_roles
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?
true
end
def ensure_local_registry_remote_builder_has_ssh_url
if registry.local? && builder.remote?
unless URI(builder.remote).scheme == "ssh"
raise Kamal::ConfigurationError, "Local registry with remote builder requires an SSH URL (e.g., ssh://user@host)"
end
end
true
end
def ensure_no_conflicting_proxy_runs
all_hosts.each do |host|
run_configs = proxy_runs(host)
if run_configs.uniq.size > 1View on GitHub (pinned to eee0083b38)
Solutions
- Restructure so only one ssl role includes each host — typically make the primary `web` role the only ssl role on that machine.
- If two roles must share a host, drop `ssl: true` from the secondary role and terminate SSL once at the primary role's proxy.
- Alternatively split the roles onto distinct hosts so the host lists no longer overlap.
Example fix
# config/deploy.yml — before
servers:
web:
hosts: [ "1.2.3.4" ]
ssl: true
admin:
hosts: [ "1.2.3.4" ]
ssl: true
# after
servers:
web:
hosts: [ "1.2.3.4" ]
ssl: true
admin:
hosts: [ "1.2.3.4" ] Defensive patterns
Strategy: validation
Validate before calling
def ssl_hosts_unique?(raw)
hosts = raw["servers"].to_a.filter_map do |_name, entry|
next unless entry.is_a?(Hash) && entry["ssl"]
Array(entry["hosts"]).map { |h| h.is_a?(Hash) ? h.keys.first : h }
end.flatten
hosts.tally.values.all? { |c| c == 1 }
end Try / catch
begin
config = Kamal::Configuration.new(create_config_files: false)
rescue Kamal::ConfigurationError => e
puts "Deploy config invalid: #{e.message}"
exit 1
end Prevention
- Designate a single ssl-terminating role (usually web) per host.
- Before enabling ssl on a role, list which machines that role shares with other ssl roles.
- When consolidating servers, re-audit ssl flags on every role touching the shared host.
When it happens
Trigger: Two roles (e.g. `web` and `admin`) both having hosts entries pointing at the same server while each sets `ssl: true`; adding `ssl: true` to a second role that shares a machine with the primary web role; host aliases resolving to the same literal host string in two ssl roles' lists.
Common situations: Consolidating what were separate servers onto one box for cost; copying role blocks and forgetting to prune hosts; enabling ssl on additional roles that share the proxy host.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- Conflicting proxy run configurations for host #{host}
- SSL is only supported on a single server unless you provide
- The primary_role #{primary_role_name} isn't defined
- No servers specified for the #{primary_role.name} primary_ro
- No servers specified for the #{role.name} role. You can igno
AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21).
Data as JSON: /api/errors/6fafd02d6012485b.
Report an issue: GitHub.