7

I want to run Django with uWSGI behind a NGINX.

I will use Django as a API service which should live on this link: project.test/api The Django project itself is blank (1.9.6), just created a app, migrated and created a superuser.

My Project structure looks like this:
/vagrant/api/here-lives-whole-django
/vagrant/api/uwsgi_params
/vagrant/frontend/some-frontend-work-seperated-from-django

My NGINX setup looks like this:

upstream testing {
    server 127.0.0.1:8000;
}

server {
    listen   80;

    server_name www.testing.test;

    charset  utf-8;

    client_max_body_size  75M;

    access_log  /var/log/nginx/www.testing.test.access.log;
    error_log  /var/log/nginx/www.testing.test.error.log;

    location /api/ {
        include /vagrant/api/uwsgi_params;
        uwsgi_pass testing;
    }

    location / {
        root /vagrant/frontend;
    }
}

The uwsgi_params file:

uwsgi_param  QUERY_STRING       $query_string;
uwsgi_param  REQUEST_METHOD     $request_method;
uwsgi_param  CONTENT_TYPE       $content_type;
uwsgi_param  CONTENT_LENGTH     $content_length;

uwsgi_param  REQUEST_URI        $request_uri;
uwsgi_param  PATH_INFO          $document_uri;
uwsgi_param  DOCUMENT_ROOT      $document_root;
uwsgi_param  SERVER_PROTOCOL    $server_protocol;
uwsgi_param  REQUEST_SCHEME     $scheme;
uwsgi_param  HTTPS              $https if_not_empty;

uwsgi_param  REMOTE_ADDR        $remote_addr;
uwsgi_param  REMOTE_PORT        $remote_port;
uwsgi_param  SERVER_PORT        $server_port;
uwsgi_param  SERVER_NAME        $server_name;

My Django url pattern:

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

Atm. Im running Django with following command:
uwsgi --socket :8000 --wsgi-file wsgi.py

Im able to reach Django but when I try to access
www.testing.test/api/admin
I get a 404 (debug from Django).

Page not found (404)
Request Method: GET
Request URL:    http://www.testing.test/api/admin
Using the URLconf defined in testing.urls, Django tried these URL patterns, in this order:
^admin/
The current URL, api/admin, didn't match any of these.

I know it will be something very simple for people who are used to this stuff, forgive me because Im new.

Ps. I found some similar questions where people worked with

uwsgi_param SCRIPT_NAME /api;
uwsgi_modifier1 30; 

But this just made my Django tell me a 404 with

Request URL:    http://www.testing.test/api/api/admin

when I requested

Request URL:    http://www.testing.test/api/admin

1 Answers1

8

I had trouble to understand your question but basically it resumes to this: I want nginx to pass all calls to /api/ to django but django is receiving the URL with /api/ prefixed.


nginx trick (does not work for internal URLs)

I'd use nginx's rewrite to solve this

location /api/ {
    rewrite ^/api/(.*) /$1  break;
    include /vagrant/api/uwsgi_params;
    uwsgi_pass testing;
}

It shall drop the /api/ part of the URL and remain in the block to uwsgi_pass into Django.


django solution (dirty in my opinion)

The above works for the first URL going into django. Yet, django is clueless about the prefix that was removed and will have trouble to generate URLs to itself. That might not be a problem in some simple APIs but it would be a problem more often than not.

I guess, the only viable way is to add the prefix to the base URLconf.

from django.conf.urls import include

mypatterns = [
    url(r'^admin/', admin.site.urls),
]

urlpatterns = [
    url(r'^api/', include(mypatterns)),
]

Although, I feel this is a very dirty solution.

grochmal
  • 2,901
  • 2
  • 22
  • 28
  • I try to run Django on the link domain.test/api/*, so it should be possible to reach Djangos build in admin like this domain.test/api/admin . If I change my project the way you described and try to go to domain.test/api/admin I will get thrown to domain.test/admin . –  May 24 '16 at 03:08
  • You will not get thrown because of the `break`, it ensures that the `rewrite` is not thrown back into the URL matching. Yet, there is an issue with **django generating URLs to itself** (i updated the answer to reflect this). I guess, giving the `/api/` prefix to all URLs in the base URLconf is the dirty-but-working solution – grochmal May 24 '16 at 03:18
  • It does or it looks like it does. When I enter domain.test/api/admin it changes to domain.test/admin . Btw. I belive I messed some stuff up because I didn't follow your old answers to the end because you deleted them. Do you remember what you wrote about? Could help me restore some config on my VM. –  May 24 '16 at 03:22
  • I was babling about random uWSGI configs 'cause i misread your question. It was completely my fault. Yet, for a good example of uwsgi config i always go bad to [this guy's gist post](https://gist.github.com/evildmp/3094281) – grochmal May 24 '16 at 03:32
  • 2
    After setting `rewrite ^/api/(.*) /$1 break;` I also had to have `uwsgi_param SCRIPT_NAME /api;` to get Django to route correctly. I've been stumped on this all day and this really helped! – Ashley 'CptLemming' Wilson May 04 '17 at 16:02