Reverse proxy to django app not working from external computer [SOLVED]

Hey all, I’m sure it is a silly mistake on my end but would really appreciate some help. TIA :slight_smile:

1. Caddy version (caddy version):

v2.3.0 h1:fnrqJLa3G5vfxcxmOH/+kJOcunPLhSBnjgIvjXV/QTA=

2. How I run Caddy:

Using the following Caddyfile on a Ubuntu 16.04 machine:

{
    auto_https disable_redirects
}


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

Trying to connect to the ubuntu machine over a local network on a 2020 Macbook Air via curl.

a. System environment:

Ubuntu 16.04.7 LTS

b. Command:

I run the following with the above Caddyfile in the working directory

sudo caddy run

c. Service/unit/compose file:

Not using systemd.

d. My complete Caddyfile or JSON config:

Caddyfile:

{
    auto_https disable_redirects
}


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

JSON from localhost:2019/config:

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "automatic_https": {
            "disable_redirects": true,
            "skip": [
              "localhost"
            ]
          },
          "listen": [
            ":80"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "subroute",
                  "routes": [
                    {
                      "handle": [
                        {
                          "handler": "reverse_proxy",
                          "upstreams": [
                            {
                              "dial": "localhost:8000"
                            }
                          ]
                        }
                      ]
                    }
                  ]
                }
              ],
              "match": [
                {
                  "host": [
                    "localhost"
                  ]
                }
              ],
              "terminal": true
            }
          ]
        }
      }
    }
  }
}

3. The problem I’m having:

I currently running a django application with gunicorn (gunicorn --bind 0.0.0.0:8000) on a ubuntu 16.04 machine. I am trying to use caddy to reverse proxy incoming traffic to my local IP (port 80) to localhost:8000.

The issue is I am not getting a response from django when i try to make a request from an external computer (a macbook in this case). I get a 200 response from caddy, but there’s no data included in the response.

If i make the same request from my ubuntu machine (the caddy host), i get a proper response with some JSON data. I’m not sure why it behaves differently when trying from another computer, my firewall seems to be off (ufw status shows inactive).

4. Error messages and/or full log output:

output from sudo caddy run:

2021/02/15 19:29:07.452	INFO	using adjacent Caddyfile
2021/02/15 19:29:07.454	INFO	admin	admin endpoint started	{"address": "tcp/localhost:2019", "enforce_origin": false, "origins": ["localhost:2019", "[::1]:2019", "127.0.0.1:2019"]}
2021/02/15 19:29:07.454	INFO	tls.cache.maintenance	started background certificate maintenance	{"cache": "0xc000332620"}
2021/02/15 19:29:07.454	INFO	http	server is listening only on the HTTP port, so no automatic HTTPS will be applied to this server{"server_name": "srv0", "http_port": 80}
2021/02/15 19:29:07.454	INFO	autosaved config	{"file": "/home/hkennyv/.config/caddy/autosave.json"}
2021/02/15 19:29:07.455	INFO	serving initial configuration
2021/02/15 19:29:07.455	INFO	tls	cleaned up storage units

When using curl --verbose localhost on my ubuntu machine (this is good & returns some JSON data. you can see the extra server header from gunicorn as well):

* Expire in 0 ms for 6 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 1 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
* Expire in 0 ms for 1 (transfer 0x5621330a82b0)
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x5621330a82b0)
* Connected to localhost (127.0.0.1) port 80 (#0)
> GET / HTTP/1.1
> Host: localhost
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Allow: GET, HEAD, OPTIONS
< Content-Length: 257
< Content-Type: application/json
< Date: Mon, 15 Feb 2021 19:30:17 GMT
< Referrer-Policy: same-origin
< Server: Caddy
< Server: gunicorn/20.0.4
< Vary: Accept, Cookie
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< 
* Connection #0 to host localhost left intact

When using curl --verbose 192.168.1.103 (the ip of the ubuntu machine) from my macbook (this one is missing the extra headers and does not return any data in the response even though it gets a 200 status code):

*   Trying 192.168.1.103...
* TCP_NODELAY set
* Connected to 192.168.1.103 (192.168.1.103) port 80 (#0)
> GET / HTTP/1.1
> Host: 192.168.1.103
> User-Agent: curl/7.64.1
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Caddy
< Date: Mon, 15 Feb 2021 19:31:57 GMT
< Content-Length: 0
<
* Connection #0 to host 192.168.1.103 left intact
* Closing connection 0

5. What I already tried:

I’ve tried adding the bind 0.0.0.0 directive. this doesn’t change anything, same results.

I thought that it could be a firewall issue, but ufw is inactive (sudo ufw status):

Status: inactive

Trying to connect via the browser doesn’t work either (on the macbook). It gets a 200 status code, but there is no response (the expected behavior is a response from the django app).

I’ve tried following this as well, but it seems like some of these directives no longer exist in caddy 2.

I have also tried with nginx and the was able to achieve the behavior I wanted, so I think that helps narrow it down to caddy?

6. Links to relevant resources:

N/A

The trouble is that you’re using http://localhost, which tells Caddy "only match requests with the hostname localhost". So when you make a request with a different IP address, Caddy doesn’t know of any way to handle it so it just responds with an empty 200 response.

If you look at your JSON config, you see the routes, you only have one handle paired with a host matcher on localhost. Caddy will try that matcher, it won’t match, then it will fall through without the request being handled. And the default behaviour for that is to respond with an empty 200 response because Caddy “worked as configured”. It’s not actually an error on Caddy’s part, but instead a misconfiguration.

Instead, you can use :80 as your site address instead of http://localhost, which will match any request to port 80.

1 Like

@francislavoie thanks, that was indeed the issue.

Here’s my new (working) caddyfile & JSON for future reference:

Caddyfile

{
    auto_https disable_redirects
}


:80 {
    reverse_proxy http://localhost:8000
}

JSON

{
  "apps": {
    "http": {
      "servers": {
        "srv0": {
          "automatic_https": {
            "disable_redirects": true
          },
          "listen": [
            ":80"
          ],
          "routes": [
            {
              "handle": [
                {
                  "handler": "reverse_proxy",
                  "upstreams": [
                    {
                      "dial": "localhost:8000"
                    }
                  ]
                }
              ]
            }
          ]
        }
      }
    }
  }
}
1 Like

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