Redirect other than proxy route to display 404

1. Caddy version (caddy version): 4.2.5

2. How I run Caddy:

a. System environment:

Windows 10: OS Build 19042.1237

b. Command:

caddy run --watch

c. Project directory:

caddy
 |  └── server1
 |  └── server2
 | 404.html
 | CaddyFile

d. My complete Caddyfile or JSON config:

localhost:8080 { 
    rewrite / /404.html
    handle /api/v1/ { 
        reverse_proxy localhost:3000
    }
    handle /api/v2/ { 
        reverse_proxy localhost:3001
    }
}
{
   "apps":{
      "http":{
         "servers":{
            "srv0":{
               "listen":[
                  ":8080"
               ],
               "routes":[
                  {
                     "handle":[
                        {
                           "handler":"subroute",
                           "routes":[
                              {
                                 "group":"group2",
                                 "handle":[
                                    {
                                       "handler":"subroute",
                                       "routes":[
                                          {
                                             "handle":[
                                                {
                                                   "handler":"reverse_proxy",
                                                   "upstreams":[
                                                      {
                                                         "dial":"localhost:3000"
                                                      }
                                                   ]
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ],
                                 "match":[
                                    {
                                       "path":[
                                          "/api/v1/"
                                       ]
                                    }
                                 ]
                              },
                              {
                                 "group":"group2",
                                 "handle":[
                                    {
                                       "handler":"subroute",
                                       "routes":[
                                          {
                                             "handle":[
                                                {
                                                   "handler":"reverse_proxy",
                                                   "upstreams":[
                                                      {
                                                         "dial":"localhost:3001"
                                                      }
                                                   ]
                                                }
                                             ]
                                          }
                                       ]
                                    }
                                 ],
                                 "match":[
                                    {
                                       "path":[
                                          "/api/v2/"
                                       ]
                                    }
                                 ]
                              }
                           ]
                        }
                     ],
                     "match":[
                        {
                           "host":[
                              "localhost"
                           ]
                        }
                     ],
                     "terminal":true
                  }
               ]
            }
         }
      }
   }
}

d. Example server index.js (both are the same implementation for each server1/2):

const app = express()

app.set("serverPort", process.env.SERVER_PORT)
app.use(helmet())
app.use(morgan("dev"))
app.use(express.json())

app.get("/api/v2/", (req, res) => { 
    res.send({ message: "Hello World v2"})
})

app.listen(app.get("serverPort"), () => { 
    console.log(`Express Server 2 Listening On Port ${app.get("serverPort")}`)
})

3. The problem I’m having:

1. going to https://localhost/api/v1 or /v2, site cant be reach
2. going to https://localhost:8080/ or anything other than endpoint proxy, display blank page (doesn't show 404.html)
3. going to https://localhost:8080/api/v1 or /v2, display json sent from server (but doesnt work without the port, site cant be reach)

4. Error messages and/or full log output:

N/A

5. What I already tried:

rewrite / /404.html

6. Links to relevant resources:

Request matching in Caddy is exact, so this would only match requests to exactly /api/v1/ and nothing else, i.e. excluding /api/v1/foo.

To fix this, use /api/v1/* for your matcher instead. If you need to also match /api/v1, then you may use /api/v1* but be aware that this would also match /api/v11 as well for example. You can use a named matcher + the path matcher to do @v1 path /api/v1 /api/v1/*, to work around that.

Right, because if you specify a port, Caddy will only be listening on port 8080. That’s to be expected. If you configure Caddy with your site address as localhost instead of localhost:8080 then it will listen on port 443 for HTTPS requests (the default HTTPS port).

You used a / matcher, which only matches exactly / and nothing else. To match all requests not otherwise handled by your v1 or v2 handle blocks, then use another handle block without a matcher, that will act as a catch-all.

See the examples in the docs:

Thank you so much for the explanation. Sorry I’m new to this :sweat_smile: I’ll update the solution once I update the workaround based on your answer :+1:

1 Like

So here’s what i’ve done to solve my problem. Instead of redirect, I rendered the 404.html file I created in the root directory when client make request other than the proxy endpoint i provided. By using the handle_errors directive. Here’s how I implement.

localhost { 
    handle /api/v1/ { 
        reverse_proxy localhost:3000
    }
    handle /api/v2/ { 
        reverse_proxy localhost:3001
    }
    file_server {
        hide 404.html
    }
    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
    }
}

The reason behind usage of file_server directive is to hide the 404.html file and avoid client making request directly to https://localhost/404.html which will send a 404 instead of 200.

@francislavoie I wanted to ask something regarding my caddyfile configuration. The above config I did not specify any cors option. But why didn’t I get any cors related error? Sorry if this question not making any sense :sweat_smile:

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