title: How to serve Django static files through HTTPS?
body: <p>I'm getting 404 errors when accessing static files served through HTTPS but static files work fine through HTTP.  </p>
  
  <p>To be clear, I can access a particular page both ways e.g. <code>http://domain.com/page</code> and <code>https://domain.com/page</code> but in the HTTPS case, the images will fail to load.  </p>
  
  <p>Furthermore, accessing an image directly <code>http://domain.com/static/image.png</code> works but <code>https://domain.com/static/image.png</code> returns 404.</p>
  
  <p>I am running Ubuntu 10.04 with Django 1.3 using mod_wsgi on apache2.</p>
  
  <p>Here are the relevant files (wsgi and prod.conf and secure_prod.conf and settings.py):</p>
  
  <h1>django.wsgi</h1>
  
  <pre><code>import os
  import sys
  import site
  
  sys.stdout = sys.stderr # Allows use of print statements
  
  PROJECT_ROOT = '/home/code/domain/src/domain-project/'
  site_packages = '/home/code/domain/lib/python2.6/site-packages'
  
  site.addsitedir(os.path.abspath(site_packages))
  sys.path.insert(0, PROJECT_ROOT)
  sys.path.insert(1, os.path.join(PROJECT_ROOT, "domain"))
  sys.path.insert(2, site_packages)
  os.environ['DJANGO_SETTINGS_MODULE'] = 'domain.settings'
  os.environ['PYTHON_EGG_CACHE'] = '/home/administrator/.python-eggs'
  os.environ["CELERY_LOADER"] = "django"
  
  import django.core.handlers.wsgi
  application = django.core.handlers.wsgi.WSGIHandler()
  
  # Load a monitor to automatically reload apache when files change
  import domain.monitor
  domain.monitor.start(interval=1.0)
  </code></pre>
  
  <h1>production.conf</h1>
  
  <pre><code>&lt;VirtualHost *:80&gt;
  
    # Admin email, Server Name (domain name) and any aliases
    ServerAdmin d@domain.com
    ServerName domain.com
      ServerAlias *.domain.com
  
    DocumentRoot /home/code/domain/src/domain-project/domain
    LogLevel warn
    WSGIDaemonProcess domain-production processes=5 maximum-requests=500 threads=100
    WSGIProcessGroup domain-production
    WSGIScriptAlias / /home/code/domain/src/domain-project/apache/production.wsgi
  
    SetEnv PYTHON_EGG_CACHE /home/apache/.python_eggs
  
      Alias /admin/media /home/code/domain/lib/python2.6/site-packages/django/contrib/admin/media
      Alias /site_media /home/code/domain/src/domain-project/static
      Alias /static /home/code/domain/src/domain-project/static
      Alias /robots.txt /home/code/domain/src/domain-project/static/robots.txt
      Alias /favicon.ico /home/code/domain/src/domain-project/static/favicon.ico
  
    &lt;Location /admin/media&gt;
      SetHandler None
      Order allow,deny
      Allow from all
    &lt;/Location&gt;
  
    &lt;Location /site_media&gt;
      SetHandler None
      Order allow,deny
      Allow from all
    &lt;/Location&gt;
  
    &lt;LocationMatch "\.(jpg|gif|png|mp4)$"&gt;
      SetHandler None
    &lt;/LocationMatch&gt;
  
    &lt;LocationMatch "^/(robots\.txt|favicon\.ico|crossdomain\.xml)$"&gt;
      SetHandler none
    &lt;/LocationMatch&gt;
  
    ErrorLog /var/log/apache2/domain/production_error.log
    LogLevel info
    CustomLog /var/log/apache2/domain/production_access.log combined
  
  &lt;/VirtualHost&gt;
  </code></pre>
  
  <h1>secure_production.conf</h1>
  
  <pre><code>&lt;VirtualHost *:443&gt;
  
      ServerAdmin d@domain.com
      ServerName domain.com
      ServerAlias *.domain.com
  
      DocumentRoot /home/code/domain/src/domain-project/domain 
      LogLevel warn
      WSGIDaemonProcess domain-production processes=5 maximum-requests=500 threads=100
      WSGIProcessGroup domain_production_secure
      WSGIScriptAlias / /home/code/domain/src/domain-project/apache/production.wsgi
  
      SSLEngine on
      SSLOptions +StrictRequire
  
      &lt;Directory /&gt;
          SSLRequireSSL
      &lt;/Directory&gt;
  
      SSLProtocol -all +TLSv1 +SSLv3
      SSLCipherSuite HIGH:MEDIUM:!aNULL:+SHA1:+MD5:+HIGH:+MEDIUM
  
      SSLCertificateFile /home/code/domain/src/domain-project/apache/key/domain.COM.crt
      SSLCertificateKeyFile /home/code/domain/src/domain-project/apache/key/domain.com.key
      SSLCertificateChainFile /home/code/domain/src/domain-project/apache/key/Apache_Plesk_Install.txt
      SSLVerifyClient none
      SSLProxyEngine off
  
      &lt;IfModule mime.c&gt;
          AddType application/x-x509-ca-cert      .crt
          AddType application/x-pkcs7-crl         .crl
      &lt;/IfModule&gt;
  
  
      SetEnv PYTHON_EGG_CACHE /home/apache/.python_eggs
  
  
      Alias /admin/media /home/code/domain/lib/python2.6/site-packages/django/contrib/admin/media
      Alias /site_media /home/code/domain/src/domain-project/static
      Alias /static /home/code/domain/src/domain-project/static
      Alias /robots.txt /home/code/domain/src/domain-project/static/robots.txt
      Alias /favicon.ico /home/code/domain/src/domain-project/static/favicon.ico
  
  
      &lt;Location /admin/media&gt;
        SetHandler None
        Order allow,deny
        Allow from all
      &lt;/Location&gt;
  
      &lt;Location /site_media&gt;
        SetHandler None
        Order allow,deny
        Allow from all
      &lt;/Location&gt;
  
      &lt;LocationMatch "\.(jpg|gif|png|mp4)$"&gt;
        SetHandler None
      &lt;/LocationMatch&gt;
  
      &lt;LocationMatch "^/(robots\.txt|favicon\.ico|crossdomain\.xml)$"&gt;
        SetHandler none
      &lt;/LocationMatch&gt;
  
      ErrorLog /var/log/apache2/domain/production_secure_error.log
      LogLevel info
      CustomLog /var/log/apache2/domain/production_secure_access.log combined
  
  &lt;/VirtualHost&gt;
  </code></pre>
  
  <h1>settings.py</h1>
  
  <pre><code># Django settings for domain project.
  import os
  
  DEBUG = False
  TEMPLATE_DEBUG = DEBUG 
  
  # create a relative path to anything on the project from the PROJECT PATH
  SETTINGS_PATH = os.path.dirname(os.path.abspath(__file__))
  PROJECT_PATH = os.path.join(*os.path.split(SETTINGS_PATH)[:-1])
  rel = lambda * args: os.path.join(PROJECT_PATH, *args)
  
  # 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 = rel('..', 'static')
  
  # URL prefix for static files.
  # Example: "http://media.lawrence.com/static/"
  STATIC_URL = '/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',
  )
  
  # 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',
  )
  
  TEMPLATE_CONTEXT_PROCESSORS = (
      'django.contrib.auth.context_processors.auth',
      'django.core.context_processors.debug',
      'django.core.context_processors.i18n',
      'django.core.context_processors.request',
      'django.core.context_processors.static',
  )
  
  
  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',
  )
  
  ROOT_URLCONF = 'domain.urls'
  
  TEMPLATE_DIRS = (
      # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
      # Always use forward slashes, even on Windows.
      # Don't forget to use absolute paths, not relative paths.
      rel('..', 'templates'),
  )
  
  DJANGO_APPS= [
      'django.contrib.auth',
      'django.contrib.contenttypes',
      'django.contrib.sessions',
      'django.contrib.sites',
      'django.contrib.messages',
      'django.contrib.staticfiles',
      'django.contrib.admin',
  ]
  
  THIRDPARTY_APPS = [
      'djcelery',
      'djkombu',
      #'sentry',
      #'sentry.client',
      #'south',
  ]
  
  domain_APPS= []
  
  INSTALLED_APPS = DJANGO_APPS + THIRDPARTY_APPS + domain_APPS
  </code></pre>