skip to Main Content

I am working on my first Django project. I want to host the same using Lighttpd server rather than nginx or apache. The project works well in the developer mode. The ‘runserver’ serves all the files as intended.

Since Lighttpd alone cannot host a Django project, I use Gunicorn to serve the dynamic aspects.

Django version – 3.2
Gunicorn – 21.2
Python – 3.8
Lighttpd – 1.4.52

I have configured my Lighttpd in a separate conf file named myapp.conf without amending the default lighttpd.conf file.

When I run the server, I see that Gunicorn loads index.html correctly but css files are not loaded by lighttpd. It gives the following error:

GET https://ip-address/myapp/static/css/indexStyle.css net::ERR_ABORTED 404 (Not Found)

Similarly Gunicorn gives an error when loading js file:
GET https://ip-address/myapp/static/js/TM_PageFun.js net::ERR_ABORTED 404 (Not Found)
Refused to execute script from ‘https://ip-address/myapp/static/js/TM_PageFun.js’ because its MIME type (‘text/html’) is not executable, and strict MIME type checking is enabled.

I find a lot of information here on connecting Django with Nginx and Gunicorn. But I couldn’t find much with Lighttpd. I am not sure where the error is.

I have added the mime-types and double checked the path and permissions.

CSS files are in /usr/web/myapp/static/css
JS files are in /usr/web/myapp/static/js
Image files are in /usr/web/myapp/static

myapp.conf looks like this :

server.max-fds = 2048

mimetype.assign := (

  ".js" => "text/javascript",
  ".css" => "text/css",
  ".html" => "text/html",
  ".txt" => "text/plain",
  ".jpg" => "image/jpeg",
  ".png" => "image/png",
)

$HTTP["url"] =~ "^/myapp/static" {
  server.document-root = "/usr/web/myapp/static"
}

$HTTP["url"] =~ "^/myapp/static/html" {
  server.document-root = "/usr/web/myapp/static/html"
  proxy.server = ( "" => ( ( "host" =>  "127.0.0.1", "port" => 8000 ) ) )
}

$HTTP["url"] =~ "^/myapp/static/js" {
  server.document-root = "/usr/web/myapp/static/js"
  proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => 8000 ) ) )

}

The lighttpd.conf looks as follows:

# lighttpd configuration file
#
# use it as a base for lighttpd 1.0.0 and above
#
# $Id: lighttpd.conf,v 1.7 2004/11/03 22:26:05 weigon Exp $

############ Options you really have to take care of ####################

## modules to load
# at least mod_access and mod_accesslog should be loaded
# all other module should only be loaded if really neccesary
# - saves some time
# - saves memory
server.modules              = (
#                               "mod_rewrite",
                                "mod_redirect",
                                "mod_alias",
                                "mod_access",
                                "mod_openssl",
#                               "mod_cml",
#                               "mod_trigger_b4_dl",
                                "mod_auth",
#                               "mod_status",
#                               "mod_setenv",
#                               "mod_fastcgi",
                                "mod_proxy",
#                               "mod_simple_vhost",
#                               "mod_evhost",
#                               "mod_userdir",
#                               "mod_cgi",
                                "mod_compress",
#                               "mod_ssi",
#                               "mod_usertrack",
#                               "mod_expire",
#                               "mod_secdownload",
#                               "mod_rrdtool",
#                               "mod_webdav",
                                "mod_accesslog" )

## a static document-root, for virtual-hosting take look at the
## server.virtual-* options
server.document-root        = "/var/www/"

## where to send error-messages to
server.errorlog-use-syslog = "enable"

# files to check for if .../ is requested
index-file.names            = ( "index.php", "index.html",
                                "index.htm", "default.htm" )

## set the event-handler (read the performance section in the manual)
# server.event-handler = "freebsd-kqueue" # needed on OS X

