Reject with 404 for not existing subdomains

1. The problem I’m having:

I’ve a couple of subdomain configured in caddy.
I need to keep some subdomains accessible only local and some of them only remote. So, to archive that I’m returning 404 error if IP is remote - to make subdomain local only.
But, I found that attackers could find (and they actually already found a few of them) my local subdomain, because caddy return different error for non existed subdomain.

2. Error messages and/or full log output:

Error for not existing subdomain:

curl -vL
*   Trying
* Connected to ( port 443 (#0)
* ALPN: offers h2,http/1.1
* (304) (OUT), TLS handshake, Client hello (1):
*  CAfile: /etc/ssl/cert.pem
*  CApath: none
* LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error
* Closing connection 0
curl: (35) LibreSSL/3.3.6: error:1404B438:SSL routines:ST_CONNECT:tlsv1 alert internal error

3. Caddy version:


4. How I installed and ran Caddy:

In docker container by using docker-compose

a. System environment:

Ubuntu Linux 22.04.3
Linux 5.15.0-97-generic on x86_64

b. Command:

curl, docker …

c. Service/unit/compose file:

d. My complete Caddy config:

(local_only) {
  @denied not remote_ip
  respond @denied 404
} {
    import local_only
    reverse_proxy authelia:9091 {
        import trusted_proxy_list
} {
  reverse_proxy openspeedtest:3000 {
    header_up X-Real-IP {remote_host}

5. Links to relevant resources:

I see a couple of similar question, but it was closed without a solution.
For example:

Is that possible to archive that?
To return 404 for not existing subdomains? Or return the same ssl error for my local subdomains?

It’s not possible to respond with HTTP when the TLS handshake fails. All clients will emit an error if the connection wasn’t established successfully. The server needs to have a valid certificate for the domain to be able to complete the TLS handshake.

You didn’t completely fill out the help topic template as per the forum rules, so I’m missing context for your question. Show your config and Caddy logs.

Might be it’s possible to abort connection somehow, that will looks like TLS handshake fail?
I see that one: Add handler to just close a connection without responding · Issue #3871 · caddyserver/caddy · GitHub
But it didn’t worked for me somehow …

No, because the TLS handshake happens before any HTTP handlers run. You cannot do anything to change how the client will report a TLS error. Servers have no control at all over that, except for successfully completing the handshake by having a valid certificate.

Edit: I see now that you added your config in OP. So you’re trying to block requests by IP? You can use the abort or error directives instead of respond, but what you have should already work. Why do you think it doesn’t work? I don’t think I follow.

Sorry, might be I’m doing something wrong.
But if I change:

(local_only) {
  @denied not remote_ip
  respond @denied 404


(local_only) {
  @denied not remote_ip
  handle {

Then all sub domains that has
import local_only
Are failing to load.
Nothing in Caddy logs so far :frowning:

Ah sorry, my bad …
It should be like that:

(local_only) {
  @denied not remote_ip
  handle @denied {

Now that works.
Needs to see if that will be better then return 404

You don’t need to wrap it with handle, you can just do abort @denied.

Using abort immediately closes the connection, it will show a connection error to the client instead of an empty page with a 404 status.

1 Like

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