Lighttpd configuration file: /etc/lighttpd/lighttpd.conf (Debian/Ubuntu) If using Pi-hole: /etc/lighttpd/external.conf

Fail2ban Configuration

Create/Modify ufw.conf (/etc/fail2ban/action.d/ufw.conf)

Make sure you configured your UFW.

[Definition]
actionstart =
actionstop =
actioncheck =
actionban = ufw insert 1 deny from <ip> to any
actionunban = ufw delete deny from <ip> to any

Create a new configuration for lighttpd ( /etc/fail2ban/filter.d/lighttpd-custom.conf). The configuration below will ban the client with request of 400 Bad Request, 403 Forbidden and 404 HTTP Not Found.

[Definition]
failregex = ^<HOST> .* "(GET|POST|HEAD) [^"]+" 400
            ^<HOST> .* "(GET|POST|HEAD) [^"]+" 403
            ^<HOST> .* "(GET|POST|HEAD) [^"]+" 404
ignoreregex =

Modify your fail2ban jail configuration (eg. /etc/fail2ban/jail.d/defaults.conf)

[lighttpd-custom]
enabled = true
port = http
filter = lighttpd-custom
logpath = /var/log/lighttpd/access.log
bantime = 86400
findtime = 600
maxretry = 2
banaction = ufw

Apply the lighttpd configuration below and modify them. Do not forget to restart fail2ban and lighttpd.

References:
https://calomel.org/lighttpd.html
https://www.owasp.org/index.php/Main_Page
https://stackoverflow.com/questions/25778420/fail2ban-regular-to-find-403-request-in-nginx
server.modules = (
        "mod_access",
        "mod_accesslog",
        "mod_setenv",
        "mod_evasive"
)


#Use specific server port
$SERVER["socket"] == ":82" {

server.error-handler-404 = "/index.php"
#set custom error page

#set document root
server.document-root        = "/var/www/error.php"
index-file.names = ( "index.html" )

#deny certain files
url.access-deny   = ( "~", ".inc", ".md", ".yml", ".ini", ".txt", ".json", ".htaccess" )

#Changing server name header (Security through obscurity)
server.tag = "httpd"

#global server bandwidth limit
server.kbytes-per-second=512

#individual connectoin limit
connection.kbytes-per-second=128

#preventing DoS
server.max-keep-alive-requests=10
server.max-keep-alive-idle=5
server.max-read-idle=10
server.max-write-idle=10

#limit request method "POST" size in kilobytes (KB)
server.max-request-size  = 1

#disable multi range requests
server.range-requests    = "disable"

#disable symlinks
server.follow-symlink    = "disable"

# mod_evasive like
evasive.max-conns-per-ip = 10

#Setting the log format to be like Apache (Httpd) or Nginx
accesslog.filename          = "/var/log/lighttpd/access.log"
accesslog.format = "%h %V %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\""

#do not log an IP address
$HTTP["remoteip"] == "127.0.0.1" {
    accesslog.filename = "/dev/null"
}


#OWASP Secure Headers Project
#Set your content security policy based on your site policies.

setenv.add-response-header = ("X-Frame-Options" => "DENY",)
setenv.add-response-header += ("X-XSS-Protection" => "1; mode=block",)
setenv.add-response-header += ("X-Content-Type-Options" => "nosniff",)
setenv.add-response-header += ("X-Permitted-Cross-Domain-Policies" => "none",)
setenv.add-response-header += ("Referrer-Policy" => "strict-origin",)
setenv.add-response-header  += ("Content-Security-Policy" => "default-src 'self';",)

#Disable etags
etag.use-inode = "disable"
etag.use-mtime = "disable"
etag.use-size = "disable"
static-file.etags = "disable"

#Disable auto index dir listing
dir-listing.activate  = "disable"

#Disable SSL engine if not needed
ssl.engine = "disable"


#Deny specific ip address(es)
$HTTP[""] == "127.0.0.1|192.168.254.243"{
 url.access-deny = ("")
}

#Denying user agents you can include bots here
$HTTP["useragent"] =~ "(Google|Yandex|Bind|BUbiNG|MauiBot|zgrab)" {
  url.access-deny = ("")
}

#Limiting request methods to GET HEAD POST
#To test for request method try $ curl -X DELETE http://mysite.com
$HTTP["request-method"] !~ "^(GET|HEAD|POST)" {
     url.access-deny = ( "" )
}

#Deny access to specific directory
$HTTP["url"] =~ "^/database" {
        url.access-deny = ("")
}

#MISC
#Redirect old domain to new
$HTTP["host"] =~ "^old.domain.com" {
        url.redirect = ( "^/(.*)" => "http://new.domain.com/$1/" )
}


$HTTP["url"] =~ "\/\..*" {
   url.access-deny = ( "" )
}

}

Except where otherwise noted, this work is licensed under Creative Commons Attribution-ShareAlike 4.0 International License (http://creativecommons.org/licenses/by-sa/4.0/).
I hope that this post is useful to you, if you liked this post you may support me via liberapay. Thank you for your support.

Donate using Liberapay