# mimetype mapping
mimetype.assign             = (
  ".pdf"          =>      "application/pdf",
  ".sig"          =>      "application/pgp-signature",
  ".spl"          =>      "application/futuresplash",
  ".class"        =>      "application/octet-stream",
  ".ps"           =>      "application/postscript",
  ".torrent"      =>      "application/x-bittorrent",
  ".dvi"          =>      "application/x-dvi",
  ".gz"           =>      "application/x-gzip",
  ".pac"          =>      "application/x-ns-proxy-autoconfig",
  ".swf"          =>      "application/x-shockwave-flash",
  ".tar.gz"       =>      "application/x-tgz",
  ".tgz"          =>      "application/x-tgz",
  ".tar"          =>      "application/x-tar",
  ".zip"          =>      "application/zip",
  ".mp3"          =>      "audio/mpeg",
  ".m3u"          =>      "audio/x-mpegurl",
  ".wma"          =>      "audio/x-ms-wma",
  ".wax"          =>      "audio/x-ms-wax",
  ".ogg"          =>      "application/ogg",
  ".wav"          =>      "audio/x-wav",
  ".gif"          =>      "image/gif",
  ".jpg"          =>      "image/jpeg",
  ".jpeg"         =>      "image/jpeg",
  ".png"          =>      "image/png",
  ".xbm"          =>      "image/x-xbitmap",
  ".xpm"          =>      "image/x-xpixmap",
  ".xwd"          =>      "image/x-xwindowdump",
  ".css"          =>      "text/css",
  ".html"         =>      "text/html",
  ".htm"          =>      "text/html",
  ".js"           =>      "text/javascript",
  ".asc"          =>      "text/plain",
  ".c"            =>      "text/plain",
  ".cpp"          =>      "text/plain",
  ".log"          =>      "text/plain",
  ".conf"         =>      "text/plain",
  ".text"         =>      "text/plain",
  ".txt"          =>      "text/plain",
  ".dtd"          =>      "text/xml",
  ".xml"          =>      "text/xml",
  ".mpeg"         =>      "video/mpeg",
  ".mpg"          =>      "video/mpeg",
  ".mov"          =>      "video/quicktime",
  ".qt"           =>      "video/quicktime",
  ".avi"          =>      "video/x-msvideo",
  ".asf"          =>      "video/x-ms-asf",
  ".asx"          =>      "video/x-ms-asf",
  ".wmv"          =>      "video/x-ms-wmv",
  ".bz2"          =>      "application/x-bzip",
  ".tbz"          =>      "application/x-bzip-compressed-tar",
  ".tar.bz2"      =>      "application/x-bzip-compressed-tar"
 )

# Use the "Content-Type" extended attribute to obtain mime type if possible
#mimetype.use-xattr        = "enable"
## send a different Server: header
## be nice and keep it at lighttpd
server.tag = "myPC"

#### accesslog module
accesslog.use-syslog = "enable"

## deny access the file-extensions
#
# ~    is for backupfiles from vi, emacs, joe, ...
# .inc is often used for code includes which should in general not be part
#      of the document-root
url.access-deny             = ( "~", ".inc" )

$HTTP["url"] =~ ".pdf$" {
  server.range-requests = "disable"
}

##
# which extensions should not be handle via static-file transfer
#
# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )

######### Options that are good to be but not neccesary to be changed #######

## bind to port (default: 80)
#server.port                = 81
server.port=80

## bind to localhost (default: all interfaces)
#server.bind                = "grisu.home.kneschke.de"

## error-handler for status 404
#server.error-handler-404   = "/error-handler.html"
#server.error-handler-404   = "/error-handler.php"

## to help the rc.scripts
#server.pid-file            = "/var/run/lighttpd.pid"


