socketry/falcon · warning
Unable to resolve #{hostname}!
Error message
Unable to resolve #{hostname}! What it means
This is a Console warning, not a raised exception. The proxy environment builds a hosts hash keyed by each upstream environment's authority, but only environments defining all three keys :authority, :ssl_context and :endpoint are registered (lib/falcon/environment/proxy.rb:35-49). During the TLS handshake, OpenSSL's SNI callback (servername_cb installed by ssl_context) calls host_context with the hostname the client sent; when it is not a key in hosts, Falcon warns 'Unable to resolve <hostname>!', logs the known hostnames, and returns nil — so no per-host certificate context is selected and the handshake fails.
Source
Thrown at lib/falcon/environment/proxy.rb:64
end
return hosts
end
# Look up the host context for the given hostname, and update the socket hostname if necessary.
# @parameter socket [OpenSSL::SSL::SSLSocket] The incoming connection.
# @parameter hostname [String] The negotiated hostname.
def host_context(socket, hostname)
hosts = self.hosts
if host = hosts[hostname]
Console.debug(self){"Resolving #{hostname} -> #{host}"}
socket.hostname = hostname
return host.ssl_context
else
Console.warn(self, hosts: hosts.keys){"Unable to resolve #{hostname}!"}
return nil
end
end
# Generate an SSL context which delegates to {host_context} to multiplex based on hostname.
def ssl_context
@server_context ||= OpenSSL::SSL::SSLContext.new.tap do |context|
context.servername_cb = Proc.new do |socket, hostname|
self.host_context(socket, hostname)
end
context.session_id_context = self.ssl_session_id
context.set_params(
ciphers: ::Falcon::TLS::SERVER_CIPHERS,
verify_mode: ::OpenSSL::SSL::VERIFY_NONE,
)View on GitHub (pinned to 5107b0713f)
Solutions
- Register the missing hostname: add an environment whose authority exactly matches the SNI name clients send (each must define authority, ssl_context and endpoint)
- For local tests, connect with the configured name: curl --resolve app.example.com:443:127.0.0.1 https://app.example.com/
- Audit Falcon::Environment::Proxy#hosts.keys and add any DNS alias as its own environment
Example fix
# before: proxy only registers authority 'app.example.com'
# curl https://localhost/ -> Console.warn: Unable to resolve localhost!
# host_context returns nil and the TLS handshake fails
class ProxyEnvironment
include Falcon::Environment::Proxy
def environments
[app_environment] # authority 'app.example.com'
end
end
# after: every hostname the proxy answers is registered
class ProxyEnvironment
include Falcon::Environment::Proxy
def environments
[app_environment, localhost_environment]
# authorities: 'app.example.com', 'localhost'
# each environment defines :authority, :ssl_context and :endpoint,
# otherwise Proxy#hosts silently skips it
end
end Defensive patterns
Strategy: validation
Validate before calling
# Before exposing the proxy: assert every served hostname is registered
hosts = proxy_environment.hosts # keys are exactly the SNI names answered
expected = %w[app.example.com www.app.example.com localhost]
missing = expected - hosts.keys
abort "Proxy has no host context for: #{missing.join(', ')}" unless missing.empty? Prevention
- Assert at boot that every DNS name pointing at the proxy appears in proxy_environment.hosts.keys
- Give each proxied environment authority, ssl_context and endpoint — missing any one silently drops it from hosts
- Test with the real SNI name (curl --resolve host:443:127.0.0.1 https://host/), not localhost or an IP
- Alert on Console 'Unable to resolve' lines in production logs; each one is a client failing SNI
When it happens
Trigger: A client connects with SNI 'localhost', a bare IP, or any hostname that differs from the configured authority (www.example.com vs example.com); or a proxied environment is silently excluded from hosts because it lacks one of authority/ssl_context/endpoint, so its hostname can never resolve.
Common situations: Local testing with curl https://localhost/ against a proxy configured only for the production hostname; adding a vhost but forgetting the authority or ssl_context key; extra DNS aliases or CNAMEs pointing at the proxy that were never declared as environments; monitoring probes connecting by IP without a matching SNI name.
Related errors
- Could not find config/serve.rb or config.ru in #{root}!
- Unsupported application configuration: #{path}!
- `Falcon::Server.middleware` is deprecated, use `.rack_middle
- Async::Container::Supervisor is replaced by Async::Service::
AI-assisted analysis of socketry/falcon@5107b0713f (2026-08-23).
Data as JSON: /api/errors/f4eb0c9a0cc27942.
Report an issue: GitHub.