FeaturesWP CloudPricingEE CLIContactMy Account
Features
Team Access & User Permissions
Install
Resources
Community
CLEAR
Tutorials
Nginx
Block wp-login.php bruteforce attack
Topics
On this page
-
- Getting Started
- Git and File-System Layout (non-default setup)
- Version Constraints
- Managing Themes and Plugins (for entire WordPress site)
- Updating Themes and Plugins (for entire WordPress site)
- Adding Composer Support to Your Own Themes and Plugins (for developers)
- Using Composer to Manage Own Theme/Plugin Dependencies (for developers)
-
- Assigning Multiple IP Addresses to Single LAN Card
- Disable IPv6 on Ubuntu 12.04
- dsh – distributed shell
- fdupes – find & replace duplicate files with hardlinks
- GPG Keys Cheatsheet
- Increase "Open Files Limit"
- kill all php, nginx, mysql or any kind of processes
- Passwordless Authentication for SSH
- Screen
- search replace in multiple files useing grep xargs sed
- Setup sftp
- sysctl.conf
- Timezone Sync
- Using Google Public DNS on Ubuntu Server
- Using openssl to match private key, cerificate and CSR
- Configure Postfix to Use Gmail SMTP on Ubuntu
- Logrotate Example for Custom Logs
- PHP 5.5, MySQL, Postfix, Nginx and WordPress on Ubuntu
- Serverdensity
- Upgrade Ubuntu 10.04 to 12.04
- Using find and sed to replace strings in multiple files
- Webmin
-
- .my.cnf – mysql user & password
- Analyse slow-query-log using Anemometer
- Improving MySQL Query Cache
- MySQL Query Profiling
- Reset MySQL root password
- tuning-primer.sh – an alternative for mysqltuner
- Using MariaDB 10
- Install/Upgrade to MySQL 5.6 on Ubuntu 12.04 LTS
- Change WordPress Domain Name
- Character Sets and Collations
- Enable innodb_file_per_table
- Enable Remote Access (Grant)
- Installing Percona Toolkit
- Using tmpfs for temporary folder creation
- YARPP and InnoDB
- Convert MyISAM to InnoDB
- Using tmpfs for mysqldump & mysqlimport
- Convert from INNODB to MYISAM
- Analyse slow-query-log using mysqldumpslow & pt-query-digest
- mysqlcheck with cron to optimize automatically
- Using MySQLTuner to Optimize MySQL configuration
-
-
- Directly connect to PHP-FPM
- Generating core-dump for php5-fpm
- GeoIP
- Having php5 and php7 on same system.
- Install Xdebug and configure it with webgrind
- Installation of PHP Code Review Tools
- memcache
- PHP's Zend Opcache Config & Web Viewer
- Setting Sqlite support with PHP
- Using HHVM with PHP-FPM Fallback
- Using Redis for PHP Sessions on Ubuntu Server
- Installing PhpMyAdmin Quickly
- Moving PHP's session storage to tmpfs
- Install Xdebug and configure it with Netbeans
- Nginx – Enable PHP-FPM Status Page
- PHP-FPM: Socket vs TCP/IP and sysctl tweaking
- APC Cache Optimization & Monitoring Using Web Interface
- Checking if PHP/WordPress can send mails
- Debugging PHP Scripts Using slow_log and more
- Increase file upload size limit in PHP-Nginx
- Increase PHP script execution time with Nginx
-
- Performance Optimization
- Remove Query string of css/js files
- Setup ElasticSearch with ElasticPress
- Using Redis for WordPress Object-Cache
- WooCommerce Window Shopping Caching Technique
- Moving WordPress To New Server (Faster)
- Better wp-cron using linux's crontab
- 404 error- Page not Found!!!
- Debugging WordPress with Nginx
Nginx Settings
Global Settings
Per Site Setting
Protecting other areas
Other Changes
Test
Logs
Simulate Attack
Other Notes
Whitelisting IP addresses
Block wp-login.php bruteforce attack
Last night, a site in our managed-hosting network was under attack.
Following config thwarted the bruteforce attack successfully using Nginx’s Limit Req Module.
Nginx Settings
Global Settings
In /etc/nginx/nginx.conf file under http{..} block, add following
limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
10m is size of zone. 1MB can hold 16000 states. I think this means 16000 unique IP addresses. In case you have way too many sites or very high traffic sites, you may want to increase it to 20MB or 100MB.
1r/s means 1 request per second is allowed. You cannot specify fractions. If you want to slowdown further, means less requests per second try 30r/m which means 30 requests per min, effectively 1 request per 2 second.
Per Site Setting
You can add something like below to server{..} block:
location = /wp-login.php {
limit_req zone=one burst=1 nodelay;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
OR
location ~ \.php$ {
location ~* wp\-login\.php {
limit_req zone=one burst=1 nodelay;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
#other rules
}
nodelay makes sure as soon as request limit exceeds, HTTP status code 503 (Service Unavailable) is returned.
Protecting other areas
On same lines you can protect other area as well. e.g. your contact form.
If you have contact form on every page, then may be you can add location of form’s action handler URL.
Other Changes
In case you want to return 444 (recommended) or any other code use following in http {..} block for global effect or with location {..} block for local-effect:
limit_req_status 444;
You can server custom error page using error_page directive.
Test
Logs
Use following command to monitor logs. Replace 503 with any other error code if you are using limit_req_status
tail -f /var/www/example.com/logs/*.log | egrep "login|503"
If your site is already under attack, you will see lines like below:
2013/08/23 04:17:03 [error] 256554#0: *99927 limiting requests, excess: 1.852 by zone "one", client: 1.2.3.4, server: example.com, request: "GET /wp-login.php HTTP/1.0", host: "exmaple.com"
1.2.3.4 is blocked IP.
Simulate Attack
You can use apache-bench to attack server:
ab -n 100 -c 10 example.com/wp-login.php
Other Notes
Whitelisting IP addresses
For wp-login example in this article you won’t need whitelisting as a real-human has no business to send multiple requests to wp-login.php at any moment.
Still, for some other purpose you may need to whitelist IP addresses.
In /etc/nginx/nginx.conf file under http{..} block, add a map{..} block like below:
map $remote_addr $rt_filtered_ip {
default $binary_remote_addr;
1.2.3.4 "";
4.4.4.4 "";
}
1.2.3.4 and 4.4.4.4 are example of whitelisted IP’s. You can have any number of them. Add every IP on separate line. Make sure you use “” in second column for every IP. rate limit module ignores empty values.
Then you need to use variable $rt_filtered_ip
limit_req_zone $rt_filtered_ip zone=one:10m rate=1r/s;
Above simple method may not work if you want to whitelist a range of IP’s. For which you need to geo module.
geo $rt_filtered_ip {
default $binary_remote_addr;
127.0.0.1 "";
192.168.1.0/24 "";
10.1.0.0/16 "";
::1 "";
2001:0db8::/32 "";
1.2.3.4 ""
}
Important: We haven’t tested geo-module example. So use at your risk.
Amazon Elastic Load Balancer and Forwarding Real-IP Nginx
PREVIOUS
Configuring HTTP/2 Server Push
NEXT
Comments
-
wcat
Stimulate Attack = freudian slip
🙂TY
-
Corrected. I hope I did not offend anybody 😉
-
-
wcat
also
tail -f /var/www/example.com/*.log | egrep "login|503"should be
tail -f /var/www/example.com/logs/*.log | egrep "login|503"-
wcat
Asterisk’s were removed….
-
Added back. Looks like it’s markdown plugin we are using.
By the way, it would not have stripped asterisks if commands were surrounded by backticks (`). Just a guess!
-
-
Thanks for corrections. 🙂
-
-
Excellent, thanks.
-
Chathu
After I added following code to nginx configuration file and reboot the VPS, I got this error.
[emerg] 1577#0: “location” directive is not allowed here in /etc/nginx/nginx.conf:67
Any solution?
Thanks!
-
Look like you added a “location” directive inside the “http” block, while you can only add it inside the “server” block.
-
Chathu
Thank you Anti DDoS and Rahul for your replies. I have an Apache Nginx installation (managed VPS). It uses back end Apache and Nginx for front end. When I navigate to Nginx admin>Configuration, I can’t see “Server” block, instead of that, it has http black. So in this situation how do I fix this issue?
Thanks!
-
-
@Anti DDoS Thanks for answering.
@Chathu Please follow above answer.
-
-
Just want to inform a typo with:
geo $rt_filterd_ip {
it should be:
geo $rt_filtered_ip {
-
Thanks for catching that typo. Corrected it. 🙂
-
-
Luka Kaspar
Thanks for this tip, however I can’t seem to get it working properly… Here’s what I used together with the global setting
location ~ \.php$ { location ~* wp\-login\.php { limit_req zone=one burst=1 nodelay; try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.iniinclude fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/var/run/php5-fpm.sock; } try_files $uri =404; fastcgi_split_path_info ^(.+\.php)(/.+)$; #NOTE: You should have "cgi.fix_pathinfo = 0;" in php.iniinclude fastcgi_params; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/var/run/php5-fpm.sock;}
It seems to have something to do with fastcgi_pass… If I set it to 127.0.0.1:9000 it seems to block, but then my website won’t load…. Any ideas?
Cheers
-
Luka Kaspar
Also, I just tried changing the sockets to 127.0.0.1:9000 in the http://www.conf file and then in the location and still no luck
-
Luka Kaspar
Nevermind, seems like there was some error in my server configuration. Did a fresh install and everything works outside the box. Strange.
Anyway, thanks for this article!
-
@Luka sorry for missing your earlier comment.
Glad to know your issue is solved.
On fresh setup, you can try https://rtcamp.com/easyengine (for wordpress-nginx sites)
-
Luka Kaspar
Yeah I thought of using easyengine but I already did a fresh install on Debian before I noticed you added support for that distro 🙂
Still, used a lot of tips from this website so in the end I came to the same outcome. great tutorials 😉
-
Glad to know that you found tutorials useful. I hope EasyEngine will make your next install “easy”. 🙂
-
-
-
-
Features
- Server Setup & Management
- Site Creation & Management
- Create WP Cloud Sites
- Speed & Caching
- Firewall Protection
- Backups & Recovery
- Logs & Monitoring
- Deployments & Developer Tools
- Team Access & User Permissions
Useful Links
Product
Other Products
Subscribe for curated product updates, tips, and announcements.
"*" indicates required fields
Comments
This field is for validation purposes and should be left unchanged.
Email*
SIGN ME UP
Δ
© rtCamp, since 2009. All rights reserved.