Location matching for catch-all redirect

1. Caddy version (caddy version):

v2.2.0-rc.3

2. How I run Caddy:

a. System environment:

systemd on Ubuntu 18.04 (No docker)

b. Command:

/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile

c. Service/unit/compose file:

# caddy.service
#
# For using Caddy with a config file.
#
# Make sure the ExecStart and ExecReload commands are correct
# for your installation.
#
# See https://caddyserver.com/docs/install for instructions.
#
# WARNING: This service does not use the --resume flag, so if you
# use the API to make changes, they will be overwritten by the
# Caddyfile next time the service is restarted. If you intend to
# use Caddy's API to configure it, add the --resume flag to the
# `caddy run` command or use the caddy-api.service file instead.

[Unit]
Description=Caddy
Documentation=https://caddyserver.com/docs/
After=network.target

[Service]
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

d. My complete Caddyfile or JSON config:

{
  email <redacted>
  default_sni get.geojs.io
}

http://*.geojs.io {
  respond /check 200
  redir https://{host}{uri}
}

https://*.geojs.io {
  reverse_proxy 127.0.0.1:8080
  encode zstd gzip
  # Do not log!
  log {
    output discard
  }
  tls {
    dns cloudflare <redacted>
  }
}

3. The problem I’m having:

I have a requirement to respond to a HTTP request that comes in over HTTP (not HTTPS!) but otherwise want to redirect everything else to HTTPs as per Caddy’s default behavior but I’m having trouble getting location matching going right.

I basically want to replicate this nginx config:

server {

	listen 80 default_server;
	listen [::]:80 default_server;

	location / {
		return 301 https://$host$request_uri;
	}

	location /check {
		default_type text/plain;
		return 200 "peachy";
	}

}

If I hit http://example.com/check I get a 200 back directly form Nginx but everything else gets redirected to HTTPS.

I can’t get the pattern matching going in Caddy however. With my config above the second redir catches everything and the first respond doesn’t do anything.

4. Error messages and/or full log output:

N/A

5. What I already tried:

I’ve tried the above config I’ve pasted along with changing some of the other lines around like:

  respond /check 200
  redir /* https://{host}{uri}

Or

  redir / https://{host}{uri}
  respond /check 200

But I seem to either end up getting Caddy to only respond with a 200 for the /check endpoint and no redirect elsewhere OR a redirect everywhere, and no 200 on the /check endpoint.

6. Links to relevant resources:


Finally let me just thank everyone for Caddy! Its a fantastic piece of software and I’ve genuinely really enjoyed using it. Going to save me a lot of pain having to rejig a lot of janky certificate handling I’ve got going on my application at the moment.

The reason you’re not getting the expected behaviour is because Caddy sorts directives based on a predetermined order, which you can find here:

redir is sorted before respond, regardless of which order you put them in your Caddyfile. To override that order, you should use route which will keep directives in the order they’re listed in your Caddyfile:

http://*.geojs.io {
	route {
		respond /check 200
		redir https://{host}{uri}
	}
}

Ahhh thankyou so much! This is exactly what I needed!

1 Like

This topic was automatically closed after 30 days. New replies are no longer allowed.