How to Set Up ModSecurity with Apache on Debian/Ubuntu

This tutorial is going to show you how to install and use ModSecurity with Apache on Debian/Ubuntu servers. ModSecurity is the most well-known open-source web application firewall (WAF), providing comprehensive protection for your web applications (like WordPress, Nextcloud, Ghost etc) against a wide range of Layer 7 (HTTP) attacks, such as SQL injection, cross-site scripting, and local file inclusion.

Set Up ModSecurity with Apache on Debian Ubuntu

Web applications are inherently insecure. If you are a WordPress admin, you probably hear news of hackers exploiting vulnerabilities in WordPress plugins and themes every once in a while. It’s essential that you deploy a WAF on your web server, especially when you have old applications that don’t receive updates. ModSecurity is originally created by Ivan Ristić in 2002, currently maintained by Trustwave SpiderLabs. It’s the world’s most widely deployed WAF, used by over a million websites. cPanel, the most widely used hosting control panel, includes ModSecurity as its WAF.

You may have heard other host-based firewalls like iptables, UFW, and Firewalld, etc. The difference is that they work on layer 3 and 4 of the OSI model and take actions based on IP address and port number. ModSecurity, or web application firewalls in general, is specialized to focus on HTTP traffic (layer 7 of the OSI model) and takes action based on the content of HTTP request and response.

ModSecurity 3

ModSecurity was originally designed for Apache web server. It could work with Nginx before version 3.0 but suffered from poor performance. ModSecurity 3.0 (aka libmodsecurity) was released in 2017. It’s a milestone release, particularly for Nginx users, as it’s the first version to work natively with Nginx. The caveat of ModSecurity 3 is that it doesn’t yet have all the features as in the previous version (2.9), though each new release will add some of the missing features. Nginx users should use ModSecurity 3. However, if you use Apache, it’s recommended to continue using the 2.9 branch for the time being.

Step 1: Install ModSecurity with Apache on Debian/Ubuntu

The ModSecurity module for Apache is included in the default Debian/Ubuntu repository. To install it, run

sudo apt install libapache2-mod-security2

Then enable this module.

sudo a2enmod security2

Restart Apache for the change to take effect.

sudo systemctl restart apache2

Step 2: Configure ModSecurity

In the /etc/apache2/mods-enabled/security2.conf configuration file, you can find the following line.

