Report this

What is the reason for this report?

Django (1.8.7) one click app on Ubuntu 16.04 not serving static files.

Posted on March 1, 2018

The default configurations led to 502 Gateway error which was resolved after commenting out ip_addersses() module. I have site running the same version of django running on localhost. Debug=False is not serving static files even on localhost.

Settings.py

"""
import os
import netifaces

BASE_DIR = os.path.dirname(os.path.dirname(__file__))

## Quick-start development settings - unsuitable for production
## See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/

## SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '[redacted]'

## SECURITY WARNING: don't run with debug turned on in production!
DEBUG = False

ALLOWED_HOSTS = ['www.naulo.com.np', '159.89.170.8', 'http://159.89.170.8/', '*', 'naulo.com.np']

## Application definition
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'base'
)

MIDDLEWARE_CLASSES = (
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
)

ROOT_URLCONF = 'django_project.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': []
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'debug': DEBUG,
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'django_project.wsgi.application'

## Database
## https://docs.djangoproject.com/en/1.6/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

## Password validation
## https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

## Internationalization
## https://docs.djangoproject.com/en/1.6/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True

# Serving media in production/server
STATIC_URL = 'static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static_cdn"),
    # '/var/www/static/',
]
MEDIA_URL = 'media/'
STATIC_ROOT = os.path.join(BASE_DIR, "static")
MEDIA_ROOT = os.path.join(BASE_DIR, "media")

## Find out what the IP addresses are at run time
## This is necessary because otherwise Gunicorn will reject the connections
def ip_addresses():
    ip_list = []
    for interface in netifaces.interfaces():
        addrs = netifaces.ifaddresses(interface)
        for x in (netifaces.AF_INET, netifaces.AF_INET6):
            if x in addrs:
                ip_list.append(addrs[x][0]['addr'])
    return ip_list

    ## Discover our IP address
# ALLOWED_HOSTS = ip_addresses()

/etc/nginx/sites-available/django

upstream app_server {
    server unix:/home/django/gunicorn.socket fail_timeout=0;
}

server {
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    root /usr/share/nginx/html;
    index index.html index.htm;

    client_max_body_size 4G;
    server_name _;

    keepalive_timeout 5;

    ## Your Django project's media files - amend as required
    location /media  {
        alias /home/django/django_project/django_project/media;
    }

    ## your Django project's static files - amend as required
    location /static {
        alias /home/django/django_project/django_project/static;
    }

    ## Proxy the static assests for the Django Admin panel
    location /static/admin {
       alias /usr/lib/python2.7/dist-packages/django/contrib/admin/static/admin/;
    }

    location / {
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header Host $host;
            proxy_redirect off;
            proxy_buffering off;

            proxy_pass http://app_server;
    }

}

/etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
	worker_connections 768;
	# multi_accept on;
}

http {

	##
	# Basic Settings
	##

	sendfile on;
	tcp_nopush on;
	tcp_nodelay on;
	keepalive_timeout 65;
	types_hash_max_size 2048;
	# server_tokens off;

	# server_names_hash_bucket_size 64;
	# server_name_in_redirect off;

	include /etc/nginx/mime.types;
	default_type application/octet-stream;

	##
	# SSL Settings
	##

	ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE
	ssl_prefer_server_ciphers on;

	##
	# Logging Settings
	##

	access_log /var/log/nginx/access.log;
	error_log /var/log/nginx/error.log;

	##
	# Gzip Settings
	##

	gzip on;
	gzip_disable "msie6";

	# gzip_vary on;
	# gzip_proxied any;
	# gzip_comp_level 6;
	# gzip_buffers 16 8k;
	# gzip_http_version 1.1;
	# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

	##
	# Virtual Host Configs
	##

	include /etc/nginx/conf.d/*.conf;
	include /etc/nginx/sites-enabled/*;
}


#mail {
#	# See sample authentication script at:
#	# http://wiki.nginx.org/ImapAuthenticateWithApachePhpScript
# 
#	# auth_http localhost/auth.php;
#	# pop3_capabilities "TOP" "USER";
#	# imap_capabilities "IMAP4rev1" "UIDPLUS";
# 
#	server {
#		listen     localhost:110;
#		protocol   pop3;
#		proxy      on;
#	}
# 
#	server {
#		listen     localhost:143;
#		protocol   imap;
#		proxy      on;
#	}
#}


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

STATICFILES_DIRS list should be:

STATICFILES_DIRS = [ os.path.join(BASE_DIR, “app_name”, “static”), # ‘/var/www/static/’, ]

replace app name with your app name.

Heya,

again I’m here to post some information on an old topic that someone might find it interesting.

1. STATICFILES_DIRS and STATIC_ROOT Configuration

In your settings.py:

  • STATICFILES_DIRS: Used during development to define additional directories containing static files. These are not relevant when DEBUG=False.
  • STATIC_ROOT: This is the directory where collectstatic gathers all static files when DEBUG=False.

Your current configuration:

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "static_cdn"),  # Additional dirs for dev
]
STATIC_ROOT = os.path.join(BASE_DIR, "static")  # For production

Solution:

  1. Run the collectstatic command to collect all static files into STATIC_ROOT:
python manage.py collectstatic
  1. Ensure Nginx is pointing to the correct directory:
location /static {
    alias /home/django/django_project/django_project/static;
}

2. Nginx Configuration for Static Files

Your Nginx configuration seems correct for serving static files. However, confirm the following:

  • The path /home/django/django_project/django_project/static matches the STATIC_ROOT in settings.py.
  • Nginx has read permissions for this directory.

Verify Nginx Permissions:

Check ownership and permissions:

ls -ld /home/django/django_project/django_project/static

If necessary, adjust permissions:

sudo chown -R www-data:www-data /home/django/django_project/django_project/static
sudo chmod -R 755 /home/django/django_project/django_project/static

3. Debugging Static Files in Production

  • Confirm the static files are collected in the STATIC_ROOT directory:
ls /home/django/django_project/django_project/static

If the files are missing, rerun:

python manage.py collectstatic
  • Test static file URLs manually: Visit http://yourdomain.com/static/css/yourfile.css and check for a 404 error or other issues.

4. Common Issues with DEBUG=False

  • Security Middleware: Ensure ALLOWED_HOSTS is properly set. Your configuration includes *, which is not recommended for production.
  • CSRF Trusted Origins: With DEBUG=False, ensure you set trusted origins:
CSRF_TRUSTED_ORIGINS = ['https://naulo.com.np', 'http://159.89.170.8']

5. Fixing the STATICFILES_DIRS Usage

STATICFILES_DIRS should typically not include STATIC_ROOT. If static_cdn is not required for production, you can remove it:

STATICFILES_DIRS = []  # Or remove it entirely

This avoids potential conflicts during collectstatic.


6. Testing Locally with DEBUG=False

For local testing:

  • Run a simple static file server:
python manage.py runserver --insecure
  • This bypasses Nginx and serves static files directly.

Final Checklist:

  1. Run python manage.py collectstatic to gather all static files.
  2. Ensure Nginx’s location /static points to the STATIC_ROOT directory.
  3. Verify permissions for the static files directory.
  4. Test static URLs directly for accessibility.
  5. Adjust STATICFILES_DIRS and STATIC_ROOT as needed for clarity.

If the issue persists, share any error messages or specific behaviors for further debugging.

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.