Last active
November 10, 2024 22:36
-
-
Save ustoopia/2a54d06ab990597d139d6eb8a327e470 to your computer and use it in GitHub Desktop.
Config to harden Nginx running Wordpress sites
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
############ Config to harden Nginx running Wordpress sites | |
# Paste this in a new file like: /etc/nginx/conf.wp/harden-wordpress.conf | |
# in main/vhost config add: include /etc/nginx/conf.wp/harden-wordpress.conf; | |
# | |
# Restart nginx and voila. This gist is based on: | |
# https://gist.github.com/nfsarmento/57db5abba08b315b67f174cd178bea88 | |
# | |
############ 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 = /robots.txt { | |
allow all; | |
log_not_found off; | |
access_log off; | |
try_files $uri /index.php?$args; | |
} | |
#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 / ; | |
} | |
# 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 / ; | |
} | |
#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; | |
} | |
# Deny access to uploads that aren’t images, videos, music, etc. | |
location ~* ^/wp-content/uploads/.*.(html|htm|shtml|php|js|swf)$ { | |
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; | |
} | |
# 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; | |
} | |
# 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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment