Static served using nginx couldn't work Error 404

I am using homebrew to start the nginx services.

Django project directory :

core (app)
main_app(app)
maps(app)
static → css folder, js folder etc
templates
manage.py

Steps :

  1. I add static url :
STATIC_URL = "/static/"
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static"),
]
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")

MEDIA_URL = "media/"
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
  1. I then collect the static
nuntea@Zonunmawias-MacBook-Air vgt-bitmapper-portal-app % python3 manage.py collectstatic 

184 static files copied to '/Users/nuntea/Documents/Vasundhara Geo technology/vgt-bitmapper-portal-app/staticfiles'.
  1. I add the following server to

    a. /etc/nginx/sites-enabled/django-app.conf 
    b. /opt/homebrew/etc/nginx/nginx.conf (After adding the new server, there are two server)
    
server {
    listen 80;
    server_name _;

    location /static/ {
       alias '/Users/nuntea/Documents/Vasundhara Geo technology/vgt-bitmapper-portal-app/staticfiles/';
    }

    location / {
        proxy_pass http://127.0.0.1:8000; 
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

}

Here are some further information :

nuntea@Zonunmawias-MacBook-Air vgt-bitmapper-portal-app % brew services list
Name          Status  User   File         
nginx         started nuntea ~/Library/LaunchAgents/homebrew.mxcl.nginx.plist

nginx -t
nginx: the configuration file /opt/homebrew/etc/nginx/nginx.conf syntax is ok
nginx: configuration file /opt/homebrew/etc/nginx/nginx.conf test is successful

nuntea@Zonunmawias-MacBook-Air vgt-bitmapper-portal-app % cat /opt/homebrew/var/log/nginx/error.log 

No error printed

sudo lsof -i :8080

COMMAND  PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
nginx   3926 nuntea    7u  IPv4 0xb41b860f0985e595      0t0  TCP *:http-alt (LISTEN)
nginx   3933 nuntea    7u  IPv4 0xb41b860f0985e595      0t0  TCP *:http-alt (LISTEN)

When I run the server :

python3 manage.py runserver

 [01/Feb/2024 12:43:05] "GET /core/login-user/?next=/ HTTP/1.1" 200 1801
 [01/Feb/2024 12:43:05] "GET /static/bootstrap_css/bootstrap.min.css HTTP/1.1" 404 179
 [01/Feb/2024 12:43:05] "GET /static/custom_css/base.css HTTP/1.1" 404 179
 [01/Feb/2024 12:43:05] "GET /static/jquery_js/jquery-3.6.4.min.js HTTP/1.1" 404 179
 [01/Feb/2024 12:43:05] "GET /static/bootstrap_js/bootstrap.min.js HTTP/1.1" 404 179

It couldn’t find the css etc

May we take a look at the nginx access log? My best guess at the moment is that runserver is handling the requests to the static files and not nginx. Do you have DEBUG on?

Couple different things here.

I set DEBUG = False. I delete the nginx and start from scratch.

The nginx listen in 8080 port. I run nginx and python3 manage.py runserver.

When I go to the url, the static file couldn’t be seen : http://127.0.0.1:8000/


06/Feb/2024 16:29:18] "GET / HTTP/1.1" 302 0
[06/Feb/2024 16:29:18] "GET /core/login-user/?next=/ HTTP/1.1" 200 1801
[06/Feb/2024 16:29:18] "GET /static/custom_css/base.css HTTP/1.1" 404 179
[06/Feb/2024 16:29:18] "GET /static/bootstrap_css/bootstrap.min.css HTTP/1.1" 404 179
[06/Feb/2024 16:29:18] "GET /static/jquery_js/jquery-3.6.4.min.js HTTP/1.1" 404 179
[06/Feb/2024 16:29:18] "GET /static/bootstrap_js/bootstrap.min.js HTTP/1.1" 404 179
[06/Feb/2024 16:29:25] "GET /static/custom_css/base.css HTTP/1.1" 404 179
[06/Feb/2024 16:29:25] "GET /static/bootstrap_css/bootstrap.min.css HTTP/1.1" 404 179

When I go to the url, the static file couldn’t be seen : http://127.0.0.1:8080/. The application works and could see the static files.

I investigate the resources request when going to different port 8000 and 8080 :

In port 8000, where the static files couldn’t be see :

Request URL: http://127.0.0.1:8000/static/custom_css/base.css


As django didn’t serve the static files anymore, it couldn’t find.

In port 8080, where the static files could be see :


Request URL: http://127.0.0.1:8080/static/custom_css/base.css

As nginx listen here, it could find and use the css etc.

The access.log is as the following :

nuntea@Zonunmawias-MacBook-Air vgt-bitmapper-portal-app % cat /opt/homebrew/var/log/nginx/access.log

127.0.0.1 - - [06/Feb/2024:16:13:16 +0530] "GET /static/bootstrap_js/bootstrap.min.js HTTP/1.1" 304 0 "http://127.0.0.1:8080/core/login-user/?next=/" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
127.0.0.1 - - [06/Feb/2024:16:13:16 +0530] "GET /static/bootstrap_css/bootstrap.min.css.map HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
127.0.0.1 - - [06/Feb/2024:16:13:16 +0530] "GET /static/bootstrap_js/bootstrap.min.js.map HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
127.0.0.1 - - [06/Feb/2024:16:31:56 +0530] "GET /core/login-user/?next=/ HTTP/1.1" 200 1801 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"
127.0.0.1 - - [06/Feb/2024:16:32:45 +0530] "GET /core/login-user/?next=/ HTTP/1.1" 200 1801 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"

I don’t think this is how it should run (thinking that port 8000 should also see the static). What is wrong ?

I don’t see anything wrong! Looks like you got it working! Your access log confirms what you observed that Nginx is handling the staticfiles request when you make the request on port 8080.

With DEBUG = False Django won’t serve staticfiles and hence Django 404s. There’s some more info in the docs. Since you wouldn’t use DEBUG turned on in production you need some other way of serving the staticfiles. Some use solutions like Whitenoise or do what you’ve done and configure the HTTP server to handle these requests.

When making requests on port 8080: Nginx is ‘in front’ of Django and Nginx serves the static files itself and for everything else calls Django on port 8000. When you make a request straight to Django on port 8000 and with DEBUG turned off, Django can’t find the static files as it is not serving them.

To move closer to production you might have Nginx listen on port 80 instead of 8080 and then you could perform your requests like http://127.0.0.1/ (note http not https). For a more realistic situation you’d probably have Nginx listen on 443 (perhaps also routing all non-https requests to https). This is harder to do on a local machine as it generally requires SSL certificates with LetsEncrypt or something similar.