Nginx+FastCGI+Django Remove URL Prefix before passing to Django - django

I've setup Nginx to fastcgi_pass to Django and don't want to serve Django from "/". I want to prefix the URLs with something like "/django/sample/" but then have Nginx remove that prefix before it gets passed to Django - this way Django's internals will act like it's actually serving from "/".
I've tried updating the Django app to include the prefix in the URLs routed, like this:
urlpatterns = patterns('',
'^', include(base_urlpatterns), # iff you wish to maintain the un-prefixed URL's too
'^your_prefix/', include(base_urlpatterns),
)
And I currently do a fastcgi_pass like so:
#django sample
location /django/sample {
include fastcgi_params;
fastcgi_pass 127.0.0.1:8024;
}
But this isn't a graceful solution as any URL in my django app then has to make sure to include a prefix like "/django/sample". And it also means that when I run locally VS on the server the URLs may need to be different.
I build quite a few django apps that'll be running from one server and don't want to always have to do this tom-foolery with URLs and remember to update all the URLs in Django.
I've been googling for a while trying to figure out how to do this with nginx but haven't seen anything.
So, I'm looking to use Nginx to remove the "/django/sample" in the request before it gets passed to Django. Anyone done this before?

You're approaching this the wrong way round. There's no reason to remove the prefix before passing to Django: as long as you configure your server correctly, Django will be aware of it, and will automatically use it in things like the {% url %} tag and reverse() call (which of course you're using for all your URL references internally).
The documentation for deploying with FastCGI gives some details of how to set the prefix, in particular the advice that if you can't get it to work any other way, you can explicitly set FORCE_SCRIPT_NAME to the value of your prefix.

Related

django filefield returning localhost-prefixed URL

I'm trying not to specify the full path of the web app in the settings to make it as portable as possible.
However,
with MEDIA_URL="/media/", an URL returned from a Django FileField model is http://localhost/media/....
with MEDIA_URL="//example.com/media/", the URL returned is http://example.com/media/....
But the schema (http/s) and domain (example.com) should match those of the requesting page. How can I do this?
The Django app is served through Nginx in combination with Gunicorn.
It sounds like nginx and Django are not configured to pass and use http host name (e.g. X-Forwarded-Host header). This looks like a good answer - https://stackoverflow.com/a/58044808/6865

How to deploy static website connecting to Django RESTful API?

First of all, google or SO search didn't help me: lots of tips regarding django's staticfiles, which I believe are not relevant here.
I have inherited a project consisting of:
Django backend in form of API returning JSON responses only;
standard Swampdragon deployment pushing realtime updates to frontend; very little configuration has been done here;
Frontend webapp built on Backbone and marionette.js, compiled and minified by Grunt.
My problem is: the frontend needs to know addresses for swampdragon and django servers; right now those values are hardcoded, so there is for example a Backbone model with lines like:
url: function() {
return App.BACKEND_URL+'settings/map';
}
Why hardcoded: backend can be served on any port or have a subdomain to itself; frontend is static and normally would be simply thrown into /var/www (for Apache) or would use some very simple nginx config. Both will be served from the same place, but there is no guarantee the port numbers or subdomains would match.
Idea number 1: try to guess what BACKEND_URL is from javascript, by taking window.location.host and appending standard port. That's hackish and error prone.
Idea number 2: move frontend to Django and make it ask for swampdragon credentials (they would be sent in the context of home view). Problem with that is, the frontend files are compiled by grunt. So where Django would kindly expect something like:
<script src="{% static 'scripts/vendor/modernizr.js' %}"></script>
I actually have
<script src="scripts/vendor/a8bcb0b6.modernizr.js"></script>
Where 'a8bcb0b6' is grunt's hash/version number and will be regenerated during next minification/build. Do I need to add additional logic to get rid of such stuff and copy grunt's output directory to django's static and template dirs?
Or is there another way to make this work, the right one, I am missing?
Your architecture is already clean, no need to make Django know about grunt or serve static files, and no need to use JS hacks to guess port numbers
Reverse Proxy
Use a reverse proxy like nginx or any other web server you like as a front end to both the static files and the REST API.
In computer networks, a reverse proxy is a type of proxy server that
retrieves resources on behalf of a client from one or more servers.
These resources are then returned to the client as though they
originated from the proxy server itself. (Wikipedia)
I will outline the important aspects without going into too much detail:
URL for the REST API
We make configs so that nginx will forward the API requests to Django
location /api {
proxy_pass http://127.0.0.1:8000; # assumes Django listens here
proxy_set_header Host $http_host; # preserve host info
}
So the above assumes your Django REST is mapped to /api and runs on port 8000 (e.g. you can run gunicorn on that port, or any other server you like)
http://nginx.org/en/docs/http/ngx_http_proxy_module.html
URL for our front end app
Next nginx will serve the static files that come out of grunt, by simply pointing it to the static folder
location / { alias /app/static/; }
The above assumes your static resources are in /app/static/ folder (like index.html, your CSS, JS etc). So this is primarily to load your BackboneJS app.
Django static files
Next step is not required, but if you have static files that you use with the Django app (static files that are generated with ./manage.py collectstatic, e.g. the django admin or the UI of Django REST Framework etc), simply map according to your Django settings.py STATIC_URL and STATIC_ROOT
location /static { alias /app/django_static_root/; }
/static and django_static_root being the STATIC_URL and STATIC_ROOT respectively
To sum up
So e.g. when you hit example.com/, nginx simply serves up the static files, then when a JS script makes REST call to /api, it gets trapped in the /api nginx location and gets forwarded to Django
End result is, example.com/ and example.com/api both hit the same front end web server, which proxies them to the right places
So there you have it, reserve proxying solves your ports and subdomain issues (and many others, like slow static files from Django and same-origin policies in web browsers and firewalls not liking anything besides default HTTP and HTTPS ports)

Rewrite URL in Nginx proxy + apache setup

I'm working in python/django with apache and a Nginx proxy.
I need to transform some URLs like these:
www.mydomain.com/client_A/
www.mydomain.com/client_B/
to
www.mydomain.com/clients/1/
www.mydomain.com/clients/2/
I would do a rewrite in the Nginx configuration, but the problem is that this should Not be visible to the user, rather he should keep seeing the URL as www.mydomain.com/client_A/ and Not as the internal URL.
The main idea is to do this in the Nginx/Apache configuration
Thanks in advance.
I believe
rewrite ^/client_A/(.*)$ /clients/1/$1 last;
in nginx config should work.
You might want to look into the following post for related question.
apache reverse proxy changes url
The idea is to use a reverse proxy with Apache to keep URLs same.

How to ignore URL with Node to use Backbone router without #?

I'm building one page application using Backbone's router to modify browser history. I don't want to use # in URLs.
How to tell Node server to ignore everything in particular URL, example:
http://example.com/app
http://example.com/app/one/
http://example.com/app/two/
All these 3 URLs should point to /app but without redirection. Whatever user type after /app/ should cause Node server to render staff from /app
If you are using Express, you would probably use wildcard patter in routing def
app.get("/app/*",function(req,res){/*...*/});

quick question: how to set *.domainname.com url in django

I know there are lots of example for how to set http://domainname.com/username
url. But how to set http://username.domainname.com url in django?
Thinking a way to have a unique url for each user as http://username.domain.com like http://garry.posterous.com/
Thanks
As the first step, you need to arrange your DNS server to serve the wildcard domain; this is completely outside Django.
When you managed to do that (i.e. dig garry.posterous.com succeeds), then simply check for the HTTP_HOST request variable in the django view routines.
see Using Subdomains with Django: http://www.rossp.org/blog/2007/apr/28/using-subdomains-django/