caddyserver/caddy · error
server listening on %v is HTTP, but attempts to configure TL
Error message
server listening on %v is HTTP, but attempts to configure TLS connection policies
What it means
A server classified as HTTP (because at least one of its addresses is http:// or uses http_port) also carries TLS connection policies. Connection policies only make sense where TLS terminates, so applying them to a plaintext server is a logical conflict and adaptation aborts.
Source
Thrown at caddyconfig/httpcaddyfile/httptype.go:1161
httpsPort := strconv.Itoa(caddyhttp.DefaultHTTPSPort)
if hsp, ok := options["https_port"].(int); ok {
httpsPort = strconv.Itoa(hsp)
}
var httpOrHTTPS string
checkAndSetHTTP := func(addr Address) error {
if httpOrHTTPS == "HTTPS" {
errMsg := fmt.Errorf("server listening on %v is configured for HTTPS and cannot natively multiplex HTTP and HTTPS: %s",
srv.Listen, addr.Original)
if addr.Scheme == "" && addr.Host == "" {
errMsg = fmt.Errorf("%s (try specifying https:// in the address)", errMsg)
}
return errMsg
}
if len(srv.TLSConnPolicies) > 0 {
// any connection policies created for an HTTP server
// is a logical conflict, as it would enable HTTPS
return fmt.Errorf("server listening on %v is HTTP, but attempts to configure TLS connection policies", srv.Listen)
}
httpOrHTTPS = "HTTP"
return nil
}
checkAndSetHTTPS := func(addr Address) error {
if httpOrHTTPS == "HTTP" {
return fmt.Errorf("server listening on %v is configured for HTTP and cannot natively multiplex HTTP and HTTPS: %s",
srv.Listen, addr.Original)
}
httpOrHTTPS = "HTTPS"
return nil
}
for _, sblock := range serverBlocks {
for _, addr := range sblock.parsedKeys {
if addr.Scheme == "http" || addr.Port == httpPort {
if err := checkAndSetHTTP(addr); err != nil {
return errView on GitHub (pinned to 50e54ee279)
Solutions
- Remove the `tls` directive/policy from the http:// site block
- Change the site address to `https://` if TLS should terminate at Caddy
- Move the TLS-terminating site to its own port/server
Example fix
# before
http://example.com {
tls internal
respond "hi"
}
# after
http://example.com {
respond "hi"
} Defensive patterns
Strategy: validation
Validate before calling
# Site blocks with http:// scheme must not contain a tls directive
for block in blocks:
if block.scheme == 'http' and block.has_directive('tls'):
raise ConfigError('tls on plaintext site: ' + block.key) Prevention
- Remove tls from sites fronted by an external TLS terminator
- Prefer auto_https defaults instead of hand-managed schemes
- Lint for `tls` inside `http://` blocks
When it happens
Trigger: A site block with an `http://` address that also defines `tls` settings (e.g. `http://example.com { tls internal }`), or a global TLS policy attached via global options to a server whose blocks are all HTTP, producing non-empty srv.TLSConnPolicies when checkAndSetHTTP runs.
Common situations: Leftover `tls` directive after switching a site to `http://` (e.g. behind another TLS-terminating proxy), or a `tls` global policy plus `http_port` sites on the same server.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- two policies with same match criteria have conflicting ALPN:
- two policies with same match criteria have conflicting ciphe
- two policies with same match criteria have conflicting curve
- two policies with same match criteria have conflicting defau
- two policies with same match criteria have conflicting fallb
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/8232d6ed99d527c8.
Report an issue: GitHub.