###### virtual hosts
##
##  If you want name-based virtual hosting add the next three settings and load
##  mod_simple_vhost
##
## document-root =
##   virtual-server-root + virtual-server-default-host + virtual-server-docroot
## or
##   virtual-server-root + http-host + virtual-server-docroot
##
#simple-vhost.server-root   = "/home/weigon/wwwroot/servers/"
#simple-vhost.default-host  = "grisu.home.kneschke.de"
#simple-vhost.document-root = "/pages/"


##
## Format: <errorfile-prefix><status-code>.html
## -> ..../status-404.html for 'File not found'
#server.errorfile-prefix    = "/home/weigon/projects/lighttpd/doc/status-"
## virtual directory listings
#dir-listing.activate       = "enable"

## enable debugging
#debug.log-request-header   = "enable"
#debug.log-response-header  = "enable"
#debug.log-request-handling = "enable"
#debug.log-file-not-found   = "enable"

### only root can use these options
#
# chroot() to directory (default: no chroot() )
#server.chroot              = "/"

## change uid to <uid> (default: don't care)
#server.username            = "wwwrun"
server.username="http"

## change uid to <uid> (default: don't care)
#server.groupname           = "wwwrun"
server.groupname="http"

#### compress module
#compress.cache-dir         = "/tmp/lighttpd/cache/compress/"
#compress.filetype          = ("text/plain", "text/html")

#### proxy module
## read proxy.txt for more info
#proxy.server               = ( ".php" =>
#                               ( "localhost" =>
#                                 (
#                                   "host" => "192.168.0.101",
#                                   "port" => 80
#                                 )
#                               )
#                             )

#### fastcgi module
## read fastcgi.txt for more info
## for PHP don't forget to set cgi.fix_pathinfo = 1 in the php.ini
#fastcgi.server             = ( ".php" =>
#                               ( "localhost" =>
#                                 (
#                                   "socket" => "/tmp/php-fastcgi.socket",
#                                   "bin-path" => "/usr/local/bin/php"
#                                 )
#                               )
#                            )

#### CGI module
#cgi.assign                 = ( ".pl"  => "/usr/bin/perl",
#                               ".cgi" => "/usr/bin/perl" )
#

#### SSL engine
#ssl.engine                 = "enable"
#ssl.pemfile                = "server.pem"

#### status module
#status.status-url          = "/server-status"
#status.config-url          = "/server-config"
#### auth module
## read authentication.txt for more info
#auth.backend               = "plain"
#auth.backend.plain.userfile = "lighttpd.user"
#auth.backend.plain.groupfile = "lighttpd.group"

#auth.backend.ldap.hostname = "localhost"
#auth.backend.ldap.base-dn  = "dc=my-domain,dc=com"
#auth.backend.ldap.filter   = "(uid=$)"

#auth.require               = ( "/server-status" =>
#                               (
#                                 "method"  => "digest",
#                                 "realm"   => "download archiv",
#                                 "require" => "user=jan"
#                               ),
#                               "/server-config" =>
#                               (
#                                 "method"  => "digest",
#                                 "realm"   => "download archiv",
#                                 "require" => "valid-user"
#                               )
#                             )

#### url handling modules (rewrite, redirect, access)
#url.rewrite                = ( "^/$"             => "/server-status" )
#url.redirect               = ( "^/wishlist/(.+)" => "http://www.123.org/$1" )

#### both rewrite/redirect support back reference to regex conditional using %n
#$HTTP["host"] =~ "^www.(.*)" {
#  url.redirect            = ( "^/(.*)" => "http://%1/$1" )
#}

#
# define a pattern for the host url finding
# %% => % sign
# %0 => domain name + tld
# %1 => tld
# %2 => domain name without tld
# %3 => subdomain 1 name
# %4 => subdomain 2 name
#
#evhost.path-pattern        = "/home/storage/dev/www/%3/htdocs/"

#### expire module
#expire.url                 = ( "/buggy/" => "access 2 hours", "/asdhas/" => "access plus 1 seconds 2 minutes")

#### ssi
#ssi.extension              = ( ".shtml" )

