Autohttps handling

Is there a way to get in a handler before the auto https redirec happens and insert logic that selectively prevents the redirect but not based on the domain?

Which version of Caddy are you using?

Fill out the help topic template, as per the forum rules. We can’t help without understanding what version you’re on, what your existing config looks like, and a deeper explanation of what you’re trying to do specifically.

1. Output of caddy version:

v2.6.1

2. How I run Caddy:

a. System environment:

amazon linux 2

b. Command:

./caddy run --config Caddyfile

d. My complete Caddy config:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "handle": [
                {
                  "encodings": {
                    "gzip": {},
                    "zstd": {}
                  },
                  "handler": "encode",
                  "prefer": [
                    "zstd",
                    "gzip"
                  ]
                },
                {
                  "handler": "reverse_proxy",
                  "upstreams": [
                    {
                      "dial": "localhost:5000"
                    }
                  ]
                }
              ]
            }
          ],
        }
      }
    }
  }
}

3. The problem I’m having:

I would like to prevent the automatic redirect from port 80 (http) to 443 (https) for urls which would get the site listed as a dangerous site but do not see any way to get into the process before the automatic redirect occurs. For example http://example.com/this_is_a_dangerous_file.apk which technically doesn’t exist however a non-404 error results from requesting it because instead you get a 308 redirect

It would be handy to be able to insert a handler which would allow one to prevent the automatic redirect

4. Error messages and/or full log output:

6. Links to relevant resources:

The current options for not automatically having the redirect appear to be:

1 Like

You can override any of the implicit redirect behavior by defining your own :80 site explicitly in the config.

But… are scanners flagging you for redirecting HTTP to HTTPS? That’s ludicrous.

Agreed that it’s dumb! How would you still let the redirect to https continue for the 99% case?

Admittedly my experience on the auto-redirect not with the latest release of caddy, and I’ve assumed that the auto-redirect is still configured the same way and works the same way so I hadn’t tried it on the latest release yet sooo I was just trying to see the below caddy json file and it doesn’t seem to be redirecting at all? This json file was created from a Caddyfile using adapt.

{
  "logging": {
    "logs": {
      "default": {
        "exclude": [
          "http.log.access.log0"
        ]
      },
      "log0": {
        "writer": {
          "filename": "/var/log/access.log",
          "output": "file",
          "roll_keep": 5,
          "roll_keep_days": 30,
          "roll_size_mb": 954
        },
        "include": [
          "http.log.access.log0"
        ]
      }
    }
  },
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "listen": [
            ":443"
          ],
          "routes": [
            {
              "handle": [
                {
                  "encodings": {
                    "gzip": {},
                    "zstd": {}
                  },
                  "handler": "encode",
                  "prefer": [
                    "zstd",
                    "gzip"
                  ]
                },
                {
                  "handler": "reverse_proxy",
                  "upstreams": [
                    {
                      "dial": "localhost:5000"
                    }
                  ]
                }
              ]
            }
          ],
          "logs": {
            "default_logger_name": "log0"
          }
        },
        "srv1": {
          "listen": [
            ":80"
          ],
          "routes": [
            {
              "match": [
                {
                  "host": [
                    "3.128.83.123"
                  ]
                }
              ],
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "static_response"
                        }
                      ]
                    }
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    },
    "tls": {
      "automation": {
        "policies": [
          {
            "issuers": [
              {
                "email": "redacted",
                "module": "acme"
              },
              {
                "email": "redacted",
                "module": "zerossl"
              }
            ],
            "on_demand": true
          }
        ],
        "on_demand": {
          "ask": "http://10.50.1.11/.validvalid"
        }
      }
    }
  }
}

In 2.6, we fixed an issue where explicit configuration was being overridden by implicit redirects. So now, you have :80 defined in your config, so Caddy won’t issue redirects automatically. Otherwise it would override your explicit configuration.

You can still do the redirects yourself of course. Just have a static_response handler send a Location header with a status code of 308.

That’s not true. It still inserts a catch-all redirect at the end of the :80 server, but it just doesn’t put one at the top, if there are no managed domains (which is true in this case because there’s no host matcher in the :443 server).

1 Like

Ah, thank you for correcting me.

I guess I’m not understanding what changed from previous versions that would cause the configuration below not to redirect to https

{
    "apps": {
      "http": {
        "servers": {
          "srv0": {
            "listen": [
              ":443",
              ":80"
            ],
            "routes": [
              {
                "handle":[
                  {
                    "encodings": {
                      "gzip": {},
                      "zstd": {}
                    },
                    "handler": "encode",
                    "prefer": [
                      "zstd",
                      "gzip"
                    ]
                  },
                  {
                    "handler": "reverse_proxy",
                    "upstreams": [
                      {
                        "dial": "localhost:5000"
                      }
                    ]
                  }
                ]
              }
            ],
            "tls_connection_policies": [
                {}
            ]
          },
        }
      },
      "tls": {
        "automation": {
          "policies": [
            {
              "issuers": [
                {
                  "email": "redacted",
                  "module": "acme"
                },
                {
                  "email": "redacted",
                  "module": "zerossl"
                }
              ],
              "on_demand": true
            }
          ],
          "on_demand": {
            "ask": "http://10.50.1.11/.validvalid"
          }
        }
      }
    }
  }

The way I understand it is, your server explicitly listens on :80 and doesn’t have any host matchers to tell the server, “Listen on 80, but my intent is to only serve these domains” – so the server thinks you want to serve any/all domains on port 80.

Thus, the automatic/implicit redirect handler never gets run, because your config explicitly, unconditionally reverse proxies all requests on port 80. And the change in 2.6 is that Caddy won’t override explicit configuration like that.

@francislavoie feel free to correct me if I’m wrong :smiley:

Yeah, basically.

You put :80 here so you’re essentially overriding all the routes Caddy would try to set up for HTTP->HTTPS redirects. Remove :80 from this server and the redirects will happen correctly. Make a second server with :80 with whatever matchers you want, and those will run before the catch-all redirect routes.

1 Like

So removing :80 still binds port 80? Don’t most people want 80 and 443 bound with auto-redirect of 80->443 done automatically?

Yes, because that’s what Caddy’s Automatic HTTPS does; it enables a server on port 80 so that it can:

  1. Solve ACME HTTP challenges
  2. Redirect HTTP requests to HTTPS

This is requirement that the vast majority of users need, so Caddy does these things automatically. See the docs:

Ok, removing that from my config going forward with 2.6. As to the question, is there a mechanism to hook into the redirect system and insert logic to the process beyond what is available here:

Like we said, there’s no need to “hook into” anything.

Just make a :80 server, set up routes in it to match requests according to your requirements (and return a static response with an error status code, or abort the connection, or emit an error).

Caddy will insert its own redirect routes after yours, so yours will take precedence. It’ll catch anything you don’t match and perform the redirect for those.

1 Like