Skip to content

Instantly share code, notes, and snippets.

@DenisJunio
Forked from nfsarmento/nginx-wordpress.conf
Created September 14, 2020 20:21

Revisions

  1. @nfsarmento nfsarmento revised this gist Sep 8, 2020. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions nginx-wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -21,11 +21,11 @@ location = /robots.txt {

    # Limit access to avoid brute force attack
    # if you getting error please add this (limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;) to your /etc/nginx/nginx.conf
    location = /wp-login.php {
    limit_req zone=one burst=1 nodelay;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    }
    #location = /wp-login.php {
    # limit_req zone=one burst=1 nodelay;
    # include fastcgi_params;
    # fastcgi_pass 127.0.0.1:9000;
    #}

    #Deny access to wp-content folders for suspicious files
    location ~* ^/(wp-content)/(.*?)\.(zip|gz|tar|bzip2|7z)\$ {
  2. @nfsarmento nfsarmento revised this gist Aug 15, 2020. 1 changed file with 139 additions and 0 deletions.
    139 changes: 139 additions & 0 deletions nginx-wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -191,3 +191,142 @@ location ~* ^/wp-content/uploads/.*\.(?:s?html?|php|js|swf)$ {
    location ~* ^/(?:xmlrpc\.php|wp-links-opml\.php|wp-config\.php|wp-config-sample\.php|wp-comments-post\.php|readme\.html|license\.txt)$ {
    deny all;
    }


    # NGINX RESTRICTIONS

    # Directives to send expires headers and turn off 404 error logging.
    location ~* ^.+\.(curl|heic|swf|tiff|rss|atom|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
    access_log off;
    log_not_found off;
    expires max;
    }

    # Web fonts send expires headers
    location ~* \.(?:eot|otf|ttf|woff|woff2)$ {
    expires max;
    access_log off;
    add_header Cache-Control "public";
    }

    # SVGs & MP4 WEBM send expires headers - this rule is set specific to ns site
    location ~* \.(?:svg|svgz|mp4|webm)$ {
    expires max;
    access_log off;
    add_header Cache-Control "public";
    }

    # Media: images, icons, video, audio send expires headers.
    location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|aac|m4a|mp3|ogg|ogv|webp)$ {
    expires 1M;
    access_log off;
    add_header Cache-Control "public";
    }

    # Cache css & js files
    location ~* \.(?:css(\.map)?|js(\.map)?)$ {
    add_header "Access-Control-Allow-Origin" "*";
    access_log off;
    log_not_found off;
    expires 30d;
    }

    # CSS and Javascript send expires headers.
    location ~* \.(?:css|js)$ {
    expires 1y;
    access_log off;
    add_header Cache-Control "public";
    }

    # HTML send expires headers.
    location ~* \.(html)$ {
    expires 7d;
    access_log off;
    add_header Cache-Control "public";
    }

    # Security settings for better privacy
    # Deny hidden files
    # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
    location ~ /\. {
    deny all;
    }

    # Use the directory /var/www/html to valide acme-challenge
    # just create the sub-directories .well-known/acme-challenge and set www-data as owner
    # #
    # chown -R www-data:www-data /var/www/html && sudo -u www-data mkdir -p /var/www/html/.well-known/acme-challenge
    # #
    location /.well-known/acme-challenge/ {
    alias /var/www/html/.well-known/acme-challenge/;
    }

    # Return 403 forbidden for readme.(txt|html) or license.(txt|html) or example.(txt|html) or other common git repository files
    location ~* "/(^$|readme|license|example|README|LEGALNOTICE|INSTALLATION|CHANGELOG)\.(txt|html|md)" {
    deny all;
    }

    # Deny backup extensions & log files and return 403 forbidden
    location ~* "\.(old|orig|original|php#|php~|php_bak|save|swo|aspx?|tpl|sh|bash|bak?|cfg|cgi|dll|exe|git|hg|ini|jsp|log|mdb|out|sql|svn|swp|tar|rdf)$" {
    deny all;
    }

    # common nginx configuration to block sql injection and other attacks
    location ~* "(eval\()" {
    deny all;
    }
    location ~* "(127\.0\.0\.1)" {
    deny all;
    }
    location ~* "([a-z0-9]{2000})" {
    deny all;
    }
    location ~* "(javascript\:)(.*)(\;)" {
    deny all;
    }

    location ~* "(base64_encode)(.*)(\()" {
    deny all;
    }
    location ~* "(GLOBALS|REQUEST)(=|\[|%)" {
    deny all;
    }
    location ~* "(<|%3C).*script.*(>|%3)" {
    deny all;
    }
    location ~ "(\\|\.\.\.|\.\./|~|`|<|>|\|)" {
    deny all;
    }
    location ~* "(boot\.ini|etc/passwd|self/environ)" {
    deny all;
    }
    location ~* "(thumbs?(_editor|open)?|tim(thumb)?)\.php" {
    deny all;
    }
    location ~* "(\'|\")(.*)(drop|insert|md5|select|union)" {
    deny all;
    }
    location ~* "(https?|ftp|php):/" {
    deny all;
    }
    location ~* "(=\\\'|=\\%27|/\\\'/?)\." {
    deny all;
    }
    location ~ "(\{0\}|\(/\(|\.\.\.|\+\+\+|\\\"\\\")" {
    deny all;
    }
    location ~ "(~|`|<|>|:|;|%|\\|\s|\{|\}|\[|\]|\|)" {
    deny all;
    }
    location ~* "/(=|\$&|_mm|(wp-)?config\.|cgi-|etc/passwd|muieblack)" {
    deny all;
    }

    location ~* "(&pws=0|_vti_|\(null\)|\{\$itemURL\}|echo(.*)kae|etc/passwd|eval\(|self/environ)" {
    deny all;
    }
    location ~* "/(^$|mobiquo|phpinfo|shell|sqlpatch|thumb|thumb_editor|thumbopen|timthumb|webshell|config|settings|configuration)\.php" {
    deny all;
    }


  3. @nfsarmento nfsarmento renamed this gist Aug 15, 2020. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  4. @nfsarmento nfsarmento revised this gist Aug 15, 2020. 1 changed file with 28 additions and 4 deletions.
    32 changes: 28 additions & 4 deletions wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -150,20 +150,44 @@ location ~ /\.ht {
    access_log off;
    log_not_found off;
    }
    location ~ /\.user.ini {
    deny all;
    access_log off;
    log_not_found off;
    }


    # Deny access to uploads that aren’t images, videos, music, etc.
    location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ {
    deny all;
    }

    #WordFence
    location ~ \.user\.ini$ {
    deny all;
    }

    # Deny backup extensions & log files
    location ~* ^.+\.(bak|log|old|orig|original|php#|php~|php_bak|save|swo|swp|sql)$ {
    deny all;
    access_log off;
    log_not_found off;
    }


    #WordFence
    location ~ \.user\.ini$ {
    deny all;
    }


    # WordPress: deny wp-content, wp-includes php files
    location ~* ^/(?:wp-content|wp-includes)/.*\.php$ {
    deny all;
    }

    # WordPress: deny wp-content/uploads nasty stuff
    location ~* ^/wp-content/uploads/.*\.(?:s?html?|php|js|swf)$ {
    deny all;
    }

    # WordPress: deny general stuff
    location ~* ^/(?:xmlrpc\.php|wp-links-opml\.php|wp-config\.php|wp-config-sample\.php|wp-comments-post\.php|readme\.html|license\.txt)$ {
    deny all;
    }
  5. @nfsarmento nfsarmento revised this gist May 16, 2020. 1 changed file with 7 additions and 0 deletions.
    7 changes: 7 additions & 0 deletions wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -160,3 +160,10 @@ location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ {
    location ~ \.user\.ini$ {
    deny all;
    }

    # Deny backup extensions & log files
    location ~* ^.+\.(bak|log|old|orig|original|php#|php~|php_bak|save|swo|swp|sql)$ {
    deny all;
    access_log off;
    log_not_found off;
    }
  6. @nfsarmento nfsarmento revised this gist May 16, 2020. 1 changed file with 28 additions and 28 deletions.
    56 changes: 28 additions & 28 deletions wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -1,16 +1,31 @@
    ############ WordPress ####################

    # Disable logging for favicon and robots.txt
    location = /favicon.ico {
    try_files /favicon.ico @empty;
    access_log off;
    log_not_found off;
    expires max;
    }

    location @empty {
    empty_gif;
    }

    location = /robots.txt {
    allow all;
    log_not_found off;
    access_log off;
    try_files $uri /index.php?$args;
    }

    # Limit access to avoid brute force attack
    # if you getting error please add this (limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;) to your /etc/nginx/nginx.conf
    # location = /wp-login.php {
    # limit_req zone=one burst=1 nodelay;
    # include fastcgi_params;
    # fastcgi_pass 127.0.0.1:9000;
    #}
    location = /wp-login.php {
    limit_req zone=one burst=1 nodelay;
    include fastcgi_params;
    fastcgi_pass 127.0.0.1:9000;
    }

    #Deny access to wp-content folders for suspicious files
    location ~* ^/(wp-content)/(.*?)\.(zip|gz|tar|bzip2|7z)\$ {
    @@ -62,7 +77,6 @@ location /wp-content/uploads/ {

    # nginx block xmlrpc.php requests
    location /xmlrpc.php {
    allow 172.0.1.1;
    deny all;
    access_log off;
    log_not_found off;
    @@ -86,23 +100,13 @@ location ^~ /wp-admin/upgrade.php {
    error_page 403 =404 / ;
    }

    # stop user enumeration
    if ($args ~ "^/?author=([0-9]*)"){
    set $rule_0 1$rule_0;
    }

    if ($rule_0 = "1"){
    rewrite ^/$ https://next100years.org.uk/404 permanent;
    }

    # Deny access to any files with a .php extension in the uploads directory
    # Works in sub-directory installs and also in multisite network
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
    }


    # Stop scann for the follow files on plugins folder
    location ~* ^/wp-content/plugins/.+\.(txt|log|md)$ {
    deny all;
    @@ -115,7 +119,6 @@ location ~* ^/wp-content/themes/.+\.(txt|log|md)$ {
    error_page 403 =404 / ;
    }


    #This module will allow us to pattern match certain key files and inject random text in the files that
    # is non-destructive / non-invasive and will most importantly alter the md5sum calculated on such files. All transparent to WPScan.
    location ~* ^/(license.txt|wp-includes/(.*)/.+\.(js|css)|wp-admin/(.*)/.+\.(js|css))$ {
    @@ -124,14 +127,6 @@ location ~* ^/(license.txt|wp-includes/(.*)/.+\.(js|css)|wp-admin/(.*)/.+\.(js|c
    sub_filter ';' '; /* $msec */ ';
    }

    #Limit Request Types
    #Most of the time your website may only perform two types fo requests i.e.
    #GET to retrieve data from your site and POST to upload data to your site.
    #Limiting the type of request that our site can handle to only these two sounds like a good idea here.
    if ($request_method !~ ^(GET|POST)$ ) {
    return 444;
    }

    #Direct PHP File Access
    #If somehow, a hacker successfully sneaks in a PHP file onto your site,
    #they’ll be able to run this file by loading file which effectively becomes a backdoor to infiltrate your site.
    @@ -155,8 +150,13 @@ location ~ /\.ht {
    access_log off;
    log_not_found off;
    }
    location ~ /\.user.ini {

    # Deny access to uploads that aren’t images, videos, music, etc.
    location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ {
    deny all;
    access_log off;
    log_not_found off;
    }

    #WordFence
    location ~ \.user\.ini$ {
    deny all;
    }
  7. @nfsarmento nfsarmento revised this gist Feb 25, 2020. 1 changed file with 38 additions and 0 deletions.
    38 changes: 38 additions & 0 deletions wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -62,6 +62,7 @@ location /wp-content/uploads/ {

    # nginx block xmlrpc.php requests
    location /xmlrpc.php {
    allow 172.0.1.1;
    deny all;
    access_log off;
    log_not_found off;
    @@ -122,3 +123,40 @@ location ~* ^/(license.txt|wp-includes/(.*)/.+\.(js|css)|wp-admin/(.*)/.+\.(js|c
    sub_filter_once on;
    sub_filter ';' '; /* $msec */ ';
    }

    #Limit Request Types
    #Most of the time your website may only perform two types fo requests i.e.
    #GET to retrieve data from your site and POST to upload data to your site.
    #Limiting the type of request that our site can handle to only these two sounds like a good idea here.
    if ($request_method !~ ^(GET|POST)$ ) {
    return 444;
    }

    #Direct PHP File Access
    #If somehow, a hacker successfully sneaks in a PHP file onto your site,
    #they’ll be able to run this file by loading file which effectively becomes a backdoor to infiltrate your site.
    #We should disable direct access to any PHP files by adding the following rules:
    location ~* /(?:uploads|files|wp-content|wp-includes|akismet)/.*.php$ {
    deny all;
    access_log off;
    log_not_found off;
    }

    #Dotfiles
    #Similar to PHP file, a dotfile like .htaccess, .user.ini, and .git may contain sensitive information.
    #To be on the safer side, it’s better to disable direct access to these files.
    location ~ /\.(svn|git)/* {
    deny all;
    access_log off;
    log_not_found off;
    }
    location ~ /\.ht {
    deny all;
    access_log off;
    log_not_found off;
    }
    location ~ /\.user.ini {
    deny all;
    access_log off;
    log_not_found off;
    }
  8. @nfsarmento nfsarmento created this gist Feb 25, 2020.
    124 changes: 124 additions & 0 deletions wordpress.conf
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,124 @@
    ############ WordPress ####################

    location @empty {
    empty_gif;
    }

    # Limit access to avoid brute force attack
    # if you getting error please add this (limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;) to your /etc/nginx/nginx.conf
    # location = /wp-login.php {
    # limit_req zone=one burst=1 nodelay;
    # include fastcgi_params;
    # fastcgi_pass 127.0.0.1:9000;
    #}

    #Deny access to wp-content folders for suspicious files
    location ~* ^/(wp-content)/(.*?)\.(zip|gz|tar|bzip2|7z)\$ {
    deny all;
    }

    location ~ ^/wp-content/uploads/sucuri {
    deny all;
    }

    location ~ ^/wp-content/updraft {
    deny all;
    }

    #Disable execution of scripts other than PHP from your document root
    location ~* .(pl|cgi|py|sh|lua|asp)$ {
    return 444;
    }

    #Disable access to your configuration files and other files that you don’t want to users are able to see
    location ~* /(wp-config.php|readme.html|license.txt|nginx.conf) {
    deny all;
    }

    # Disable wp-config.txt
    location = /wp-config.txt {
    deny all;
    access_log off;
    log_not_found off;
    }

    # Disallow php in upload folder and add webp rewrite
    location /wp-content/uploads/ {
    location ~ \.php$ {
    #Prevent Direct Access Of PHP Files From Web Browsers
    deny all;
    }
    # webp rewrite rules
    location ~ \.(png|jpe?g)$ {
    add_header Vary "Accept-Encoding";
    add_header "Access-Control-Allow-Origin" "*";
    add_header Cache-Control "public, no-transform";
    access_log off;
    log_not_found off;
    expires max;
    try_files $uri $uri =404;
    }
    }

    # nginx block xmlrpc.php requests
    location /xmlrpc.php {
    deny all;
    access_log off;
    log_not_found off;
    return 444;
    }

    # nginx block wpscann on plugins folder
    location ~* ^/wp-content/plugins/.+\.(txt|log|md)$ {
    deny all;
    error_page 403 =404 / ;
    }

    # block access to install.php and upgrade.php
    location ^~ /wp-admin/install.php {
    deny all;
    error_page 403 =404 / ;
    }

    location ^~ /wp-admin/upgrade.php {
    deny all;
    error_page 403 =404 / ;
    }

    # stop user enumeration
    if ($args ~ "^/?author=([0-9]*)"){
    set $rule_0 1$rule_0;
    }

    if ($rule_0 = "1"){
    rewrite ^/$ https://next100years.org.uk/404 permanent;
    }

    # Deny access to any files with a .php extension in the uploads directory
    # Works in sub-directory installs and also in multisite network
    # Keep logging the requests to parse later (or to pass to firewall utilities such as fail2ban)
    location ~* /(?:uploads|files)/.*\.php$ {
    deny all;
    }


    # Stop scann for the follow files on plugins folder
    location ~* ^/wp-content/plugins/.+\.(txt|log|md)$ {
    deny all;
    error_page 403 =404 / ;
    }

    # Stop scann for the follow files on themes folder
    location ~* ^/wp-content/themes/.+\.(txt|log|md)$ {
    deny all;
    error_page 403 =404 / ;
    }


    #This module will allow us to pattern match certain key files and inject random text in the files that
    # is non-destructive / non-invasive and will most importantly alter the md5sum calculated on such files. All transparent to WPScan.
    location ~* ^/(license.txt|wp-includes/(.*)/.+\.(js|css)|wp-admin/(.*)/.+\.(js|css))$ {
    sub_filter_types text/css text/javascript text/plain;
    sub_filter_once on;
    sub_filter ';' '; /* $msec */ ';
    }