Apache 403 while serving Django static files

11,195

Solution 1

I faced this issue as well.

i can't place the static files in /var/www as Noah suggested.

Solved by adding to apache2.conf:

<Directory /usr/local/django_apps/myapp/static>
    Options Indexes FollowSymLinks
    AllowOverride None
    Require all granted
</Directory>

Solution 2

Another possibility would be a missing trailing slash in the static root directory. The following configuration was resulting in 403 errors:

WSGIPythonPath /home/foo/app/
WSGIPythonHome /home/foo/.envs/foo

<VirtualHost *:80>
    Alias /static/ /home/foo/assets
    ServerAdmin [email protected]
    WSGIScriptAlias / /home/foo/app/wsgi.py
    ErrorLog ${APACHE_LOG_DIR}/app_wsgi_error.log
    CustomLog ${APACHE_LOG_DIR}/app_wsgi_access.log combined
    <Directory /home/foo/app/>
        <Files wsgi.py>
            Require all granted
        </Files>
    </Directory>
    <Directory /home/foo/assets>
        Require all granted
    </Directory>
</VirtualHost>

After adding a trailing slash to /home/foo/assets, everything worked perfectly. I hope that helps future Googlers.

Solution 3

I figured it out. I moved all the files the static and media files to /var/www and apache seems much happier

Share:
11,195

Related videos on Youtube

noah
Author by

noah

Software Engineering major, interested in web application design and sysadmining

Updated on September 24, 2022

