djangokubernetesdjango-rest-frameworkpaginationnginx-ingress

My django API “next” link uses a stale hostname only when receiving requests from GKE services (Like Cloud Run)


What are the details of your problem?

I have a application in Django that is deployed using GKE. It uses an ingress to deploy it... Those manifests.yml that are used for deploying applications on Google Cloud...

The application deploys it successfully, I'm able to login, navigate, and do most of my tasks. The problem is, whenever I try to request a API route that returns a list, I get the correct results but the next pagination link is built with a 'stale hostname'...

It should appear at like something like this: https://www.my-api-url.com/api/stores/?page=1&active=true But the hostname is being built like this: https://api-back.my-api-url.com/api/stores/?active=true&page=2 This 'api-back' is actually the hostname of my API Container from Google Cloud... The Docker Container on Kubernetes.

But the thing is: I already configured in Django Settings the correct hosts, and I checked the Environment Variables... They all point to the correct URLs. I also searched the entire codebase, Kubernetes manifests, and ingress configs and I can’t find this 'api-back.my-api-url.com' anywhere.

I found this related question stating DRF uses the request hostname for the paginator, but I still can’t figure out where the stale hostname is coming from: How to change the host in next key in a paginated URL in django rest framework?

What did you try and what were you expecting?

I expected my DRF and Django Settings to build next with the API URL defind in my settings and my enviroment variables. Checklist of what I saw to see if it's OK or not:

Despite that, the next link still shows the stale hostname.

What could be causing this behaviour?


Solution

  • DRF builds pagination links using request.build_absolute_uri(), which depends on the Host header it receives.
    If your app is behind a GKE Ingress or Load Balancer, it’s likely not forwarding the original host —
    so Django sees your internal service name like api-back.my-api-url.com.

    1. In your Django settings.py:

    USE_X_FORWARDED_HOST = True
    SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
    

    2.In your Ingress annotations, preserve the original host:

    nginx.ingress.kubernetes.io/use-forwarded-headers: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header Host $host;
      proxy_set_header X-Forwarded-Host $host;
    

    3.If needed, override DRF’s pagination link generator:

    from rest_framework.pagination import PageNumberPagination
    
    class FixedHostPagination(PageNumberPagination):
        def get_next_link(self):
            url = super().get_next_link()
            if url:
                return url.replace('api-back.my-api-url.com', 'www.my-api-url.com')
            return None
    

    Why it happens:

    Your ingress or proxy rewrites the Host header to the internal service name.
    DRF uses that to build links, so you end up with stale internal URLs.