1

My site's frontend is built with Angular 7, and the back end is built with Django Rest Framework. It's all running via docker-compose, and I'm trying to serve the entire site through NGINX.

The basic premise of my configuration is this:

  • If the request includes a url with /api/ or /admin/ in it, allow gunicorn to handle the request.
  • If the url is anything else, send it to the root index.html so that Angular can handle the routing.
  • The root url / should serve my pre-compiled javascript via the index.html.

With the following Nginx config, I can visit all of the Angular routes. I can visit the admin page and my browsable API. However, when I go to /admin or the browsable API, all of the static files return a 404 error.

Do you see the issue? Thanks!

# urls.py

urlpatterns = [
    re_path(r'^favicon\.ico$', favicon_view),

    path('api/v1/', include('api.urls'), name='api'),
    path('admin/', admin.site.urls),
]



# nginx.conf

upstream my_app {
    server django:8000;
}

server {

    listen 80;

    location /staticfiles/ {
        alias /usr/src/app/staticfiles/;
    }

    location ~ (api|admin) {
        proxy_pass http://my_app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

    location / { 
        root /usr/src/app/staticfiles/;
        try_files $uri $uri/ /index.html;
    }

}
1
  • This config does work for my application... I had other issues to sort through. I've updated the post with my urlpatterns from Django. As you can see, I'm not using Django for much outside of the API in this project. If your use case is more complex, look at the answer from @wmorrel Commented Jun 4, 2019 at 20:25

1 Answer 1

3

Your configs are saying that everything available from /api/ or /admin/ are provided by the proxy to my_app. So, you may either ensure that the static files used by those endpoints are available through Django Rest Framework, OR tell NGINX to always try the static files first, then fall back to the my_app proxy.

The first option will involve setting STATIC_ROOT, STATIC_URL, STATICFILES_STORAGE, etc per the Django documentation on static files (link goes to current dev version).

The other option involves collecting the assets used by /api/ and /admin/ in the same location as your Angular assets, and altering your NGINX configuration to look something like this:

# nginx.conf

upstream my_app {
    server django:8000;
}

server {

    listen 80;

    location /staticfiles/ {
        alias /usr/src/app/staticfiles/;
    }

    location / { 
        root /usr/src/app/staticfiles/;
        try_files $uri $uri/ index.html;
        location /drf {
            proxy_pass http://my_app;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_redirect off;

        }
    }

}

This basically says try to look up everything in your Angular staticfiles directory, if it's not found, try looking it up in your DRF application.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for the response. I tried to plug in your nginx.conf, and it's not quite right. I can navigate to the browsable API as expected (e.g. /api/v1/users/). When I go to /admin/, I get a 403 - Forbidden. When I go to http://localhost:1337/admin/login/?next=/admin/, it works. When I login and redirect to /admin/, I get a 403. As for the Angular routes, if I go to the root URL (http://localhost:1337/) it works okay. Clicking buttons in the app continues to navigate okay. However, going to one of the Angular URLs directly (e.g. /about/) results in a 404 - Not found. Any ideas?
I can't really help without seeing more of the project. Are you sure your authorization method is being persisted? Are you using cookies, or header access tokens, or something else; and are those being set properly? It sounds like your problems are deeper than just a proxy configuration.
FWIW, I'm using header access tokens for auth. It appears to be working correctly. I made some changes to my static file handling in Django (namely started hosting static on AWS S3), which meant reworking my static settings in Django, and now it appears to be working as expected. QUESTION: In your first paragraph in the answer, OR tell NGINX to always try the static files first, then fall back to the my_app proxy. - Doesn't my original nginx.conf do that?
No, the original config will only use the proxy when the path matches the regular expression api|admin. If you serve any paths from the Django app that do not match, then the original configuration would try to load from /usr/src/app/staticfiles/, and when not found, return index.html instead. In addition, if you have any Angular files that happen to match, that config would try to load from Django instead.
I only have passing familiarity with Angular, so ymmv. If the issue is specifically with loading index.html as a fallback for an empty path, I would just add a location block for an empty path pointing to index.html. I suspect there's more going on, so a more robust solution would be to configure all the DRF stuff to respond to a specific path that won't conflict with Angular. That keeps the original try_files and only direct to the proxy for the DRF path. I'll update the answer with what that could look like.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.