Serverpilot is a hosted control panel for setting up and managing LAMP/LEMP stacks on Ubuntu servers. Just like any other control panel it can be installed with a single command. ServerPilot is simple to use and does not install unnecessary packages like other commercial control panels.
I had written an article for DigitalOcean on setting up mod_security on Apache. Since I found several DO users using ServerPilot to manage their Droplets I wanted to do a small piece on configuring mod_security on ServerPilot managed Ubuntu servers. ServerPilot supports custom .conf files for Apache making it easier load additional modules. This tutorial with be brief, for a detailed explanation please read the guide I wrote for DigitalOcean.
Update: As of 15th April installing mod_security from the Ubuntu repository no longer works (on Ubuntu 16.04 and 18.04) and outputs the following Apache error:
httpd: Syntax error on line 160 of /etc/apache-sp/httpd.conf: Syntax error on line 3 of /etc/apache-sp/conf.d/security2.conf: Cannot load /usr/lib/apache2/modules/mod_security2.so into server: /usr/lib/apache2//modules/mod_security2.so: undefined symbol: apr_crypto_block_cleanup
So on Ubuntu 16.04 and 18.04 mod_security has to be installed from source. Users of Ubuntu 14.04 can follow the previous method.
Installing mod_security on Ubuntu 16.04 and 18.04
Install dependencies
Update the apt repository and install packages necessary for compiling and building from source.
apt-get update apt-get install build-essential libpcre3-dev libxml2-dev libexpat1-dev
Visit APR’s (Apache Portable Runtime) website, download the latest version of APR and APR-util, compile and install them.
cd /tmp wget http://www-eu.apache.org/dist//apr/apr-1.6.3.tar.gz tar -xzf apr-1.6.3.tar.gz cd apr-1.6.3 ./configure make sudo make install cd /tmp wget http://www-eu.apache.org/dist//apr/apr-util-1.6.1.tar.gz tar -xzf apr-util-1.6.1.tar.gz cd apr-util-1.6.1/ ./configure --with-apr=/usr/local/apr make sudo make install
Install mod_security from source
Download, compile and install mod_security from source.
cd /tmp wget https://www.modsecurity.org/tarball/2.9.2/modsecurity-2.9.2.tar.gz tar -xzf modsecurity-2.9.2.tar.gz cd modsecurity-2.9.2/ ./configure --enable-htaccess-config --with-apxs=/opt/sp/apache/bin/apxs make sudo make install
Create mod_security config files
Since we install mod_security from source the configuration directories and files have to be created manually.
sudo mkdir /etc/modsecurity sudo wget -O /etc/modsecurity/unicode.mapping https://github.com/SpiderLabs/ModSecurity/raw/v2/master/unicode.mapping sudo wget -O /etc/modsecurity/modsecurity.conf https://github.com/SpiderLabs/ModSecurity/raw/v2/master/modsecurity.conf-recommended
Create a file at /etc/apache-sp/conf.d/security2.conf
and place the following config:
LoadModule unique_id_module lib/sp-apache/mod_unique_id.so LoadModule security2_module /usr/local/modsecurity/lib/mod_security2.so <IfModule security2_module> IncludeOptional /etc/modsecurity/*.conf IncludeOptional "/usr/share/modsecurity-crs/*.conf" IncludeOptional "/usr/share/modsecurity-crs/activated_rules/*.conf" </IfModule>
Next use sed
to edit modsecurity.conf
and configure mod_security to block attacks and disable buffering of HTTP response bodies:
sudo sed -i "s/SecRuleEngine DetectionOnly/SecRuleEngine On/" /etc/modsecurity/modsecurity.conf sudo sed -i "s/SecResponseBodyAccess On/SecResponseBodyAccess Off/" /etc/modsecurity/modsecurity.conf
Setup mod_security Core Rule Set (CRS)
Download mod_security rule set, extract and copy them to their own directory.
cd /tmp wget https://github.com/SpiderLabs/owasp-modsecurity-crs/archive/2.2.9.tar.gz tar -xzf 2.2.9.tar.gz sudo mkdir /usr/share/modsecurity-crs sudo mv owasp-modsecurity-crs-2.2.9/ /usr/share/modsecurity-crs sudo mv /usr/share/modsecurity-crs/modsecurity_crs_10_setup.conf{.example,}
Do a config test for Apache:
sudo /opt/sp/apache/bin/apachectl -t
This should return “Syntax OK”.
Restart Apache:
service apache-sp restart
Confirm if the module was loaded:
sudo /opt/sp/apache/bin/apachectl -M | grep security2
You should see a module named security2_module (shared) which indicates that the module was loaded.
That’s it, now scroll down to the SQL injection test section and test the rules.
Installing mod_security on Ubuntu 14.04
Install mod_security
Update the apt repository and install the mod_security package:
apt-get update apt-get install libapache2-mod-security2 modsecurity-crs
Enable mod_unique_id
Modsecurity depends on a module named mod_unique_id. This module will prevent Apache from starting if the server’s hostname doesn’t resolve. So ensure the hostname resolves.
ping -c 4 `hostname` ping -c 4 `hostname -f`
Both of these should resolve to your loopback IP address, if not edit the /etc/hosts
file and add your server’s hostname.
Execute the following command to add unique_id to the list of load modules to be loaded:
bash -c "echo 'LoadModule unique_id_module lib/sp-apache/mod_unique_id.so' > /etc/apache-sp/conf.d/unique_id.conf"
Create mod_security config files
Create a .conf file to load the mod_security module file.
bash -c "cat /etc/apache2/mods-available/security2.{load,conf} > /etc/apache-sp/conf.d/security2.conf"
Edit the newly created file and add the following before the </ifModule>
line:
IncludeOptional "/usr/share/modsecurity-crs/*.conf" IncludeOptional "/usr/share/modsecurity-crs/activated_rules/*.conf"
Once added the file should look like this:
# Depends: unique_id LoadModule security2_module /usr/lib/apache2/modules/mod_security2.so <IfModule security2_module> # Default Debian dir for modsecurity's persistent data SecDataDir /var/cache/modsecurity # Include all the *.conf files in /etc/modsecurity. # Keeping your local configuration in that directory # will allow for an easy upgrade of THIS file and # make your life easier IncludeOptional /etc/modsecurity/*.conf IncludeOptional "/usr/share/modsecurity-crs/*.conf" IncludeOptional "/usr/share/modsecurity-crs/activated_rules/*.conf" </IfModule>
Rename the modsecurity.conf-recommended
file:
mv /etc/modsecurity/modsecurity.conf{-recommended,}
Edit the renamed file and configure mod_security to block attacks:
sed -i "s/SecRuleEngine DetectionOnly/SecRuleEngine On/" /etc/modsecurity/modsecurity.conf
Disable buffering of HTTP response bodies:
sed -i "s/SecResponseBodyAccess On/SecResponseBodyAccess Off/" /etc/modsecurity/modsecurity.conf
Important: This is SecResponseBodyAccess and NOT SecRequestBodyAccess.
The directives SecRequestBodyLimit
, SecRequestBodyNoFilesLimit
and SecRequestBodyInMemoryLimit
have been discussed in the DigitalOcean article.
Create a directory named “apache2” inside “/var/log”, this is where mod_security will store its audit log file.
mkdir /var/log/apache2
Do a config test for Apache:
/opt/sp/apache/bin/apachectl -t
This should return “Syntax OK”
Restart Apache:
service apache-sp restart
Confirm if the module was loaded:
/opt/sp/apache/bin/apachectl -M | grep security2
You should see a module named security2_module (shared) which indicates that the module was loaded.
SQL injection test
Enable the SQL injection rule:
cd /usr/share/modsecurity-crs/activated_rules ln -s ../base_rules/modsecurity_crs_41_sql_injection_attacks.conf .
Restart Apache for the rules to take effect:
service apache-sp restart
Test SQL injection using the following cURL request:
curl -o /dev/null -s -v -d "' or true -- " http://example.com
This should return a 403 Forbidden error as follows:
* Hostname was found in DNS cache * Trying 1.1.1.1... * Connected to example.com (1.1.1.1) port 80 (#0) > POST / HTTP/1.1 > User-Agent: curl/7.35.0 > Host: example.com > Accept: */* > Content-Length: 13 > Content-Type: application/x-www-form-urlencoded > } [data not shown] * upload completely sent off: 13 out of 13 bytes < HTTP/1.1 403 Forbidden * Server nginx is not blacklisted < Server: nginx < Date: Mon, 04 May 2015 19:42:12 GMT < Content-Type: text/html; charset=iso-8859-1 < Content-Length: 209 < Connection: keep-alive < Vary: Accept-Encoding < { [data not shown] * Connection #0 to host example.com left intact
That’s it, we now have mod_security running on a server managed by ServerPilot. If you use the ServerPilot links in this article to signup, you’ll get a $10 account credit. 😉
Richard says
Thanks heaps for the tutorial, though a few things didn’t seem to work for me at first.
sh -c “cat /etc/apache2/mods-available/security2.{load,conf} > /etc/apache-sp/conf.d/security2.conf” – didn’t appear to work on a default SP + Ubunutu install. Instead I added the lines below to security2.conf
Include /etc/apache2/mods-available/security2.load
Include /etc/apache2/mods-available/security2.conf
Not sure if thats correct though.
I also had to modify the modsecurity.conf file to change the default logging location to work with ServerPilot’s location.
After downloading the OWASP rules and enabling them modsecurity is working however I’ve had several troubles with my WordPress site, is there any recommended rules for a WordPress install running Woocommerce with Modsecurity, as it appears the default OWASP rules are way too restrictive. Also not sure if having Nginx infront is causing any issues.
Jesin A says
Hi Richard,
I tried the
sh -c "cat /etc/apache2/mods-available[..]
command on a new Ubuntu 14.04 VM with default SP and it worked. What happened when you tried that command?And yes, using
Include
is also correct and will work.Sorry, I missed out the part on creating a directory in the /var/log location. I’ve added the step in the article –
mkdir /var/log/apache2
Also rules should be available at /usr/share/modsecurity-crs, did you manually download them?
Googling “wordpress mod_security” will show up a lot of suggestions on what to exclude. But it is better to find them out yourself to get it tailored for your needs. The following command lists the rule IDs that blocked the request.
You can them exclude them as per your requirements.
Richard says
Hi Jesin
I did another install on one of my other servers and the sh -c “cat /etc/apache2/mods-available[..] – came up with cat: /etc/apache2/mods-available/security2.{load,conf}: No such file or directory. Not sure why its different, I’m using a standard Vultr VPS.
Cheers for the additional info, I managed to exclude around 25 rules that were causing issues and the website now works fine. It was necessary to perform actions on both the front and backend of wordpress to cover all security rules being triggered. I added one at a time using the command;
echo “SecRuleRemoveById xxxxxx” >> /usr/share/modsecurity-crs/activated_rules/whitelist.conf
using your egrep command to find them.
I guess it’s now just a matter of looking over those rules to see how I can add them back in without causing issues.
Thanks again
Jesin A says
I think you are using Ubuntu 12.04, here the files are named as mod-security.conf and mod-security.load.
Certain rules must be excluded for certain areas of the site to function properly. This could be useful – http://wpsecure.net/2012/01/using-mod_security-2-with-wordpress/
Peter says
I ran through these steps and everything seems to have completed just fine, however when I attempt to load any site/page on the server, I get a 403 Forbidden. I cleared cookies and then was able to load the frontend of the WordPress site, but then after I login to the backend, it gives me a 403 again.
I can go into /etc/modsecurity/modsecurity.conf and change “SecRuleEngine On” to OFF and restart apache and everything works fine again.
The only thing that I was confused on was the last injection test. When I enter “curl -o /dev/null -s -v -d “‘ or true — ” http://example.com” exactly, I don’t get a 403, I get 200 OK. Was I suppose to substitute “example.com” for something else? If I put this server’s URL in there I do in fact get a 403 though, just like if I try to load the site in the browser.
Peter says
I guess I don’t really know if I need to enable mod security at all on my server pilot server. I am using the WP Ultimate CSV Importer plugin and under security and performance checker, it has a “No” next to Mod Security and they say I need to add “SecFilterEngine Off and SecFilterScanPOS off” to my htaccess. When I did that, their status didn’t change. So I figured I needed to install Mod Security.
I am trying to enable the comments importer module with this plugin and Mod Security is listed under the “Required to enable/disable Loaders, Extensions and modules” so I figured I have to be close to the right track on this.
Sorry, probably way over topic since I’m throwing things at the wall at this point.
Jesin A says
Hi Peter,
The plugin you mentioned doesn’t need mod_security to work. It is only providing you instructions to disable mod_security (if installed and enabled) to avoid conflicts.
If you wish to use mod_security, rule exceptions have to be made for certain files and directories as normal operations on WordPress (and similar CMS) trigger mod_security rules.
Liew CheonFong says
Hi, I got error when restart apache-sp. Do you have any idea? Thank you.
$ service apache-sp restart
/etc/init.d/apache-sp: line 13: ulimit: open files: cannot modify limit: Operation not permitted
/etc/init.d/apache-sp: line 14: ulimit: open files: cannot modify limit: Invalid argument
httpd: Syntax error on line 161 of /etc/apache-sp/httpd.conf: Syntax error on line 25 of /etc/apache-sp/vhosts.d/0default.conf: Could not open config directory /etc/apache-sp/vhosts.d/0default.d: Permission denied
Jesin A says
Hi Liew,
Login as the root user and try this command. Or login as a user with sudo privileges and enter “sudo service apache-sp restart”
Bruno Oliveira says
Hi .. Thanks for the tutorial .. It’s unique.
But I’m having a lot of false positives with these SQL injection settings.
I use WHMCS and it’s blocking access to me, and it does not let me run modules. I have to disable all #SecRule
I have no experience with this, but after I did that, the log is empty!
Is there a newer configuration for “modsecurity_crs_41_sql_injection_attacks.conf”? One that I can replace that does not give me as many locks and false positive?
Thanks for the help anyway. Sorry for my bad English.
Rick says
Looks like this method is not working anymore.
Trying to install Mod security on a current Serverpilot setup, requires apache2-api-20120211.
Serverpilot install their own apache version.
Is there a way to overcome this?
Jesin A says
Hi Rick,
It looks like ServerPilot is blocking the installation of the
apache2-bin
package which containsapache2-api-20120211
. Installing this package won’t install the complete Apache server.To over come this create a new file here –
/etc/apt/preferences.d/09overrideapache
with the following contentsNow run the following commands and they should work:
Rick says
Worked like a charm! (and it also solved the same problem I had with mod_evasive)
Thanks a lot for providing such a detailed answer.
This is a very handy tutorial.