404 - not found path on reverse proxy with sub-domain

I am able to set up a regular docker server with reverse proxy.
That being said, I am having a hard time figuring out the right Caddyfile set up for a reverse proxy with sub-domains.

here is my caddyfile:

{
    auto_https off
    auto_https disable_redirects
    #email   email@gmail.com
}
api.localhost:8080 {
	reverse_proxy api.zipperapiv2:8000
}

zipperapiv2:8000 is a docker Golang server with 2 sub-domains;

  • api.localhost:8000 &
  • sock.localhost:8000.

By itself, the subdomains work. When I introduce Caddy reverse proxy, it fails miserably.
Honestly, I think I am doing it wrong.

Currently, I cannot get any URL paths to work. I get a 404 not found error on a path like api.localhost:8080/token
Any help will be useful.

Could you please fill out the help thread template? There’s some information missing here that would help us understand the issue.

It would help to know your Caddy version and see your full, unredacted Caddy logs.

If you’re running with Docker or docker-compose, the commands you used to run or your docker-compose.yml would be helpful to understand your setup.

1. Caddy version (caddy version):

2.1.1

2. How I run Caddy:

a. System environment:

docker, with systemd on production

b. Command:

docker-compose up

c. Service/unit/compose file:

none in testing. Just docker-compose up

d. My complete Caddyfile or JSON config:

{
    auto_https off
    auto_https disable_redirects
    #email   email@gmail.com
}

http://api.localhost:8080 {
        reverse_proxy zipperapiv2:8000
}

3. The problem I’m having:

I am able to set up a regular docker server with reverse proxy.
That being said, I am having a hard time figuring out the right Caddyfile set up for a reverse proxy with sub-domains.

here is my caddyfile:

{
    auto_https off
    auto_https disable_redirects
    #email   email@gmail.com
}
api.localhost:8080 {
	reverse_proxy api.zipperapiv2:8000
}

zipperapiv2:8000 is a docker Golang server with 2 sub-domains;

  • api.localhost:8000 &
  • sock.localhost:8000 .

By itself, the subdomains work. When I introduce Caddy reverse proxy, it fails miserably.
Honestly, I think I am doing it wrong.

Currently, I cannot get any URL paths to work. I get a 404 not found error on a path like api.localhost:8080/token
Any help will be useful.

4. Error messages and/or full log output:

zipperapiv2_1 | {“time”:“2020-08-22T20:37:57.714890432Z”,“id”:"",“remote_ip”:“192.168.224.1”,“host”:“api.localhost:8080”,“method”:“GET”,“uri”:"/v2/tokenv2",“user_agent”:“Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36”,“status”:404,“error”:“code=404, message=Not Found”,“latency”:35111,“latency_human”:“35.111µs”,“bytes_in”:0,“bytes_out”:30}

5. What I already tried:

Just my Caddyfile. Not sure

6. Links to relevant resources:

none

It seems like the 404 is coming from zipperapiv2, right? I think you’ll need to look into why that’s returning a 404 in its logs. Is it expecting a different Host header instead?

I’m not seeing an issue at the Caddy level (and you didn’t give us your Caddy logs so I can’t tell if there’s an issue there).

I don’t see a Caddy response. It is almost like it is not there.

I was able to get a caddy reponse

caddyserver    | {"level":"error","ts":1598137567.9595816,"logger":"http.log.error","msg":"dial tcp 127.0.0.1:8000: connect: connection refused","request":{"method":"GET","uri":"/v2/tokenv2","proto":"HTTP/1.1","remote_addr":"192.168.224.1:40390","host":"api.localhost:8080","headers":{"Upgrade-Insecure-Requests":["1"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Dest":["document"],"Accept-Language":["en-GB,en;q=0.9,sw-TZ;q=0.8,sw;q=0.7,en-US;q=0.6"],"Accept-Encoding":["gzip, deflate, br"],"Connection":["keep-alive"],"Cache-Control":["max-age=0"],"Dnt":["1"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-User":["?1"]}},"duration":0.001778829,"status":502,"err_id":"ejemzs6i9","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:411)"}

This is the caddyfile

http://api.localhost:8080 {
        reverse_proxy localhost:8000
}

When running in Docker, localhost means “this container”. If you’re trying to proxy to your other container, you need to use the container name to proxy to it.

It looks like your container name is zipperapiv2, so use reverse_proxy zipperapiv2:8000.

@francislavoie,
Please help me understand this.
I have a Golang server inside a container that has subdomains.
For the subdomains to work, it needs a valid hostname in the hosts’ file. So I choose localhost inside the container.
Up to here, it is good.
So far, I can access these routes without Caddy reverse proxy on my laptop:
http://localhost:8000/, http://api.localhost:8000/, & http://api.localhost:8000/tokenv2

Now when I introduce caddy, the subdomains don’t seem to work.
I guess the question is how do access a container’s subdomain inside Caddy?

http://localhost:8080 {
        reverse_proxy zipperapiv2:8000
}

http://api.localhost:8080 {
        reverse_proxy api.zipperapiv2:8000
}

And the error

caddyserver    | {"level":"error","ts":1598300565.317542,"logger":"http.log.error","msg":"dial tcp: lookup api.zipperapiv2 on 127.0.0.11:53: no such host","request":{"method":"GET","uri":"/","proto":"HTTP/1.1","remote_addr":"192.168.224.1:57638","host":"api.localhost:8080","headers":{"Dnt":["1"],"User-Agent":["Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36"],"Accept":["text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"],"Sec-Fetch-User":["?1"],"Accept-Encoding":["gzip, deflate, br"],"Connection":["keep-alive"],"Upgrade-Insecure-Requests":["1"],"Sec-Fetch-Site":["none"],"Sec-Fetch-Mode":["navigate"],"Sec-Fetch-Dest":["document"],"Accept-Language":["en-GB,en;q=0.9,sw-TZ;q=0.8,sw;q=0.7,en-US;q=0.6"]}},"duration":0.070246047,"status":502,"err_id":"fz0fq5w2a","err_trace":"reverseproxy.(*Handler).ServeHTTP (reverseproxy.go:411)"}

I’m not exactly sure what you mean by “has sudbomains”… but I think what you’re looking for is the header_up subdirective of reverse_proxy. This will let you override the Host header when making proxy requests so that your upstream server knows which subdomain is being requested:

http://api.localhost:8080 {
    reverse_proxy zipperapiv2:8000 {
        header_up Host api.zipperapiv2
    }
}
1 Like

Finally, i was able to get the routing to work.
Even after putting Caddy container on host network mode, it would not route any local subdomain names.
To fix this, i had to add extra hosts to it, plus the solution above.

extra_hosts:
      - "api.localhost:127.0.0.1"
1 Like

@francislavoie, thank you so much.
It has taken a few extra days but the 3 sub-domains inside one container are being routed correctly.
It turns out I indeed needed header_up Host api.localhost:8000 for an all bridge network.
I also needed extra_hosts: - "api.localhost:127.0.0.1" in case I ended putting caddy on the host network and used docker-proxy reverse proxy .
It has been a learning experience.
Next will be setting up swarm.

1 Like

For usage with swarm, I recommend looking into Caddy-docker-proxy:

It configures Caddy based on docker labels, and it can read from swarm the list of upstreams to proxy to if you have multiple for load balancing.

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