How To Protect Yourself From A DDoS Attack On The Web Server Level!

DDoS Attack At The Web Server Level Main Logo

How To Protect Yourself from A DDoS Attack On The Web Server Level!

Statistics DDoS-attacks shows the constant growth and displacement of the vector from the network layer to the application layer.

If you have a small site on the server with minimal characteristics, then you might be able to put it down by any completely legal means of stress testing.

Warning: We do not recommend to perform this to anyone due to the IP address is easy can be tracked and the experimenter can fly into the damage compensation.


Therefore, a site without DDoS protection will very soon look as wild as a Windows 98 computer without an antivirus.

DDoS Attack At The Web Server Level 1

The first thing you can and should do to protect your site is to configure the iptables firewall. I use almost unchanged settings iptables from the article on the site of one of the providers of protection against DDoS-attacks. The only thing I changed is the number of allowed connections in rules # 8 and # 10.

Before running a script that changes iptables parameters, you need to make sure that there is an alternative possibility to reset these parameters to their initial state. Because if the rules are set incorrectly, no one can connect to the server, including the administrator.

The iptables firewall controls the attack at the network level. The next thing to configure is a web server. As a web server that is open for access from the Internet, we will consider nginx. In the file nginx.conf, you need to increase the limits for the number of files and open connections (the example is taken from Wikipedia):

# Increase the maximum number of files used
worker_rlimit_nofile 80000;
events {
# Increase the maximum number of connections
worker_connections 65536;
# Using an effective epoll method to handle connections

Next, configure the default server that will deny access to those devices (for example, IoT) that will access the IP address and not the domain name:

# Default server configuration
server {
listen 80 default_server;
listen 443 ssl default_server;
deny all;

Also in nginx, you can set some limits on the number of hits, but this setting will not be very flexible and not selective at all. Our goal is to make such protection at the web server level, to pay off the requests of the attackers, but to skip the requests of good users to the server.

The speed of executing good code on Lua is a little inferior to good code in C. But to develop on Lua is faster and easier, and besides, scripts can be changed without recompiling the server. At the next restart, they will be read, compiled by LuaJIT, and that’s all that’s required.

  • Detailed instructions how to fix optnresty. After installation, we continue to configure nginx. In the HTTP section, we define the necessary parameters for the operation of Lua scripts:

lua_shared_dict whitelist 10m;
lua_shared_dict banlist 100m;

lua_package_path '/home/username/antiddos/?.lua;;';

init_by_lua '
local whitelist = ngx.shared.whitelist
whitelist:add("", true)
whitelist:add("", true)

access_by_lua_file /home/username/antiddos/main.lua;

  • The lua_shared_dict string creates a new dictionary (key-value). This dictionary will be unified for all queries, so it is convenient to store white and blacklists. This dictionary, in addition to the key-value parameters, can have a time-to-live parameter, which is ideal for storing counters, if you want to limit the number of requests in a period of time.
  • The lua_package_path line specifies the paths for searching for Lua modules, in which you need to include a directory with scripts. Two consecutive semicolons at the end of a line mean that this path is appended to the current value of the path, and not completely replaces it.
  • The init_by_lua line specifies the code that will be executed once when the server starts (and not every new request). It specifies a whitelist of IP addresses. The second parameter of the function add – true is just the value that is then used in the if statement. The third time-to-live parameter is missing, so the value will be stored without time limit.
  • The line access_by_lua_file specifies the path to the script that will be executed for each request to the server (not only when the server starts). In it, in fact, is the whole logic of defense.

Let’s take a look at some of the tests that can be done with the Lua script:

-- if client IP is in whitelist, pass
local whitelist = ngx.shared.whitelist
in_whitelist = whitelist:get(ngx.var.remote_addr)
if in_whitelist then

-- HTTP headers
local headers = ngx.req.get_headers();

-- wp ddos
if type(headers["User-Agent"]) ~= "string"
or headers["User-Agent"] == ""
or["User-Agent"], "^WordPress", "ioj") then
ngx.log(ngx.ERR, "ddos")

local banlist = ngx.shared.banlist
local search_bot = "search:bot:count:request:per:10:s"
if["User-Agent"], "Google Page Speed Insights|Googlebot|baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator", "ioj") then
local count, err = banlist:incr(search_bot, 1)
if not count then
banlist:set(search_bot, 1, 10)
count = 1
if count >= 50 then
if count == 50 then
ngx.log(ngx.ERR, "bot banned")

The programming language Lua is in many ways similar (even too much) to JavaScript, so the Lua code is intuitive to anyone who writes JavaScript.

The global variable ngx is used to communicate with the context of the nginx server. The return statement outside the body of the function means a return from the module.

  • In this example, if the IP address is in the whitelist, then the script runs out, and the normal processing of the nginx request continues.

Further, an attack based on the features of the implementation of the WordPress. If the attack is detected, then the job ends in a special status 444 (typical for nginx only): ngx.exit (444).

And, finally, we give the “green road” to search bots. Here you have to use the counter because under the search bot are often counterfeited by intruders – therefore we consider the number of hits. ban list: set (search_bot, 1, 10) initializes the counter, which will be reset after 10 seconds after creation. ban list: incr (search_bot, 1) adds one to the current counter value.


Typically, such a web server is used as a proxy, and the protected web server is hosted on a different IP address.