caddyserver/caddy · error
upstream address has conflicting scheme (https://) and port
Error message
upstream address has conflicting scheme (https://) and port (:80, the HTTP port)
What it means
The upstream declares scheme https:// but an explicit port 80 (the plaintext HTTP default). This is the mirror of the http://:443 conflict: Caddy would be asked to speak TLS to a plaintext port and fails fast at config load.
Source
Thrown at modules/caddyhttp/reverseproxy/addresses.go:115
}
}
if port == "" {
port = toURL.Port()
}
// there is currently no way to perform a URL rewrite between choosing
// a backend and proxying to it, so we cannot allow extra components
// in backend URLs
if toURL.Path != "" || toURL.RawQuery != "" || toURL.Fragment != "" {
return parsedAddr{}, fmt.Errorf("for now, URLs for proxy upstreams only support scheme, host, and port components")
}
// ensure the port and scheme aren't in conflict
if toURL.Scheme == "http" && port == "443" {
return parsedAddr{}, fmt.Errorf("upstream address has conflicting scheme (http://) and port (:443, the HTTPS port)")
}
if toURL.Scheme == "https" && port == "80" {
return parsedAddr{}, fmt.Errorf("upstream address has conflicting scheme (https://) and port (:80, the HTTP port)")
}
if toURL.Scheme == "h2c" && port == "443" {
return parsedAddr{}, fmt.Errorf("upstream address has conflicting scheme (h2c://) and port (:443, the HTTPS port)")
}
// if port is missing, attempt to infer from scheme
if port == "" {
switch toURL.Scheme {
case "", "http", "h2c":
port = "80"
case "https":
port = "443"
}
}
scheme, host = toURL.Scheme, toURL.Hostname()
} else {
var err errorView on GitHub (pinned to 50e54ee279)
Solutions
- Use 'http://backend:80' (or just 'backend:80') when the backend is plaintext.
- Point the https:// upstream at the actual TLS port (443 or custom).
- If TLS terminates upstream of the backend, terminate it in Caddy instead and proxy plaintext.
Example fix
# before reverse_proxy https://backend:80 # after reverse_proxy http://backend:80
Defensive patterns
Strategy: validation
Validate before calling
func httpsOnHttpPort(u *url.URL) bool {
return u.Scheme == "https" && u.Port() == "80"
}
if parsed, err := url.Parse(upstream); err == nil && httpsOnHttpPort(parsed) {
return fmt.Errorf("upstream %q pairs https:// with the plaintext port 80", upstream)
} Prevention
- Use http:// (or bare host:port) for plaintext backends on 80.
- Document which upstream ports are TLS vs plaintext per service.
- Validate with 'caddy validate' after changing backend ports.
When it happens
Trigger: 'reverse_proxy https://backend:80' or 'caddy reverse-proxy --to https://host:80'.
Common situations: Backend behind a TLS-terminating load balancer that listens on 80 while the config kept https://; mixing up internal (plaintext) and external (TLS) ports.
Related errors
- upstream address has conflicting scheme (http://) and port (
- due to parsing difficulties, placeholders are not allowed wh
- parsing upstream URL: %v
- parsing upstream URL: parse "%v": port range invalid: %v
- for now, URLs for proxy upstreams only support scheme, host,
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/dba0bce22f57c78d.
Report an issue: GitHub.