Comments

  • noah
    noah over 1 year

    I've looked through a lot of the related posts but nothing seems to be helping.
    Relevant Info:

    Django version - 1.4

    Apache version - 2.2

    Python version - 2.7

    OS - Xubuntu 12.04

    DB - Mysql

    I'm trying to get Apache to serve both the django app and static files. The issue become apparent in the admin site which fails to display any of the CSS styles or images. My admin site currently looks like:

    (well, I would have included an image but stack overflow didn't let me. Suffice to say it looks like the admin page of everyone else who's posted on this topic, see Apache not serving django admin static files )

    Application pieces like my login page and some dynamic content work just fine, but when I try to serve static content, I get a 403 error. Additionally when I try to navigate to the stylesheet manually by looking at the admin page's rendered html and clicking on the link to the stylesheet at

    http://localhost/static/admin/css/base.css 
    

    I get a 403 error. I can navigate there in a terminal, and changed the permissions for the folder so that Apache's www-data user explicitly has access to all the files.

    Here are the relevant pieces of my httpd.conf:

    #AliasMatch ^/([^/]*\.css) /usr/local/wsgi/static/styles/$1
    
    Alias /media/ "/usr/local/wsgi/media/"
    Alias /static/ "/usr/local/wsgi/static/"
    
    <Directory "/usr/local/wsgi/static">
    Order deny,allow
    Allow from all
    </Directory>
    
    <Directory "/usr/local/wsgi/media">
    Order deny,allow
    Allow from all
    </Directory>
    WSGIScriptAlias / "/home/noah/Documents/Web/Basic/apache/django.wsgi"
    
    <Directory "/usr/local/wsgi/scripts">
    Order allow,deny
    Allow from all
    </Directory>
    

    On the advice of a friend I also copied the above to my sites-available default:

    <VirtualHost *:80>
        ServerAdmin webmaster@localhost
    
        DocumentRoot /var/www
        TypesConfig /etc/mime.types
        <Directory />
            Options FollowSymLinks
            AllowOverride None
        </Directory>
        <Directory /home/noah/Documents/Web/Basic/apache/ >
            Options -Indexes FollowSymLinks
                AllowOverride AuthConfig FileInfo
                Order allow,deny
                Allow from all
            </Directory>
        <Directory /var/www/>
            Options Indexes FollowSymLinks MultiViews
            AllowOverride None
            Order allow,deny
            allow from all
        </Directory>
        SetEnv DJANGO_SETTINGS_MODULE Basic.settings
        ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
        <Directory "/usr/lib/cgi-bin">
            AllowOverride None
            Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
            Order allow,deny
            Allow from all
        </Directory>
    
    #AliasMatch ^/([^/]*\.css) /usr/local/wsgi/static/styles/$1
    
    Alias /media "/usr/local/wsgi/media/"
    Alias /static "/usr/local/wsgi/static/"
    
    <Directory "/usr/local/wsgi/static">
    Order deny,allow
    Allow from all
    </Directory>
    
    <Directory "/usr/local/wsgi/media">
    Order deny,allow
    Allow from all
    </Directory>
    WSGIScriptAlias / "/home/noah/Documents/Web/Basic/apache/django.wsgi"
    
    <Directory "/usr/local/wsgi/scripts">
    Order allow,deny
    Allow from all
    </Directory>
    
        ErrorLog ${APACHE_LOG_DIR}/error.log
    
        # Possible values include: debug, info, notice, warn, error, crit,
        # alert, emerg.
        LogLevel warn
    
        CustomLog ${APACHE_LOG_DIR}/access.log combined
    
        Alias /doc/ "/usr/share/doc/"
        <Directory "/usr/share/doc/">
            Options Indexes MultiViews FollowSymLinks
            AllowOverride None
            Order deny,allow
            Deny from all
            Allow from 127.0.0.0/255.0.0.0 ::1/128
        </Directory>
    
    </VirtualHost>
    

    Here is my django.wsgi

    import os
    import sys
    
    path = '/home/noah/Documents/Web/Basic'
    if path not in sys.path:
        sys.path.append(path)
    
    os.environ['DJANGO_SETTINGS_MODULE'] = 'Basic.settings'
    
    import django.core.handlers.wsgi
    application = django.core.handlers.wsgi.WSGIHandler()
    

    And finally, here is my settings.py:

    # Absolute filesystem path to the directory that will hold user-uploaded files.
    # Example: "/home/media/media.lawrence.com/media/"
    MEDIA_ROOT = '/usr/local/wsgi/media/'
    
    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash.
    # Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
    MEDIA_URL = 'http://localhost/media/'
    
    # Absolute path to the directory static files should be collected to.
    # Don't put anything in this directory yourself; store your static files
    # in apps' "static/" subdirectories and in STATICFILES_DIRS.
    # Example: "/home/media/media.lawrence.com/static/"
    STATIC_ROOT = '/usr/local/wsgi/static/'
    
    # URL prefix for static files.
    # Example: "http://media.lawrence.com/static/"
    STATIC_URL = 'http://localhost/static/'
    
    # Additional locations of static files
    STATICFILES_DIRS = (
        # Put strings here, like "/home/html/static" or "C:/www/django/static".
        # Always use forward slashes, even on Windows.
        # Don't forget to use absolute paths, not relative paths.
    )
    
    # List of finder classes that know how to find static files in
    # various locations.
    STATICFILES_FINDERS = (
        'django.contrib.staticfiles.finders.FileSystemFinder',
        'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    #    'django.contrib.staticfiles.finders.DefaultStorageFinder',
    )
    
    # Make this unique, and don't share it with anybody.
    SECRET_KEY = 'bmc&amp;epl=#u)r3elkvj#@90*cji*z^cg8dnh$7j9kh@g9wzw(ih'
    
    # List of callables that know how to import templates from various sources.
    TEMPLATE_LOADERS = (
        'django.template.loaders.filesystem.Loader',
        'django.template.loaders.app_directories.Loader',
    #     'django.template.loaders.eggs.Loader',
    )
    
    MIDDLEWARE_CLASSES = (
        'django.middleware.common.CommonMiddleware',
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        # Uncomment the next line for simple clickjacking protection:
        # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
    )
    
    ROOT_URLCONF = 'Basic.urls'
    
    # Python dotted path to the WSGI application used by Django's runserver.
    WSGI_APPLICATION = 'Basic.wsgi.application'
    

    My Django project 'Basic' lives in ~/Documents/Web/ which is symlinked to /var/www/

    Any help is greatly appreciated, and let me know if you need any more files/information.

  • noah
    noah over 8 years
    I'll move the check to your solution, because democracy
  • dcolumbus
    dcolumbus about 7 years
    I wonder why this needs to be set in apache.conf and isn't adequate within the vhosts files...
  • Jossef Harush Kadouri
    Jossef Harush Kadouri about 7 years
    I agree, best practice to set it in a custom "sites-available" conf file
  • Walucas
    Walucas over 6 years
    I set on sites-available conf file, solved my problem