Lighttpd
Web Server Error Response Codes
All HTTP response status codes are separated into five classes or categories. The first digit of the status code defines the class of response, while the last two digits do not have any classifying or categorisation role. There are five classes defined by the standard:
- 1xx informational response – the request was received, continuing process
- 2xx successful – the request was successfully received, understood and accepted
- 3xx redirection – further action needs to be taken in order to complete the request
- 4xx client error – the request contains bad syntax or cannot be fulfilled
- 5xx server error – the server failed to fulfill an apparently valid request
https://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Performance Tweaks
Compression
Create directory for virtual hosts' cache...
mkdir /var/cache/lighttpd/www.domain.com chown -R www-data:www-data /var/cache/lighttpd/www.domain.com
Edit config file...
compress.cache-dir = "/var/cache/lighttpd/www.domain.com/"
Turn on zlib compression for PHP...
nano /etc/php/7.2/cgi/php.ini zlib.output_compression = On
Restart web server...
service lighttpd restart
Test...
curl -I -H 'Accept-Encoding: gzip,deflate' https://www.domain.com/
Expiry Cache Control
$HTTP["url"] =~ "^/" { expire.url = ( "" => "access 5000 days" ) } setenv.add-response-header += ( "Cache-Control" => "public, must-revalidate, proxy-revalidate" )
https://www.cyberciti.biz/faq/lighttpd-send-cache-control-maxage-headers-of-staticfiles/
Etags and Last-Modifed
Before... missing...
$ curl -I https://www.normawinstone.com/wp-content/cache/omgf-webfonts/anton-400-normal-z-C8.woff2 HTTP/1.1 200 OK Cache-Control: public, must-revalidate, proxy-revalidate Content-Type: application/octet-stream Accept-Ranges: bytes Content-Length: 14220 Date: Sat, 20 Jun 2020 09:29:38 GMT Server: lighttpd/1.4.45
If the Content-Type is NULL, then set the Content-Type to "application/octet-stream" and disable caching.
In this case disabling caching means that both ETag and Last-Modified are neither calculated, nor sent with the response.
But how to fix that? There were multiple approaches as lighttpd processes /etc/mime.types on Debian. One solution that works for each and every file is defining a fall-back value inside the configuration file.
Why? Because the Content-Type will not be NULL when it reaches the check.
Long story short, the fix was adding these three lines to the bottom of our lighttpd.conf:
mimetype.assign += ( "" => "application/octet-stream" )
After... included...
$ curl -I https://www.normawinstone.com/wp-content/cache/omgf-webfonts/anton-400-normal-z-C8.woff2 HTTP/1.1 200 OK Cache-Control: public, must-revalidate, proxy-revalidate Content-Type: application/octet-stream Accept-Ranges: bytes ETag: "2396403747" Last-Modified: Fri, 19 Jun 2020 09:42:29 GMT Content-Length: 14220 Date: Sat, 20 Jun 2020 09:37:29 GMT Server: lighttpd/1.4.45
https://anexia.com/blog/en/the-tale-of-lighttpd-not-sending-the-last-modified-header/
Improve SSL Security
ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/domain_com.pem" ssl.ca-file = "/etc/lighttpd/domain_com.ca-bundle" # # tweaks - start # ssl.dh-file = "/etc/ssl/certs/dhparam.pem" ssl.ec-curve = "secp384r1" ssl.use-compression = "disable" ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" ssl.cipher-list = "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4" # # tweaks - finish #
https://raymii.org/s/tutorials/Strong_SSL_Security_On_lighttpd.html
Shell Script To Clean Lighttpd Web Server Cache
https://bash.cyberciti.biz/file-management/cleaning-webserver-cache-script/
HOWTO: Fix Error: All Files Content-Type: application/octet-stream
Instead of displaying web pages, your browser will try to download files.
This is because Lighttpd's mime assign settings are broken.
To fix it, recreate the mime configuration file and change the settings then restart the server...
sudo -i /usr/share/lighttpd/create-mime.conf.pl > /usr/share/lighttpd/mime.conf sudo nano /etc/lighttpd/lighttpd.conf include "/usr/share/lighttpd/mime.conf" systemctl restart lighttpd.service exit
https://redmine.lighttpd.net/boards/2/topics/8820
HOWTO: Fix Error: failed to execute shell
Error...
failed to execute shell: bash -c /usr/share/lighttpd/create-mime.assign.pl: No such file or directory failed to execute shell: bash -c /usr/share/lighttpd/include-conf-enabled.pl: No such file or directory
Reason...
Because the Ubuntu Release Upgrader has removed PHP during the upgrade process. God knows why.
Solution...
Reinstall the PHP CGI module and the PHP MySQL module.
Fix...
sudo apt-get install php-cgi php-mysql sudo lighty-enable-mod fastcgi-php sudo service lighttpd restart
HOWTO: Compile Source Code Latest Version
sudo -i apt-get install build-essential libpcre3 libpcre3-dev zlib1g-dev libbz2-dev libssl-dev libxml2 libxml2-dev libxml libxml++2.6-dev libsqlite3-dev mkdir lighttpd cd lighttpd wget https://download.lighttpd.net/lighttpd/releases-1.4.x/lighttpd-1.4.55.tar.gz tar -xzvf lighttpd-1.4.55.tar.gz cd lighttpd-1.4.55/ ./configure --with-openssl make make install wget https://www.xarg.org/download/rc.lighttpd.debian -O /etc/init.d/lighttpd chmod +x /etc/init.d/lighttpd /etc/init.d/lighttpd start
HOWTO: Index Page Column Sorting
Example - http://doc.lighttpd.net/
View Source and you will see the CSS and JavaScript.
Documentation - https://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModDirlisting
You will need Lighttpd version 1.4.42+
HOWTO: Lighttpd + PHP
Install the packages we need: (this may not be all, but these two will automatically download the rest as dependencies)
sudo aptitude install lighttpd php-cgi
Enable the fastcgi module and the php configuration with
sudo lighty-enable-mod fastcgi sudo lighty-enable-mod fastcgi-php
Reload the lighttpd daemon
sudo service lighttpd force-reload
To test if it's working create the file /var/www/index.php with the following contents:
<?php phpinfo(); ?>
Thanks - https://wiki.ubuntu.com/Lighttpd+PHP
HOWTO: Move Default Document Root
sudo mkdir /var/www/default sudo mv /var/www/index.lighttpd.html /var/www/default/ sudo chown -R www-data:www-data /var/www/default/ sudo nano /etc/lighttpd/lighttpd.conf server.document-root = "/var/www/default" sudo /etc/init.d/lighttpd restart
HOWTO: SSL Certificate with Let's Encrypt
http://wiki.indie-it.com/wiki/Let%27s_Encrypt#LetsEncrypt_with_Lighttpd
HOWTO: SSL Secure Certificate Purchase
HOWTO: SSL Secure Certificate Generation
https://www.digicert.com/easy-csr/openssl.htm
openssl req -new -newkey rsa:2048 -nodes -out domain_co_uk.csr -keyout domain_co_uk.key -subj "/C=GB/ST=County/L=Town/O=Your Name/OU=Web Site/CN=domain.co.uk"
HOWTO: SSL Secure Certificate Installation
https://www.digicert.com/ssl-certificate-installation-lighttpd.htm
cat COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > BundleCA.crt cat your_domain_name.key your_domain_name.crt > your_domain_name.pem
$SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/path/to/your_domain_name.pem" ssl.ca-file = "/path/to/BundleCA.crt" #ssl.use-compression = "disable" ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" #ssl.honor-cipher-order = "enable" #ssl.cipher-list = "AES256+EECDH:AES256+EDH:!aNULL:!eNULL" ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM" }
HOWTO: Restrict Access To IP Address
$HTTP["remoteip"] !~ "123.456.789.10|66.102.[0-15].[0-255]" { url.access-deny = ( "" ) }
or
$HTTP["remoteip"] !~ "66.249.*.*|66.102.*.*" { }
HOWTO: Restrict Access By User Agent Browser String
$HTTP["useragent"] !~ "GoogleDocs" { url.access-deny = ( "" ) }
HOWTO: Restrict Access By Request Method
$HTTP["request-method"] !~ "^GET$" { url.access-deny = ( "" ) }
or
$HTTP["request-method"] !~ "^(GET|HEAD)$" { url.access-deny = ( "" ) }
HOWTO: Password Protect Directory
Create the password file...
http://www.toolsvoid.com/htpasswd-password-generator
Or...
sudo apt-get install apache2-utils sudo htpasswd -c /etc/lighttpd/.htpasswd username
Add the authentication module to the main configuration file...
"mod_auth",
Add the following lines to the separate virtual host file...
auth.backend = "htpasswd" auth.backend.htpasswd.userfile = "/etc/lighttpd/.htpasswd" auth.require = ( "/webmail/" => ( "method" => "basic", "realm" => "Webmail Access", "require" => "valid-user", ) )
If you want to ignore localhost and your network each time, use this instead...
$HTTP["remoteip"] !~ "(127.0.0.1|192.168.0.*)" { auth.backend = "htpasswd" auth.backend.htpasswd.userfile = "/etc/lighttpd/.htpasswd" auth.require = ( "/webmail/" => ( "method" => "basic", "realm" => "Webmail Access", "require" => "valid-user", ) ) }
HOWTO: Allow Directory Listing
Add the following line to your main configuration file or separate virtual host file...
server.dir-listing = "enable"
...or...
$HTTP["url"] =~ "^/files($|/)" { server.dir-listing = "enable" }
Official Web Page - http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModDirlisting
Thanks - http://www.cyberciti.biz/tips/howto-lighttpd-enable-disable-directory-listing.html
HOWTO: Change Directory Listing Design
Create 2 files called HEADER.txt and README.txt in your web site folder.
These contain the HTML and CSS for your directory listing page (when no index.html is found).
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> <head> <title>Index of /linux/</title> <link rel="shortcut icon" href="/favicon.ico" /> <style type="text/css"> a, a:active {text-decoration: none; color: blue;} a:visited {color: #48468F;} a:hover, a:focus {text-decoration: underline; color: red;} body {background-color: #F5F5F5;} h2 {margin-bottom: 12px;} table {margin-left: 12px;} th, td { font: 90% monospace; text-align: left;} th { font-weight: bold; padding-right: 14px; padding-bottom: 3px;} td {padding-right: 14px;} td.s, th.s {text-align: right;} div.list { background-color: white; border-top: 1px solid #646464; border-bottom: 1px solid #646464; padding-top: 10px; padding-bottom: 14px;} div.foot { font: 90% monospace; color: #787878; padding-top: 4px;} </style> </head> <body>
...and...
</body> </html>
Then, add these settings to your web site configuration file...
dir-listing.auto-layout = "disable" dir-listing.show-header = "enable" dir-listing.hide-header-file = "enable" dir-listing.encode-header = "disable" dir-listing.show-readme = "enable" dir-listing.hide-readme-file = "enable" dir-listing.encode-readme = "disable"
...and restart Lighttpd.
Thanks - http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs_ModDirlisting
HOWTO: Allow IP Address To See Directory Listing
$HTTP["host"] == "www.domain.com" { $HTTP["remoteip"] =~ "123.456.789.0|987.654.432.1" { $HTTP["url"] =~ "^/images/3p($|/)" { dir-listing.activate = "enable" } } server.document-root = "/var/www/www.domain.com/html" server.errorlog = "/var/www/www.domain.com/logs/error.log" accesslog.filename = "/var/www/www.domain.com/logs/access.log" }
HOWTO: Hide Files From Directory Listing
dir-listing.exclude = ( "favicon.ico" )
HOWTO: Set File Mime Type For Downloads
mimetype.assign += ( ".log" => "text/plain" )
HOWTO: Fix File Timestamps
use_localtime=NO
HOWTO: WebDAV
Install the modules...
sudo apt-get install lighttpd-mod-webdav
Enable the modules...
sudo lighty-enable-mod auth sudo lighty-enable-mod webdav
Create the directories and apply correct permissions...
sudo mkdir /var/www/domain.co.uk/dav sudo chown -R www-data:www-data /var/www/domain.co.uk/dav sudo chmod g+w /var/www/domain.co.uk/dav
Add this to your virtual host file...
alias.url = ( "/dav" => "/var/www/domain.co.uk/dav" ) $HTTP["url"] =~ "^/dav($|/)" { dir-listing.activate = "enable" webdav.activate = "enable" webdav.is-readonly = "disable" webdav.sqlite-db-name = "/var/run/lighttpd/lighttpd.webdav_lock.db" auth.backend = "htpasswd" auth.backend.htpasswd.userfile = "/etc/lighttpd/htpasswd" auth.require = ( "" => ( "method" => "basic", "realm" => "webdav", "require" => "valid-user" ) ) }
Restart the web server...
sudo service lighttpd restart
Thanks - https://www.howtoforge.com/how-to-set-up-webdav-with-lighttpd-on-debian-squeeze
HOWTO: Multiple SSL Certificates on Single IP Address using Server Name Indication (SNI)
/etc/lighttpd/lighttpd.conf
In this file, you load the next file.
include "/etc/lighttpd/ssl.conf"
/etc/lighttpd/ssl.conf
In this file, you enable SSL on the port and set a default SSL Certificate then assign different Certificates for each host domain.
Be advised, you still have to include the non-www version of the host domain so that it matches correctly.
This is so you can redirect the non-www version of a domain name to the full subdomain www version - see the section on this below.
$SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/ssl/the-default-domain.com.pem" $HTTP["host"] == "example.org" { ssl.pemfile = "/etc/lighttpd/example.org.pem" } $HTTP["host"] == "www.example.org" { ssl.pemfile = "/etc/lighttpd/www.example.org.pem" } $HTTP["host"] == "mail.example.org" { ssl.pemfile = "/etc/lighttpd/mail.example.org.pem" } }
HOWTO: Redirect non-www and non-https to https www using schemes
# domain.com $HTTP["scheme"] == "http" { $HTTP["host"] == "domain.com" { url.redirect = ( ".*" => "https://www.domain.com/$1" ) url.redirect-code = 301 } $HTTP["host"] == "www.domain.com" { url.redirect = ( ".*" => "https://www.domain.com/$1" ) url.redirect-code = 301 } } $HTTP["scheme"] == "https" { $HTTP["host"] == "domain.com" { url.redirect = ( ".*" => "https://www.domain.com/$1" ) url.redirect-code = 301 } $HTTP["host"] == "www.domain.com" { server.name = "www.domain.com" server.document-root = "/var/www/www.domain.com/html" accesslog.filename = "/var/www/www.domain.com/logs/access.log" url.rewrite-if-not-file = ( "^/(wp-.+).*/?" => "$0", "^/keyword/([A-Za-z_0-9\-]+)/?$" => "/index.php?keyword=$1", "^/.*?(\?.*)?$" => "/index.php$1" ) } }
HOWTO: Redirect Root Domain To WWW
$HTTP["host"] =~ "^example.com$" { url.redirect = ( "^/(.*)" => "http://www.example.com/$1" ) }
HOWTO: Redirect To Secure HTTPS
https://wiki.archlinux.org/index.php/Lighttpd#Redirect_http_requests_to_https
server.modules += ( "mod_redirect" )
$SERVER["socket"] == ":80" { $HTTP["host"] =~ "example.org" { url.redirect = ( "^/(.*)" => "https://example.org/$1" ) server.name = "example.org" } } $SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/certs/server.pem" server.document-root = "..." }
When the visitor comes to port 80 (wrapped in the http scheme) it redirects them to port 443 then looks up the host details. This way, you can have multiple host configurations doing different things, like redirecting without any subdomain or a different subdomain with WordPress, and blocking access except for a few IP addresses, etc...
$HTTP["scheme"] == "http" { $HTTP["host"] =~ "^secure\.domain\.com$" { url.redirect = ( "^/(.*)" => "https://secure.domain.com/$1" ) } $HTTP["host"] =~ "^domain\.com$" { url.redirect = ( ".*" => "http://www.domain.com" ) url.redirect-code = 301 } $HTTP["host"] =~ "^aws\.domain\.com$" { server.document-root = "/var/www/aws.domain.com/html" server.errorlog = "/var/www/aws.domain.com/logs/error.log" accesslog.filename = "/var/www/aws.domain.com/logs/access.log" # uncomment below for wordpress url.rewrite-if-not-file = ( "^/(wp-.+).*/?" => "$0", "^/keyword/([A-Za-z_0-9\-]+)/?$" => "/index.php?keyword=$1", "^/.*?(\?.*)?$" => "/index.php$1" ) } } $SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/domain_com.pem" ssl.ca-file = "/etc/lighttpd/BundleCA.crt" ssl.use-sslv2 = "disable" ssl.use-sslv3 = "disable" ssl.cipher-list = "ECDHE-RSA-AES256-SHA384:AES256-SHA256:RC4-SHA:RC4:HIGH:!MD5:!aNULL:!EDH:!AESGCM" $HTTP["host"] =~ "secure\.domain\.com$" { server.document-root = "/var/www/secure.domain.com/html" server.errorlog = "/var/www/secure.domain.com/logs/error.log" accesslog.filename = "/var/www/secure.domain.com/logs/access.log" $HTTP["remoteip"] !~ "123.456.789.10|01.987.654.321|66.0.0.0/8" { url.access-deny = ( "" ) } } }
OLD METHOD
server.modules += ( "mod_redirect" ) $SERVER["socket"] == ":80" { $HTTP["host"] =~ "example.org" { url.redirect = ( "^/(.*)" => "https://example.org/$1" ) server.name = "example.org" } } $SERVER["socket"] == ":443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/ssl/server.pem" server.document-root = "..." }
HOWTO: Test Configuration
sudo lighttpd -t -f /etc/lighttpd/lighttpd.conf