IncludeOptional /etc/modsecurity/*.conf

sudo a2enmod security2

This means Apache will include all the *.conf files in /etc/modsecurity/ directory. We need to rename the modsecurity.conf-recommended file to make it work.

sudo mv /etc/modsecurity/modsecurity.conf-recommended /etc/modsecurity/modsecurity.conf

Then edit this file with a command-line text editor like Nano.

sudo nano /etc/modsecurity/modsecurity.conf

Find the following line.

SecRuleEngine DetectionOnly

This config tells ModSecurity to log HTTP transactions, but takes no action when an attack is detected. Change it to the following, so ModSecurity will detect and block web attacks.

SecRuleEngine On

Then find the following line (line 186), which tells ModSecurity what information should be included in the audit log.

SecAuditLogParts ABDEFHIJZ

However, the default setting is wrong. You will know why later when I explain how to understand ModSecurity logs. The setting should be changed to the following.

SecAuditLogParts ABCEFHJKZ

Save and close the file. Then restart Apache for the change to take effect. (Reloding the web server isn’t enough.)

sudo systemctl restart apache2

Step 3: Install the OWASP Core Rule Set (CRS)

To make ModSecurity protect your web applications, you need to define rules to detect malicious actors and block them. For beginners, it’s a good idea to install existing rule sets, so you can get started quickly and then learn the nitty-gritty down the road. There are several free rule sets for ModSecurity. The OWASP Core Rule Set (CRS) is the standard rule set used with ModSecurity.

  • It’s free, community-maintained and the most widely used rule set that provides a sold default configuration for ModSecurity.
  • It contains rules to help stop common attack vectors, including SQL injection (SQLi), cross-site scripting (XSS), and many others.
  • It can integrate with Project Honeypot.
  • It also contains rules to detect bots and scanners.
  • It has been tuned through wide exposure to have very few false positives.

When installing ModSecurity from the default Debian/Ubuntu repository, the modsecurity-crs package is also installed as a dependency. This package contains the OWASP core rule set version 3.x. However, it can become out of date. If you care about security, you should use the latest version of core rule set.

Download the latest OWASP CRS from GitHub.

wget https://github.com/coreruleset/coreruleset/archive/v3.3.0.tar.gz

Extract the file.

tar xvf v3.3.0.tar.gz

Create a directory to store CRS files.

sudo mkdir /etc/apache2/modsecurity-crs/

Move the extracted directory to /etc/apache2/modsecurity-crs/.

sudo mv coreruleset-3.3.0/ /etc/apache2/modsecurity-crs/

Go to that directory.

cd /etc/apache2/modsecurity-crs/coreruleset-3.3.0/

Rename the crs-setup.conf.example file.

sudo mv crs-setup.conf.example crs-setup.conf

Edit the /etc/apache2/mods-enabled/security2.conf file.

sudo nano /etc/apache2/mods-enabled/security2.conf

Find the following line, which loads the default CRS files.

IncludeOptional /usr/share/modsecurity-crs/*.load

Change it to the following, so the latest OWASP CRS will be used.

IncludeOptional /etc/apache2/modsecurity-crs/coreruleset-3.3.0/crs-setup.conf
IncludeOptional /etc/apache2/modsecurity-crs/coreruleset-3.3.0/rules/*.conf

apache Install the OWASP Core Rule Set CRS debian ubuntu

Save and close the file. Then test Apache configuration.

sudo apache2ctl -t

If the syntax is OK, then restart Apache.

sudo systemctl restart apache2

Step 4: Learn How OWASP CRS Works

Let’s take a look at the CRS config file, which provides you with good documentation on how CRS works.

sudo nano /etc/apache2/modsecurity-crs/coreruleset-3.3.0/crs-setup.conf

You can see that OWASP CRS can run in two modes:

  • self-contained mode. This is the traditional mode used in CRS v2.x. If an HTTP request matches a rule, ModSecurity will block the HTTP request immediately and stop evaluating remaining rules.
  • anomaly scoring mode. This is the default mode used in CRS v3.x. ModSecurity will check an HTTP request against all rules, and add a score to each matching rule. If a threshold is reached, then the HTTP request is considered an attack and will be blocked. The default score for inbound requests is 5 and for outbound response is 4.

modsecurity Anomaly Scoring debian ubuntu

When running in anomaly scoring mode, there are 4 paranoia levels.

  • Paranoia level 1 (default)
  • Paranoia level 2
  • Paranoia level 3
  • Paranoia level 4

With each paranoia level increase, the CRS enables additional rules giving you a higher level of security. However, higher paranoia levels also increase the possibility of blocking some legitimate traffic due to false alarms.

modsecurity Paranoia Level Initialization debian ubuntu

These are the two basic concepts you need to understand before using the CRS. Now we can close the file. The individual CRS rules are stored in /etc/apache2/modsecurity-crs/coreruleset-3.3.0/rules/ directory. Each matching rule will increase the anomaly score.

Step 5: Testing

To check if ModSecurity is working, you can launch a simple SQL injection attack on your own website. (Please note that it’s illegal to do security testing on other people’s websites without authorization.) Enter the following URL in your web browser.

https://yourdomain.com/?id=3 or 'a'='a'

If ModSecurity is working properly, your Apache web server should return a 403 forbidden error message.

modsecurity SQL injection test debian ubuntu

And in the audit log (/var/log/apache2/modsec_audit.log), you can see the following line in section H, which means ModSecurity detected and blocked this SQL injection attack by using OWASP CRS v3.3.0.

Action: Intercepted (phase 2)

modsecurity-apache-Action-Intercepted-phase-2-debian-ubuntu

When ModSecurity runs in DetectionOnly mode, it won’t block this SQL injection attack.

Step 6: Understanding the ModSecurity Logs

It’s important to analyze the ModSecurity logs, so you will know what kind of attacks are directed to your web applications and take better actions to defend against threat actors. There are mainly two kinds of logs in ModSecurity:

  • debug log: disabled by default.
  • audit log: /var/log/apache2/modsec_audit.log

To understand ModSecurity audit logs, you need to know the 5 processing phases in ModSecurity, which are:

  • Phase 1: Inspect request headers
  • Phase 2: Inspect request body
  • Phase 3: Inspect response headers
  • Phase 4: Inspect response body
  • Phase 5: Action (logging/blocking malicious requests)

They are also two types of logging file.

  • Serial: one file for all logs. This is the default.
  • Concurrent: multiple files for logging. This can provide better write performance. If you can notice your web pages slowing down after enabling ModSecurity, you can choose to use the concurrent logging type.

Events in the log are divided into several sections.

  • section A: audit log header
  • section B: request header
  • section C: request body
  • section D: reserved
  • section E: intermediary response body
  • section F: final response headers
  • section G: reserved
  • section H: audit log trailer
  • section I: compact request body alternative, which excludes files
  • section J: information on uploaded files
  • section K: every rule matched by an event, in order of match
  • section Z: final boundary

If you run a high traffic website, the ModSecurity audit log can get too large very quickly, so we need to configure log rotation for the ModSecurity audit log. Create a logrotate configuration file for ModSecurity.

sudo nano /etc/logrotate.d/modsecurity

Add the following lines to this file.

/var/log/apache2/modsec_audit.log
{
        rotate 14
        daily
        missingok
        compress
        delaycompress
        notifempty
}

This will rotate the log file every day (daily), compressing old versions (compress). The previous 14 log files will be kept (rotate 14), and no rotation will occur if the file is empty (notifempty). Save and close the file.

Step 7: Handling False Positives

ModSecurity is a generic web application firewall and not designed for a specific web application. The OWASP core rule set is also a generic rule set with no particular application in mind, so it’s likely that you will see false positives after enabling ModSecurity and OWASP CRS. If you increase the paranoia level in the CRS, there will be more false positives.

For example, by default, the CRS forbids Unix command injection like entering sudo on a web page, which is rather common on my blog. To eliminate false positives, you need to add rule exclusions to the CRS.

Application-Specific Rule Exclusions

There are some prebuilt, application-specific exclusions shipped with OWASP CRS. Edit the crs-setup.conf file.

sudo nano /etc/apache2/modsecurity-crs/coreruleset-3.3.0/crs-setup.conf

Go to the Application Specific Rule Exclusions section and find the following lines.

#SecAction \
# "id:900130,\
#  phase:1,\
#  nolog,\
#  pass,\
#  t:none,\
#  setvar:tx.crs_exclusions_cpanel=1,\
#  setvar:tx.crs_exclusions_drupal=1,\
#  setvar:tx.crs_exclusions_dokuwiki=1,\
#  setvar:tx.crs_exclusions_nextcloud=1,\
#  setvar:tx.crs_exclusions_wordpress=1,\
#  setvar:tx.crs_exclusions_xenforo=1"

For instance, If I want to enable WordPress exclusions, the above lines should be changed to the following. Please be careful about the syntax. There should be no comments between t:none,\ and setvar:tx.crs_exclusions_wordpress=1". (The backslash \ character at the end indicates the next line is a continuation of the current line.)

SecAction \
  "id:900130,\
   phase:1,\
   nolog,\
   pass,\
   t:none,\
   setvar:tx.crs_exclusions_wordpress=1"
#  setvar:tx.crs_exclusions_cpanel=1,\
#  setvar:tx.crs_exclusions_drupal=1,\
#  setvar:tx.crs_exclusions_dokuwiki=1,\
#  setvar:tx.crs_exclusions_nextcloud=1,\
#  setvar:tx.crs_exclusions_xenforo=1"

Save and close the file. Then test Apache configurations.

sudo apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

sudo systemctl restart apache2

Note that if you have multiple applications such as (WordPress, Nextcloud, Drupal, etc) installed on the same server, then the above rule exclusions will be applied to all applications. To minimize the security risks, you should enable a rule exclusion for one application only. To do that, go to the /etc/apache2/modsecurity-crs/coreruleset-3.3.0/rules/ directory.

cd /etc/apache2/modsecurity-crs/coreruleset-3.3.0/rules/

Rename the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS file.

sudo mv REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf.example REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Then edit this file.

sudo nano REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf

Add the following line at the bottom of this file. If your WordPress is using the blog.yourdomain.com sub-domain and the request header sent from visitor’s browser contains this sub-domain, then ModSecurity will apply the rule exclusions for WordPress.

SecRule REQUEST_HEADERS:Host "@streq blog.yourdomain.com" "id:1000,phase:1,setvar:tx.crs_exclusions_wordpress=1"

If you have installed Nextcloud on the same server, then you can also add the following line in this file, so if a visitor is accessing your Nextcloud sub-domain, ModSecurity will apply the Nextcloud rule exclusions.

SecRule REQUEST_HEADERS:Host "@streq nextcloud.yourdomain.com" "id:1001,phase:1,setvar:tx.crs_exclusions_nextcloud=1"

Save and close this file. Then test Apache configurations.

sudo apache2ctl -t

If the test is successful, rstart Apache for the change to take effect.

sudo systemctl restart apache2

Custom Rule Exclusions

Enabling the prebuilt application-specific rule exclusions might not eliminate all false positives. If so, you need to examine the ModSecurity audit log (/var/log/apache2/modsec_audit.log), check which rule caused the false positive and add your custom rule exclusions in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file.

Section H in the audit log tells you which rule is matched. For example, If I try to use the <code>...</code> HTML in the comment form, ModSecurity blocks my comment. The following log tells me that the HTTP request matched a rule in REQUEST-941-APPLICATION-ATTACK-XSS.conf (line 527). The rule ID is 941310. The request URI is /wp-comments-post.php.

modsecurity Custom Rule Exclusions

It’s detected as malformed encoding XSS filter attack. However, I want users to be able to use the <code>...</code> and <pre>...</pre> HTML tag in the comment form, so I created a rule exclusion. Add the following line at the bottom of the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file.

SecRule REQUEST_URI "@streq /wp-comments-post.php" "id:1002,phase:1,ctl:ruleRemoveById=941310"

This line tells ModSecurity that if the request URI is /wp-comments-post.php, then don’t apply rule ID 941310. Save and close the file. Then test Apache configurations.

sudo apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

sudo systemctl restart apache2

If a false positive matches multiple rule IDs, you can add rule exclusions in one line like so:

SecRule REQUEST_URI "@streq /wp-admin/post.php" "id:1003,phase:1,ctl:ruleRemoveById=941160,ctl:ruleRemoveById=941310,ctl:ruleRemoveById=942100"

Note: It’s not recommended to disable too many rules of level 1 in the OWASP CRS, as it will make your website be hacked much more easily. Only disable rules if you know what you are doing.

IP Whitelisting

If you want to disable ModSecurity for your own IP address, but leave it enabled for all other IP addresses, then add the following custom rule in the REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file. Replace 12.34.56.78 with your real IP address.

SecRule REMOTE_ADDR "^12\.34\.56\.78" "id:1004,phase:1,allow,ctl:ruleEngine=off"

To whitelist a subnet, use the following syntax, which will whitelist the 10.10.10.0/24 network.

SecRule REMOTE_ADDR "^10\.10\.10.*" "id:1005,phase:1,allow,ctl:ruleEngine=off"

Save and close the file. Then test Apache configurations.

sudo apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

sudo systemctl restart apache2

Chaining Rules

If your Apache has multiple virtual hosts, you may want to whitelist your IP address for a specific virtual host. You need to chain two rules like so:

SecRule REMOTE_ADDR "^12\.34\.56\.78" "id:1004,phase:1,allow,ctl:ruleEngine=off,chain"
SecRule REQUEST_HEADERS:Host "@streq nextcloud.yourdomain.com" "t:none"

The chain keyword at the end of the first rule indicates that the ruleEngine=off action will only be taken if the condition in the next rule is also true.

(Optional) Integrate ModSecurity with Project Honeypot

Project Honeypot maintains a list of known malicious IP addresses, available free to the public. ModSecurity can integrates with Project Honeypot and block IP addresses on the Project Honeypot list.

Note that using Project Honeypot will make your website slower for new visitors, because your web server will need to send a query to Project Honeypot before it can send a response to the new visitor. However, once the IP reputation data is cached on your web server, the performance impact will be very minimal.

To use Project Honeypot, first create a free account on its website. Then go to your account dashboard and click the get one link to request an access key for the HTTP blacklist.

Project Honeypot HTTP blacklist API key

Next, edit the crs-setup.conf file.

sudo nano /etc/apache2/modsecurity-crs/coreruleset-3.3.0/crs-setup.conf

Find the following lines.

#SecHttpBlKey XXXXXXXXXXXXXXXXX
#SecAction "id:900500,\
#  phase:1,\
#  nolog,\
#  pass,\
#  t:none,\
#  setvar:tx.block_search_ip=1,\
#  setvar:tx.block_suspicious_ip=1,\
#  setvar:tx.block_harvester_ip=1,\
#  setvar:tx.block_spammer_ip=1"

Remove the beginning # characters to uncomment them, and add your HTTPBL API key obtained from Project Honeypot.

Integrate ModSecurity with Project Honeypot

Note that block_search_ip should be set to 0 (disabled), as we don’t want to block search engine crawlers. Save and close the file. Then restart Apache.

sudo systemctl restart apache2

Now ModSecurity will query Project Honeypot on all HTTP requests. To test if this would work, edit the crs-setup.conf file.

sudo nano /etc/apache2/modsecurity-crs/coreruleset-3.3.0/crs-setup.conf

In Nano text editor, you can quickly jump to the end of the file by pressing Ctrl+W, then Ctrl+V. Add the following line at the end of this file. This allows us to pass an IP address in an URL. (Once the test is successful, you can remove this line from the file.)

SecRule ARGS:IP "@rbl dnsbl.httpbl.org" "phase:1,id:171,t:none,deny,nolog,auditlog,msg:'RBL Match for SPAM Source'

Save and close the file. Test Apache configurations.

sudo apache2ctl -t

Then restart Apache.

sudo systemctl restart apache2

Go to Project Honeypot website and find a malicious IP address, for example, 134.119.218.243. Run the following command to test the HTTP blacklist.

curl -i -s -k -X $'GET' 'https://yourdomain.com/?IP=134.119.218.243'

Your Apache web server should return a 403 forbidden response because the IP address is on Project Honeypot.

How to Disable ModSecurity for a Virtual Host

By default, ModSecurity is enabled for all Apache virtual hosts. If you want to disable ModSecurity for a specific virtual host, then edit the virtual host file (/etc/apache2/sites-enabled/example.com.conf) and add the following line to the <VirtualHost>...</VirtualHost> context.

SecRuleEngine DetectionOnly

Reload Apache for the change to take effect.

sudo systemctl reload apache2

How to Upgrade OWASP CRS

You need to upgrade the core rule set when a new version comes out. The process is straightforward.

  • Go through step 3 again to install the new version of core rule set.
  • Then go to step 7. Copy of your custom rules in the crs-setup.conf  and REQUEST-900-EXCLUSION-RULES-BEFORE-CRS file.

Next, test Apache configurations.

sudo apache2ctl -t

If the test is successful, restart Apache for the change to take effect.

sudo systemctl restart apache2

How do you know if the new version is working? Launch a simple SQL injection attack like in step 5 and check your server logs. It will show you the CRS version that’s preventing this attack.

Next Step

I hope this tutorial helped you set up ModSecurity web application firewall with Apache on Debian/Ubuntu. You may also want to check out other security tutorials.

As always, if you found this post useful, then subscribe to our free newsletter to get new tutorials 🙂

Rate this tutorial
[Total: 8 Average: 4.9]

24 Responses to “How to Set Up ModSecurity with Apache on Debian/Ubuntu

  • somerandom
    10 months ago

    Thanks. I was running into an issue this morning setting up mod security on Gentoo and your guide helped me out.

  • wow. modsecurity looks really cool. it is great news that they started to support nginx. i look forward to nginx instructions once it stable. i never knew these security companies existed. thank you for the enlightenment! cheers LinuxBabe

  • I received this error on install, I believe because ModSecurity was already installed and seem to be enabled.

    Setting up libyajl2:arm64 (2.1.0-3) ...
    Setting up libapache2-mod-security2 (2.9.3-1) ...
    apache2_invoke: Enable module security2
    apache2_reload: Your configuration is broken. Not restarting Apache 2
    apache2_reload: apache2: Syntax error on line 147 of /etc/apache2/apache2.conf: 
    Syntax error on line 12 of /etc/apache2/mods-enabled/security2.conf: Syntax erro
    r on line 5 of /usr/share/modsecurity-crs/owasp-crs.load: Could not open configu
    ration file /etc/modsecurity/crs/crs-setup.conf: No such file or directory
    Setting up modsecurity-crs (3.2.0-1) ...
    

    I’ve also added you NextCloud exclusion to Rules, but I’ve having connection issues with my laptop syncing to Nextcloud.

    Not sure what I have missed, but my NextCloud client says connection closed.

  • I had to restore from a backup as this didn’t play well with my Nextcloud 20.0.4 server.

    After following this tutorial, Nextcloud dropped connections to NC clients.
    The Web access was bugged to, NC overview suddenly threw warnings about caldav (https://docs.nextcloud.com/server/20/admin_manual/issues/general_troubleshooting.html#service-discovery).
    The photos page would fail with error.
    Couldn’t access rubbish bin(Denied).
    Tasks page would load.
    Etc…

    Not sure what else needs to be done after adding the exclusions to ModSecurity?
    I triple checked the steps, so not sure what else I can try.

    I have previous tweaked my /etc/apache2/conf-enabled/security.conf to include some basic security hardening like Headers tags .
    I also have fail2ban running, blocking excessive GET, POST, BOTS & DOS. but I am unsure if that would conflict with ModSecurity?

    I’ll have to read up some more & poke around the Nextcloud forums to see if I can find any clues.

    • I’m using OWASP CRS 3.3.0, and added the following line in the /etc/apache2/modsecurity-crs/coreruleset-3.3.0/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf file.

      SecRule REQUEST_HEADERS:Host "@streq nextcloud.yourdomain.com" "id:1001,phase:1,setvar:tx.crs_exclusions_nextcloud=1"

      After that, My Nextcloud is working again.

      You may want to restart Apache and check if it’s running.

      sudo systemctl restart apache2
      sudo systemctl status apache2

      You don’t need to restore your server from backup. If ModSecurity is not working as expected, edit the /etc/modsecurity/modsecurity.conf file, set SecRuleEngine to DetectionOnly, so ModSecurity won’t block any request.

      • Thanks for the reply & apologies for the messy comments, I forgot your html tags.

        I did a remove, purge & reinstall of modsecurity, no errors this time.

        And sorry, I thought I followed along, but I had failed to uncomment a couple of lines in the crs-setup.conf file.

        However after removing the necessary comments I get the following error (Please note I’m using a differing folder than your tutorial).

        AH00526: Syntax error on line 362 of /etc/modsecurity/coreruleset-3.3.0/crs-setup.conf:
        Error parsing actions: Unexpected character at position 51: id:900130,   phase:1,   nolog,   pass,   t:none, \ setvar:tx.crs_exclusions_cpanel=1, \
        setvar:tx.crs_exclusions_drupal=1,  \
        setvar:tx.crs_exclusions_dokuwiki=1, \
        setvar:tx.crs_exclusions_nextcloud=1, \ setvar:tx.crs_exclusions_wordpress=1, \  setvar:tx.crs_exclusions_xenforo=1
        Action '-t' failed.
        The Apache error log may have more information.
        • denwar
          9 months ago
          SecAction \
             "id:900130,\
              phase:1,\
              nolog,\
              pass,\
              t:none,\
           #  setvar:tx.crs_exclusions_cpanel=1,\
           #  setvar:tx.crs_exclusions_drupal=1,\
           #  setvar:tx.crs_exclusions_dokuwiki=1,\
              setvar:tx.crs_exclusions_nextcloud=1"
           #  setvar:tx.crs_exclusions_wordpress=1,\
           #  setvar:tx.crs_exclusions_xenforo=1"
          

          apache2ctl -t

          AH00526: Syntax error on line 360 of /etc/modsecurity/coreruleset-3.3.0/crs-setup.conf:
          Error parsing actions: Unexpected character at position 51: id:900130,   phase:1,   nolog,   pass,   t:none,#  setvar:tx.crs_exclusions_cpanel=1,#  setvar:tx.crs_exclusions_drupal=1,#  setvar:tx.crs_exclusions_dokuwiki=1,   setvar:tx.crs_exclusions_nextcloud=1
          Action '-t' failed.
          The Apache error log may have more information.
          
        • denwar
          9 months ago

          Sorry, I’m burning the candles at both ends……

          I removed the commented lines out of the double quotes for that rule.

          apache2ctl -t is happy now.

          I owe you a beer for the hassle, I appreciate your tutorials and they’ve help me learn a great deal!

    • Yes, you should remove those comment lines.

      There should be no comments between t:none,\ and setvar:tx.crs_exclusions_nextcloud=1". The backslash \ character at the end indicates the next line is a continuation of the current line.)

  • Still getting some problems with Nextcloud.

    Photos page returns an error.

    Settings > Overview, security scan shows.

    There are some warnings regarding your setup.
    
        Your web server is not properly set up to resolve "/.well-known/caldav". Further information can be found in the documentation.
        Your web server is not properly set up to resolve "/.well-known/carddav". Further information can be found in the documentation.
    
    Please double check the installation guides ↗, and check for any errors or warnings in the log. 

    Nextcloud logs show many entries like the following:

    [Mon Jan 04 00:27:02.226318 2021] [:error] [pid 5914:tid 281472608575888] [client IPHIDDEN:62951] [client IPHIDDEN] ModSecurity: Warning. String match "nextcloud.com" at REQUEST_HEADERS:Host. [file "/etc/modsecurity/coreruleset-3.3.0/rules/REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf"] [line "167"] [id "1001"] [hostname "nextcloud.com"] [uri "/remote.php/dav/calendars/USER/quick-list/"] [unique_id "X-XXXXXXXXXXXXXX-XXXXXXXXs"] 
    • The warnings on /.well-known/caldav and /.well-known/carddav are not caused by ModSecurity. It’s related to your Apache virtual host configurations.

      A standard Apache virtual host file for Nextcloud is as follows:

      <IfModule mod_ssl.c>
      SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
      <VirtualHost *:443>
              DocumentRoot "/var/www/nextcloud"
              ServerName nextcloud.example.com
      
              ErrorLog ${APACHE_LOG_DIR}/nextcloud.error
              CustomLog ${APACHE_LOG_DIR}/nextcloud.access combined
      
              <Directory /var/www/nextcloud/>
                  Require all granted
                  Options FollowSymlinks MultiViews
                  AllowOverride All
      
                 <IfModule mod_dav.c>
                     Dav off
                 </IfModule>
      
              SetEnv HOME /var/www/nextcloud
              SetEnv HTTP_HOME /var/www/nextcloud
              Satisfy Any
      
             </Directory>
      
      
      SSLCertificateFile /etc/letsencrypt/live/nextcloud.example.com/fullchain.pem
      SSLCertificateKeyFile /etc/letsencrypt/live/nextcloud.example.com/privkey.pem
      Include /etc/letsencrypt/options-ssl-apache.conf
      SSLUseStapling on
      </VirtualHost>
      </IfModule>
      

      And the /var/www/nextcloud/.htaccess file should have the following lines.

      <IfModule mod_rewrite.c>
        RewriteEngine on
        RewriteCond %{HTTP_USER_AGENT} DavClnt
        RewriteRule ^$ /remote.php/webdav/ [L,R=302]
        RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
        RewriteRule ^\.well-known/host-meta /public.php?service=host-meta [QSA,L]
        RewriteRule ^\.well-known/host-meta\.json /public.php?service=host-meta-json [QSA,L]
        RewriteRule ^\.well-known/webfinger /public.php?service=webfinger [QSA,L]
        RewriteRule ^\.well-known/nodeinfo /public.php?service=nodeinfo [QSA,L]
        RewriteRule ^\.well-known/carddav /remote.php/dav/ [R=301,L]
        RewriteRule ^\.well-known/caldav /remote.php/dav/ [R=301,L]
        RewriteRule ^remote/(.*) remote.php [QSA,L]
        RewriteRule ^(?:build|tests|config|lib|3rdparty|templates)/.* - [R=404,L]
        RewriteCond %{REQUEST_URI} !^/\.well-known/(acme-challenge|pki-validation)/.*
        RewriteRule ^(?:\.|autotest|occ|issue|indie|db_|console).* - [R=404,L]
      </IfModule>
      

      Make sure you have enabled the required modules in Apache for Nextcloud.

      sudo a2enmod rewrite headers env dir mime setenvif ssl

      Then restart Apache.

      sudo systemctl restart apache2

      Your ModSecurity logs indicate the rule exclusions for Nextcloud is working.

  • This caldav errors only occur when ModSecurity is active.
    My Nextcloud .htaccess is default config, appears as you have posted.

    My vhost file is as follows…….

    SSLStaplingCache shmcb:/var/run/apache2/stapling_cache(128000)
    
            DocumentRoot "/var/www/nextcloud"
            ServerName MYWEBSITE.net
    
            ErrorLog ${APACHE_LOG_DIR}/nextcloud.error
            CustomLog ${APACHE_LOG_DIR}/nextcloud.access combined
    
            
                Require all granted
                Options FollowSymlinks MultiViews
                AllowOverride All
    
               
                   Dav off
               
    
            SetEnv HOME /var/www/nextcloud
            SetEnv HTTP_HOME /var/www/nextcloud
            Satisfy Any
    
           
    Protocols h2 http/1.1
    SSLCertificateFile /etc/letsencrypt/live/MYWEBSITE.net/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/MYWEBSITE.net/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
    SSLUseStapling on
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    
    
    

    The only other changes I’ve made to Apache2 are to the security.conf (conf-enabled).

    #Header set X-Frame-Options: "sameorigin"
    Header always append X-Frame-Options "DENY"
    # Custom Added settings by Mendax
    FileETag none
    Header edit Set-Cookie ^(.*)$ $1;HttpOnly;Secure
    Header set X-XSS-Protection "1; mode=block"
    #Header set X-Permitted-Cross-Domain-Policies: "master-only"
    Header set X-Permitted-Cross-Domain-Policies: "none"
    Header set Referrer-Policy "no-referrer"
    Header always unset "X-Powered-By"
    Header unset "X-Powered-By"
    RequestReadTimeout header=20-40,MinRate=500 body=20,MinRate=500
    
    • If ModSecurity gets in the way, you would see a 403 forbidden error in your web application or in the modsecurity log.

      • Xiao,
        This is a great article – thanks. Do you know how to stop logging of the exclusions in the apache2 logs? The apache2 logs are flooded with “ModSecurity: Warning. String match…” This makes it impossible to troubleshoot other issues.

        Denwar,
        I also received errors for /.well-known/ once modsecurity was enabled. This error was resolved by following the steps for adding exclusions for id’s 911100, 949110, and 980130.

        Something like below may work for you:

        SecRule REQUEST_URI “@beginsWith /.wellknown/” “id:1004,phase:2,pass,nolog,ctl:ruleRemoveById=911100,ctl:ruleRemoveById=949110,ctl:ruleRemoveById=980130”
        • Simply add nolog option, so it won’t log the rule exclusion match.

          SecRule REQUEST_HEADERS:Host "@streq nextcloud.yourdomain.com" "id:1001,phase:1,nolog,setvar:tx.crs_exclusions_nextcloud=1"
  • Thanks, Xiao, I will try to restart the server as all of the exclusions include “nolog” but all exclusions are still logged. If that does not work there must be a conflict somewhere.

  • Xiao, have you had any difficulties with the SecRequestBodyNoFilesLimit and SecRequestBodyLimit? In my setup the “No files” limit applies to my NextCloud web file uploads (even though it should not apply to files). It doesn’t seem to be well documented, so leads me to believe it may be something specific in my setup (I am using an Apache2 reverse proxy). Any thoughts you have would be appreciated.

  • hi Xiao, maybe this is a bit too complicated for me; and apologies if this is the wrong place to post; but what do you think of
    CrowdSec
    see for example for a description
    https://opensource.com/article/21/1/crowdsec-rest-api

  • Ribamar FS
    8 months ago

    Very good. Thank you.

  • A great detailed guide.

  • Eric Jacolin
    5 months ago

    Great article, thanks.
    In Step 3, “Edit the /etc/apache2/mods-enabled/security2.conf file.” should be:
    “Edit the /etc/apache2/mods-available/security2.conf file.”
    Otherwise this won’t work in a Docker deployment

  • dragonsway
    4 months ago

    My logrotate service failes. It complains about a duplicate entry for modsecurity.

       ● logrotate.service - Rotate log files
           Loaded: loaded (/lib/systemd/system/logrotate.service; static; vendor preset: enabled)
           Active: failed (Result: exit-code) since Tue 2021-06-08 14:22:07 CST; 2h 54min ago
             Docs: man:logrotate(8)
                   man:logrotate.conf(5)
         Main PID: 15370 (code=exited, status=1/FAILURE)
        
        Jun 08 14:22:07 server1.example.com systemd[1]: Starting Rotate log files...
        Jun 08 14:22:07 server1.example.com logrotate[15370]: error: modsecurity:1 duplicate log entry for /var/log/apache2/modsec_audit.log
        Jun 08 14:22:07 server1.example.com logrotate[15370]: error: found error in file modsecurity, skipping
        Jun 08 14:22:07 server1.example.com systemd[1]: logrotate.service: Main process exited, code=exited, status=1/FAILURE
        Jun 08 14:22:07 server1.example.com systemd[1]: logrotate.service: Failed with result 'exit-code'.
        Jun 08 14:22:07 server1.example.com systemd[1]: Failed to start Rotate log files.
    

    However, /etc/logrotate.d/modsecurity doesn’t contain any duplicates:

    /var/log/apache2/modsec_audit.log
    {
            rotate 14
            daily
            missingok
            compress
            delaycompress
            notifempty
    }
    
    Any suggestions?
    

Leave a Comment

  • Comments with links are moderated by admin before published.
  • Your email address will not be published.
  • Use <pre> ... </pre> HTML tag to quote the output from your terminal/console.
  • Please use the community (https://community.linuxbabe.com) for questions unrelated to this article.
  • I don't have time to answer every question. Making a donation would incentivize me to spend more time answering questions.

The maximum upload file size: 2 MB. You can upload: image. Links to YouTube, Facebook, Twitter and other services inserted in the comment text will be automatically embedded. Drop file here