{"record":{"id":"11750b8b1462521b","repo":"basecamp/kamal","slug":"invalid-publish-ip-address-ip","errorCode":null,"errorMessage":"Invalid publish IP address: #{ip}","messagePattern":"Invalid publish IP address: #(.+?)","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/kamal/configuration/proxy/boot.rb","lineNumber":110,"sourceCode":"  end\n\n  def error_pages_container_directory\n    File.join app_container_directory, \"error_pages\"\n  end\n\n  def tls_directory\n    File.join app_directory, \"tls\"\n  end\n\n  def tls_container_directory\n    File.join app_container_directory, \"tls\"\n  end\n\n  private\n    def ensure_valid_bind_ips(bind_ips)\n      bind_ips.present? && bind_ips.each do |ip|\n        next if ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex\n        raise ArgumentError, \"Invalid publish IP address: #{ip}\"\n      end\n\n      true\n    end\n\n    def format_bind_ip(ip)\n      # Ensure IPv6 address inside square brackets - e.g. [::1]\n      if ip =~ Resolv::IPv6::Regex && ip !~ /\\A\\[.*\\]\\z/\n        \"[#{ip}]\"\n      else\n        ip\n      end\n    end\nend\n","sourceCodeStart":92,"sourceCodeEnd":125,"githubUrl":"https://github.com/basecamp/kamal/blob/eee0083b38661c3707c6b6052cc89e85038a096c/lib/kamal/configuration/proxy/boot.rb#L92-L125","documentation":"Kamal::Configuration::Proxy::Boot#ensure_valid_bind_ips validates each publish/bind IP extracted from the proxy configuration against Resolv::IPv4::Regex and Resolv::IPv6::Regex. Any string that is not a syntactically valid IPv4 or IPv6 literal (hostnames, ranges, malformed addresses) raises this ArgumentError with the offending value, because Docker's --publish flag requires a literal bind address.","triggerScenarios":"A proxy `publish:` spec with a hostname instead of an IP (e.g. `myhost.example.com:80:80`); a malformed IPv4 like `192.168.1` or `999.1.1.1`; passing a whole host:port:port string where only the bare IP was expected; an IPv6 entry with wrong abbreviation syntax in the bind position.","commonSituations":"Trying to bind a service to a domain name instead of an interface IP; typos in hand-written publish args; NAT/private-network configs where developers guess internal addresses; IPv6 entries with stray colons.","solutions":["Replace the invalid value with a literal IPv4 or IPv6 address (e.g. `127.0.0.1`, `192.168.1.10`, `::1`).","If you only meant to fix the port mapping, keep the format IP:HOST_PORT:CONTAINER_PORT and ensure the first segment is a bare valid IP.","For hostnames, resolve them to IPs first (dig/host) — docker publish cannot bind a DNS name."],"exampleFix":"# config/deploy.yml — before (accessory proxy publish)\naccessories:\n  admin:\n    proxy:\n      host: 1.2.3.4\n      publish:\n        - \"myhost.example.com:8080:80\"\n\n# after\naccessories:\n  admin:\n    proxy:\n      host: 1.2.3.4\n      publish:\n        - \"192.168.1.10:8080:80\"","handlingStrategy":"validation","validationCode":"require \"resolv\"\n\ndef valid_publish_ips?(publish_specs)\n  Array(publish_specs).all? do |spec|\n    ip = spec.to_s.split(\":\").first\n    ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex\n  end\nend","typeGuard":"require \"resolv\"\n\ndef valid_bind_ip?(value)\n  value.is_a?(String) &&\n    (value =~ Resolv::IPv4::Regex || value =~ Resolv::IPv6::Regex)\nend","tryCatchPattern":"begin\n  Kamal::Configuration.new(create_config_files: false)\nrescue ArgumentError => e\n  abort \"#{e.message} — publish binds need literal IPv4/IPv6 addresses\"\nend","preventionTips":["Always bind literal IPs (127.0.0.1, private LAN IPs, ::1), never hostnames.","Lint publish strings with Resolv before committing proxy config.","For IPv6, write the canonical form and let kamal bracket it in docker args."],"tags":["kamal","proxy","ip-address","validation","docker"],"backgroundTag":"invalid-ip-address","analyzedSha":"eee0083b38661c3707c6b6052cc89e85038a096c","analyzedAt":"2026-08-21T15:17:22.045Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}