#### rrdtool
#rrdtool.binary             = "/usr/bin/rrdtool"
#rrdtool.db-name            = "/var/www/lighttpd.rrd"

#### setenv
#setenv.add-request-header  = ( "TRAV_ENV" => "mysql://user@host/db" )
#setenv.add-response-header = ( "X-Secret-Message" => "42" )

## for mod_trigger_b4_dl
# trigger-before-download.gdbm-filename = "/home/weigon/testbase/trigger.db"
# trigger-before-download.memcache-hosts = ( "127.0.0.1:11211" )
# trigger-before-download.trigger-url = "^/trigger/"
# trigger-before-download.download-url = "^/download/"
# trigger-before-download.deny-url = "http://127.0.0.1/index.html"
# trigger-before-download.trigger-timeout = 10

## for mod_cml
## don't forget to add index.cml to server.indexfiles
# cml.extension               = ".cml"
# cml.memcache-hosts          = ( "127.0.0.1:11211" )

#### variable usage:
## variable name without "." is auto prefixed by "var." and becomes "var.bar"
#bar = 1
#var.mystring = "foo"

## integer add
#bar += 1
## string concat, with integer cast as string, result: "www.foo1.com"
#server.name = "www." + mystring + var.bar + ".com"
## array merge
#index-file.names = (foo + ".php") + index-file.names
#index-file.names += (foo + ".php")

#### include
#include /etc/lighttpd/lighttpd-inc.conf
## same as above if you run: "lighttpd -f /etc/lighttpd/lighttpd.conf"
#include "lighttpd-inc.conf"

#### include_shell
#include_shell "echo var.a=1"
## the above is same as:
#var.a=1

# include other config file fragments from lighttpd.d subdir
include "/etc/lighttpd.d/*.conf"

My Django settings.py has the following :

BASE_DIR = "/usr/web/myapp"
DEBUG = False
ALLOWED_HOSTS = ['*']
WSGI_APPLICATION = 'myapp.wsgi.application'
static_path = BASE_DIR +"/static"
STATIC_ROOT = BASE_DIR + "/static"
STATIC_URL = "/myapp/static"
STATICFILES_DIRS=(os.path.join(static_path),)

urls.py

from typing import Counter
from django import views
from django.urls import path
from . import views
from django.contrib import admin

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',views.index, name='index'),
    path('index.html',views.index, name='index'),
    path('TM_page.html',views.TM_page, name='TM_page'),
    path('logout',views.logout_request,name='logout')
]

2

Answers


  1. To serve static documents while deploying Django software with Lighttpd and Gunicorn:

    Confirm Django settings are configured for static file serving.

    Run collect static to accumulate static files.

    Configure Lighttpd to serve static documents with suitable rules.

    Verify file permissions and restart offerings if needed.

    Check Lighttpd error logs for troubleshooting.

    Login or Signup to reply.
  2. How about letting lighttpd serve the static files and proxying the dynamic requests back to gunicorn?

    $HTTP["url"] =~ "^/myapp" {
      $HTTP["url"] =~ "^/myapp/static" {
        alias.url = ( "/myapp/static" => "/usr/web/myapp/static" )
      }
      else {
        proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => 8000 ) ) )
      }
    }
    

    Also answered on stackoverflow using gunicorn 5 years ago here:

    How to configure lighttpd to serve django static files?

    Answered on stackoverflow using the simpler SCGI protocol rather than proxying to gunicorn:

    How to setup django with lighttpd?

    If you use a search engine for Django and FastCGI or SCGI, you’ll find loads of examples how to set it up. lighttpd can be configured to use mod_fastcgi, mod_scgi, or mod_proxy to send dynamic requests to a Django backend.

    BTW: Lighttpd - 1.4.52 is very old — lighttpd 1.4.52 was released Nov 2018! The latest lighttpd stable version is lighttpd 1.4.76.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search