Bunny Web Server

Why Replace Apache/PHP?

This new web server solves the following problems with Apache:

  1. configuration
  2. removes all unused options and scripting
  3. removes "server limit", lightweight threads can allow >100K simultaneous connections
  4. adds extra security features
  5. adds complete logging of connections
  6. adds proxy service to retrieve data
  7. adds realtime notifications

Configuration File

certfile = /dps3/ssl/dss.pem
certcafile = /dps3/ssl/dssca.pem
That's it. I'll add more options as I need them, but the idea is to keep it small and simple.

Removal of Options

This server does not support PHP or any scripting language. PHP can't do threads which causes memory usage problems when using a large number of connections, and the server does not require any scripting capabilities anyway. We have C++ and simple, easy-to-change source.

Server Limit

This server is designed to have 300K simultaneous connections per server for real-time notifications, these can be load balanced for unlimited connections.

Extra Security

Security is redesigned using access lists. I have the lists split into six different files.

Paramter Checking

First we check the paramters to make sure they fit a pattern, the file parmMap.txt can have:
page=*
q=node/add
q=user
q=user/register
v=*
callback=*
pos=*
These would be the only options allowed via GET, all others get code 412 returned.

Application Checking

Next we check to see if the requested path is acceptable by checking against the positive list:
/
/about
/contact
/dps/public/dfn/terms_of_service
/faq
/main
/node/1
/node/2
/node/3
/node/4
....
/favicon.ico
/misc/ajax.js
/misc/arrow-asc.png
/misc/autocomplete.js
/misc/jquery.once.js
/misc/menu-collapsed.png
...
You can use wildcards:
/sites/default/files/css/*

Page Cache

We map certain pages to local cached files so they don't have to go to the application, ie Drupal:
/=files/main.html
/main=files/main.html
/products=files/products.html
/about=files/about.html
....

Application Map

We maintain a list of valid paths in the application, ie Drupal, because we don't want to have Drupal have to deal with invalid requests:
/user/
/user/*
/user/*/edit
/user/*/dps/bundles
/user/*/dps/companies
/user/*/dps/devices
/user/*/dps/bundles
/user/*/dsec/companies
....
And there's extra wildcarding options here to make sure it's a valid path.

Extra Logging

The bunny server has a dedicated thread for logging so each of the worker threads only writes to memory and aquires no resources, other than a semaphore if used with Notifications, to be efficient. Also there should be no way for a connection to not be logged. In Apache, if a connection is established but the client doesn't send a valid HTTP message, nothing is logged. That won't happen here, every connection is logged:

195.154.167.170 - - [21/Apr/2020:07:16:16 +0000] "GET / " 200 45966
66.249.64.20 - - [21/Apr/2020:07:17:36 +0000] "GET / " 200 45966
2.56.139.185 - - [21/Apr/2020:07:20:10 +0000] "GET / " 200 45966
2.56.139.185 - - [21/Apr/2020:07:20:12 +0000] "GET /user/register " 200 8715
2.56.139.185 - - [21/Apr/2020:07:20:15 +0000] "POST /user/register " 200 8912
209.17.97.90 - - [21/Apr/2020:07:26:22 +0000] "GET / " 200 45966
54.36.149.70 - - [21/Apr/2020:07:26:31 +0000] "GET /documents/dssClient.README.html " 200 1249
173.252.111.4 - - [21/Apr/2020:07:31:37 +0000] "NONE BAD REQUEST " 0 0
162.243.130.155 - - [21/Apr/2020:07:32:16 +0000] "GET / " 200 45966
49.70.52.44 - - [21/Apr/2020:07:42:41 +0000] "GET /promotions.html " 400 0
49.70.60.166 - - [21/Apr/2020:07:42:42 +0000] "GET /promotions.html " 400 0
42.236.12.150 - - [21/Apr/2020:07:51:22 +0000] "GET / " 200 45966
42.236.12.130 - - [21/Apr/2020:07:51:30 +0000] "GET / " 200 45966
171.67.71.243 - - [21/Apr/2020:07:52:48 +0000] "NONE BAD REQUEST " 0 0
35.154.57.40 - - [21/Apr/2020:07:55:16 +0000] "GET /console " 400 0
35.154.57.40 - - [21/Apr/2020:07:55:19 +0000] "GET /cgi-bin/test-cgi " 400 0
35.154.57.40 - - [21/Apr/2020:07:55:21 +0000] "GET / " 200 45966
35.154.57.40 - - [21/Apr/2020:07:55:24 +0000] "GET /horde/imp/test.php " 400 0
35.154.57.40 - - [21/Apr/2020:07:55:27 +0000] "GET /login.action " 400 0
54.36.149.32 - - [21/Apr/2020:07:55:29 +0000] "GET /robots.txt " 200 2189
35.154.57.40 - - [21/Apr/2020:07:55:29 +0000] "GET /login?from=0.000000 " 412 0
35.154.57.40 - - [21/Apr/2020:07:55:32 +0000] "GET /phpMyAdmin/scripts/setup.php " 400 0
35.154.57.40 - - [21/Apr/2020:07:55:34 +0000] "GET /phpmyadmin/scripts/setup.php " 400 0
35.154.57.40 - - [21/Apr/2020:07:55:36 +0000] "GET / " 200 45966
35.154.57.40 - - [21/Apr/2020:07:55:39 +0000] "GET /atutor/index.php " 400 0
54.36.150.26 - - [21/Apr/2020:07:55:40 +0000] "GET / " 200 45966
196.52.84.33 - - [21/Apr/2020:07:56:29 +0000] "GET /user/register " 200 8715
196.52.84.33 - - [21/Apr/2020:07:56:31 +0000] "GET /user/register " 200 8715
196.52.84.33 - - [21/Apr/2020:07:56:34 +0000] "POST /user/register " 200 8912

71.6.167.142 - - [21/Apr/2020:11:36:28 +0000] "GET / " 200 45966
71.6.167.142 - - [21/Apr/2020:11:36:28 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:28 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:39 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:39 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:39 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:39 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:39 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:41 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:43 +0000] "GET /robots.txt " 200 2189
71.6.167.142 - - [21/Apr/2020:11:36:43 +0000] "GET /sitemap.xml " 400 0
71.6.167.142 - - [21/Apr/2020:11:36:43 +0000] "GET /.well-known/security.txt " 400 0
71.6.167.142 - - [21/Apr/2020:11:36:43 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:43 +0000] "NONE BAD REQUEST " 0 0
71.6.167.142 - - [21/Apr/2020:11:36:44 +0000] "GET /favicon.ico " 200 3078
71.6.167.142 - - [21/Apr/2020:11:36:44 +0000] "GET /misc/ajax.js " 200 25035
71.6.167.142 - - [21/Apr/2020:11:36:44 +0000] "GET /CHANGELOG.txt " 400 0
47.57.24.93 - - [21/Apr/2020:11:39:20 +0000] "GET / " 200 45966
47.57.24.93 - - [21/Apr/2020:11:39:49 +0000] "GET /about " 200 45762

125.161.104.119 - - [21/Apr/2020:12:44:30 +0000] "GET / " 200 45966
82.115.213.54 - - [21/Apr/2020:12:44:37 +0000] "GET /?q=user " 200 45966
91.76.148.82 - - [21/Apr/2020:12:54:34 +0000] "GET / " 200 45966
198.143.155.138 - - [21/Apr/2020:12:56:32 +0000] "GET / " 200 45966
198.143.155.138 - - [21/Apr/2020:12:56:41 +0000] "NONE BAD REQUEST " 0 0
198.143.155.138 - - [21/Apr/2020:12:56:45 +0000] "NONE BAD REQUEST " 0 0
198.143.155.138 - - [21/Apr/2020:12:56:54 +0000] "NONE BAD REQUEST " 0 0

Adds Proxy Service

The Bunny Server completes the preliminary security validation for the connections and logs the result. The rest is done with proxies so no resources are acquired by the threads, except for a semaphore with Notifications.

The BunnyMan proxy takes the requests after validation and forwards them to the appropriate place, using load balancing as needed. The requests contains a type field and everything needed to route the messages to any type of system, but in this case we forward to the Bunny Farm, which is in PHP/C++, for processing.

Adds Realtime Notifications

This is probably the biggest problem with Apache, when to get notified when data has changed so you can get data in a timely way without polling?

This system should support an unlimited number of notification clients.