When you are using OpenShift, you will be using
routes to expose a route from a service. Let’s say you want to expose a path in example.com/dummy. When you do that for a django application(without any reverse proxy server), it usually becomes a problem, because the sub directory does not work well with Django’s urls. You will probably face error 404 page not found.
If you are not using NGINX/Apache or any other reverse proxy server to serve the django application, you will not be able to set
X-SCRIPT-NAME. To me, it does not make sense to use reverse proxy in pods when OpenShift provides routes(or ingress in kubernetes) using NGINX/HA-Proxy(depending on your setup).
In this situation, I have used the following solution:
Disable Namespace Ownership Check in Router ︎
You need to patch the
router in OpenShift before starting any step(from OpenShift 3.9). By disabling Ownership check, you can allow a service to use a
xyz.com/abc even if there is another service taking
xyz.com. You can do it like this(from
oc adm router ... --disable-namespace-ownership-check=true oc env dc/router ROUTER_DISABLE_NAMESPACE_OWNERSHIP_CHECK=true
FYI: this also works in OKD as well.
I have set FORCE_SCRIPT_NAME in
settings.py. Usually I fetched the value from environment varibles, which I have set in the Deployment Config:
FORCE_SCRIPT_NAME = os.environ.get('DJANGO_FORCE_SCRIPT_NAME', '/subdirectory') # without trailing slash
FORCE_SCRIPT_NAME will configure django’s url in path
/subdirectory. But it is not sufficient to serve the django application in sub path, as
SCRIPT_NAME in requests are not updated, also it will show some erratic behaviour such as showing double entry of
/subpath in url, 404 Page not found issues etc. To fix this, lets go to the second step:
Lets update the
wsgi.py file like this:
import os from django.core.wsgi import get_wsgi_application from django.conf import settings os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'dummy.settings') _application = get_wsgi_application() # Here is the important part def application(environ, start_response): script_name = getattr(settings, 'FORCE_SCRIPT_NAME', None) if script_name: environ['SCRIPT_NAME'] = script_name path_info = environ['PATH_INFO'] if path_info.startswith(script_name): environ['PATH_INFO'] = path_info[len(script_name):] scheme = environ.get('HTTP_X_SCHEME', '') if scheme: environ['wsgi.url_scheme'] = scheme return _application(environ, start_response)
In above code, we are getting the value of
FORCE_SCRIPT_NAME, then putting that value in wsgi
Big thanks to ︎
I got the implementation idea from this Stack Overflow answer. Big thanks to @whp.
That is it for today, hope it helps. If you have a better approach to resolve this problem please make a comment in comment section below.
Last updated: Nov 13, 2020