Aborting on unhandled subdomains on shared block for wildcard and base domain

1. Caddy version:

v2.6.4 h1:2hwYqiRwk1tf3VruhMpLcYTg+11fCdr8S3jhNAdnPy8=

2. How I installed, and run Caddy:

Downloaded from caddy website with transform-encoder and vultr. I run caddy via the systemd unit provided with the debian package.

a. System environment:

Linux 5.10.0-21-amd64 #1 SMP Debian 5.10.162-1 (2023-01-21) x86_64 GNU/Linux, systemd

b. Command:

Paste command here.

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 network-online.target
Requires=network-online.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 Caddy config:

# The Caddyfile is an easy way to configure your Caddy web server.
#
# Unless the file starts with a global options block, the first
# uncommented line is always the address of your site.
#
# To use your own domain name (with automatic HTTPS), first make
# sure your domain's A/AAAA DNS records are properly pointed to
# this machine's public IP, then replace the line below with your
# domain name.

(_unauthorized) {
        error {args.0} "Unauthorized" 403
}

*.xinayder.me xinayder.me {
        header {
                # disable FLoC tracking
                Permissions-Policy interest-cohort=()

                # enable HSTS
                Strict-Transport-Security max-age=31536000;

                # disable clients from sniffing the media type
                X-Content-Type-Options nosniff

                # clickjacking protection
                X-Frame-Options DENY

                # keep referrer data off of HTTP connections
                Referrer-Policy no-referrer
        }

        log {
                output file /var/log/caddy/xinayder.me/access.log {
                        roll_size 10MiB
                }

                format transform `{request>remote_ip} - {request>user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
                        time_format "02/Jan/2006:15:04:05 -0700"
                }
        }

        tls cert@xinayder.me {
                dns vultr <REDACTED>
                resolvers 9.9.9.9
        }

        @matrix host matrix.xinayder.me
        handle @matrix {
                reverse_proxy /_matrix/* http://localhost:8008
        }

        # Set this path to your site's directory.
        root * /var/www/xinayder.me
        file_server {
                hide blog tags categories
        }

        #    import _unauthorized /blog/
        #    import _unauthorized /tags/
        #    import _unauthorized /categories/

        #    error blog "Unauthorized" 403
        #    error /blog/index.html "Unauthorized" 403

        handle_errors {
                rewrite * /error.html
                templates
                file_server
        }

        @resume {
                header User-Agent *curl*
                path /
        }

        rewrite @resume /resume.json

        #    handle_errors {
        #        @403 {
        #            expression {http.error.status_code} == 403
        #        }
        #        redir @403 /403.html
        #
        #        @404 {
        #            expression {http.error.status_code} == 404
        #        }
        #        redir @404 /404.html
        #
        #        @500 {
        #            expression {http.error.status_code} == 500
        #        }
        #        redir @500 /500.html
        #    }

        # Another common task is to set up a reverse proxy:
        # reverse_proxy localhost:8080

        # Or serve a PHP site through php-fpm:
        # php_fastcgi localhost:9000

        # Refer to the Caddy docs for more information:
        # https://caddyserver.com/docs/caddyfile

        @irc host irc.xinayder.me
        handle @irc {
                reverse_proxy localhost:9000
        }

        @znc host znc.xinayder.me
        handle @znc {
                reverse_proxy localhost:1030
        }

        @hass host hass.xinayder.me
        handle @hass {
                reverse_proxy edupenna.duckdns.org:9999
                header -X-Frame-Options
        }

        @websockets {
                header Connection *Upgrade*
                header Upgrade websocket
        }

        @ntfy host notify.xinayder.me
        handle @ntfy {
                reverse_proxy localhost:9005

                # Redirect HTTP to HTTPS, but only for GET topic addresses, since we want
                # it to work with curl without the annoying https:// prefix
                @httpget {
                    protocol http
                    method GET
                    path_regexp ^/([-_a-z0-9]{0,64}$|docs/|static/)
                }
                redir @httpget https://{host}{uri}
        }

        header /.well-known/matrix/* Content-Type application/json
        header /.well-known/matrix/* Access-Control-Allow-Origin *
        respond /.well-known/matrix/server `{"m.server": "matrix.xinayder.me:443"}`
        respond /.well-known/matrix/client `{"m.homeserver": {"base_url": "https://matrix.xinayder.me:443"}}`
}

3. The problem I’m having:

As seen on my Caddyfile, I have a single block handling my wildcard and root domain and it also handles my reverse proxy subdomains. The problem with this approach, however, is that any request to an unhandled subdomain will be redirected to the root site, which I believe is the result of root and file_serverdirectives.

I was worried that separating these two would cause Caddy to issue separate certificates for the wildcard domains and the root domain, but that already seems to be the case? I checked the certificate for my website and it doesn’t list the wildcard subdomain on the CN field.

With this in mind, if I separate the subdomains from the root server block, I would need to copy the TLS directive as well as any other directives I’d like to be common directives for these two configurations, right? For example, if I want to include the header directives, should I create a snippet and import it in both domain blocks? Do I also need to copy the log directive to the subdomain block?

Also, what I wanted to achieve was: any request to an invalid path will return a 404; this counts subdomains as well, if I access a subdomain that isn’t handled by caddy, it should return an error or just abort the request. Right now even if I access a subdomain like testxsd.xinayder.me, it will redirect me to my main page, which isn’t what I expect.

4. Error messages and/or full log output:

N/A

5. What I already tried:

6. Links to relevant resources:

You’re exactly correct here. You’ve defined file_server as the behaviour for both *.xinayder.me and xinayder.me, so whenever Caddy gets a subdomain you haven’t overridden with a handle, it falls through to the file server.

I believe Caddy always handles certificates separately and never combines them based on how you write the site address list.

Yes, yes, and yes. Snippets are a good idea (see: Caddyfile Concepts — Caddy Documentation). You can import the snippet in each site block. Put all of the common config in a single snippet if you like.

You want one site block for xinayder.me with the common config snippet + the file_server, and a separate site block for *.xinayder.me with the common config snippet + the host → handle sets + a fallback respond 404 taking the place of the file_server you have right now.

2 Likes

Caddy doesn’t support multi-SAN certificates, for a variety of reasons. See docs/acme-ops.md at master · https-dev/docs · GitHub for an explanation.

2 Likes

Would the following work for you?

Instead of this:

# Set this path to your site's directory.
root * /var/www/xinayder.me
file_server {
        hide blog tags categories
}

use this:

@root_site host xinayder.me
handle @root_site {
	root * /var/www/xinayder.me
	file_server {
		hide blog tags categories
	}
}

and then something like this as a very last subdomain definition after all other subdomain definitions within your existing block:

@wildcard host *.xinayder.me
handle @wildcard {
	respond 404
}

So, pretty much this:

*.xinayder.me xinayder.me {

	...

	@root_site host xinayder.me
	handle @root_site {
		root * /var/www/xinayder.me
		file_server {
			hide blog tags categories
		}
	}

	@wildcard host *.xinayder.me
	handle @wildcard {
		respond 404
	}
}

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