basecamp/kamal · error · Kamal::ConfigurationError

Conflicting proxy run configurations for host #{host}

Error message

Conflicting proxy run configurations for host #{host}

What it means

Kamal::Configuration#ensure_no_conflicting_proxy_runs gathers, for every host, the proxy `run` option hash from each role and accessory present on that host (via proxy_runs, which maps host_roles(host) plus host_accessories(host) to their proxy.run). If the same host receives more than one distinct run configuration, Kamal cannot decide which custom docker run options to launch the proxy with, so it raises with the host name.

Source

Thrown at lib/kamal/configuration.rb:422

      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 > 1
          raise Kamal::ConfigurationError, "Conflicting proxy run configurations for host #{host}"
        end
      end
    end

    def proxy_runs(host)
      (host_roles(host) + host_accessories(host)).map(&:proxy).compact.map(&:run).compact
    end

    def role_names
      raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
    end

    def ensure_valid_hooks_output!
      case raw_config.hooks_output
      when Symbol, String
        validate_hooks_output_level!(raw_config.hooks_output.to_sym)
      when Hash
        raw_config.hooks_output.each { |hook, level| validate_hooks_output_level!(level.to_sym, hook) }

View on GitHub (pinned to eee0083b38)

Solutions

  1. Inspect `kamal config` for each role/accessory on the failing host and make their `proxy: { run: }` hashes identical — usually by defining run options once at the top-level proxy and removing per-role overrides.
  2. Or move the differing role/accessory to a separate host.
  3. If the difference is unintentional (stale copy-paste), delete the duplicate run block so all entries on that host agree.

Example fix

# config/deploy.yml — before
servers:
  web:
    hosts: [ "1.2.3.4" ]
    proxy:
      run:
        network: app-net
  api:
    hosts: [ "1.2.3.4" ]
    proxy:
      run:
        network: api-net

# after
proxy:
  run:
    network: app-net
servers:
  web:
    hosts: [ "1.2.3.4" ]
  api:
    hosts: [ "1.2.3.4" ]
Defensive patterns

Strategy: validation

Validate before calling

def proxy_runs_uniq?(raw)
  hosts_to_run = Hash.new { |h, k| h[k] = [] }
  raw["servers"].to_a.each do |_name, entry|
    next unless entry.is_a?(Hash)
    run = entry.dig("proxy", "run")
    hosts = entry["hosts"] || entry
    Array(hosts).each do |h|
      host = h.is_a?(Hash) ? h.keys.first : h
      hosts_to_run[host] << run
    end
  end
  hosts_to_run.values.all? { |runs| runs.compact.uniq.size <= 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

When it happens

Trigger: Two roles sharing a host where each sets a different `proxy: { run: }` block (e.g. different network or labels); an accessory on the same host as a web role defining its own proxy.run that differs from the role's; per-role proxy run overrides added during an upgrade while the global proxy config still differs.

Common situations: Custom proxy run options (logging, ulimits, networks) rolled out per role; accessories like a monitoring agent attaching to the proxy; consolidating roles onto one machine making previously-divergent run configs collide.

Related errors


AI-assisted analysis of basecamp/kamal@eee0083b38 (2026-08-21). Data as JSON: /api/errors/d992bef5616d4e7e. Report an issue: GitHub.