mliezun / caddy-snake

Caddy plugin to serve Python apps
MIT License
87 stars 3 forks source link

Trying to make this work with Django #4

Closed 30350n closed 7 months ago

30350n commented 7 months ago

Hey!

I'm currently trying to get this working with a django project, but I'm getting a django.core.exceptions.DisallowedHost: Invalid HTTP_HOST header: ':'. The domain name provided is not valid according to RFC 1034/1035. error. The host appears to be correct in the caddy access log, though it's not part of the headers directive (I don't know enough about http to tell if that's normal):

2024/02/23 16:29:48.544 info    http.log.access.log0    handled request {"request": {"remote_ip": "<ip>", "remote_port": "51804", "client_ip": "<ip>", "proto": "HTTP/1.1", "method": "GET", "host": "inventree.<redacted>.de", "uri": "/", "headers": {"Accept-Language": ["en-US,en;q=0.5"], "Sec-Fetch-User": ["?1"], "Accept": ["text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"], "Accept-Encoding": ["gzip, deflate, br"], "Sec-Fetch-Mode": ["navigate"], "X-Forwarded-For": ["<ip>"], "User-Agent": ["Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:123.0) Gecko/20100101 Firefox/123.0"], "Upgrade-Insecure-Requests": ["1"], "Cookie": [], "Connection": ["close"], "X-Forwarded-Port": ["443"], "Sec-Fetch-Dest": ["document"], "Sec-Fetch-Site": ["none"], "X-Forwarded-Proto": ["https"], "X-Forwarded-For-Anon": ["2001:9e8::"]}}, "bytes_read": 0, "user_id": "", "duration": 0.000136843, "size": 7, "status": 200, "resp_headers": {"Server": ["Caddy"], "Content-Type": ["text/plain; charset=utf-8"]}}

I'm deploying on a shared host, so everythings going through another nginx server (which I can't really configure) before being forwarded to caddy.

Before I was using another nginx server to serve static/media files which further forwarded to a uwsgi server running the django project. So if this works out, it'd simplify the whole setup quite a lot, thanks to your project 😃

mliezun commented 7 months ago

Hi! Thanks for your interest in this plugin and for taking the time to report the issue 😁.

I was able to reproduce the error and managed to find the cause. I'll publish a fix in a couple hours.

The problem is that, as you pointed out, the host is not being passed correctly.

I tested from a terminal with a dummy Django api, and this worked fine:

curl http://localhost:9080/hello-world/
{"message":"Hello World"}

If the request is done directly to the IP and the host is passed in the header (which should also work), it fails:

curl http://127.0.0.1:9080/hello-world/ -H 'Host: localhost'

Throws the same error as you reported django.security.DisallowedHost Invalid HTTP_HOST header: ':'. The domain name provided is not valid according to RFC 1034/1035.

mliezun commented 7 months ago

Should be fixed in 6012179. If you have time, please test it using the following command to build from main branch:

CGO_ENABLED=1 xcaddy build --with github.com/mliezun/caddy-snake@main

Let me know if the error persists 😅

30350n commented 7 months ago

Thanks a lot for the quick fix!

It appears to be working, but something weird is happening:

So I have been having some issues with 301 redirects from Django lately (which is more or less what made me to try to switch from nginx to caddy in the first place) and with this now I'm getting redirects to inventree.<redacted>.de:8005/index/ for example. So the port I use for internal communication on the shared host somehow ends up in the response for 301 redirects.

30350n commented 7 months ago

Looks like https://github.com/mliezun/caddy-snake/blob/60121794395596bf5ac72fa4fd431bdcd8ed1016/caddysnake.go#L160-L163 could cause that.

mliezun commented 7 months ago

In this case Im not able to reproduce the issue. I did this:

$ curl -i http://127.0.0.1:9080/redirection/ -H 'Host: localhost'
HTTP/1.1 301 Moved Permanently
Allow: GET, HEAD, OPTIONS
Content-Length: 0
Content-Type: text/html; charset=utf-8
Location: /hello-world/
Referrer-Policy: same-origin
Server: Caddy
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Date: Sat, 24 Feb 2024 12:15:38 GMT

$ curl -i http://localhost:9080/redirection/
HTTP/1.1 301 Moved Permanently
Allow: GET, HEAD, OPTIONS
Content-Length: 0
Content-Type: text/html; charset=utf-8
Location: /hello-world/
Referrer-Policy: same-origin
Server: Caddy
Vary: Accept, Cookie
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Date: Sat, 24 Feb 2024 12:16:00 GMT

In both cases Location: /hello-world/ would redirect correctly regardless of the base host.

These are the Django views that I used for testing:


class HelloWorldView(APIView):
    def get(self, request, format=None):
        return Response({"message": "Hello World"}, status=status.HTTP_200_OK)

class RedirectionView(APIView):
    def get(self, request, format=None):
        return redirect("hello_world", permanent=True)

Can you share a minimal example that I can use to reproduce the error?

30350n commented 7 months ago

Oh yeah sorry, seems like that was a local cache thing. Firefox seems to cache 301s really aggressively. I've cleared the cache and now everything seems to be working. Thanks again!

mliezun commented 7 months ago

Awesome! Let me know if you encounter other difficulties while using the plugin.

Thanks again for reporting the issue and for your help debugging.

Im closing this issue as the problem has been resolved.