{"id":48049,"date":"2025-01-30T16:15:07","date_gmt":"2025-01-30T16:15:07","guid":{"rendered":"https:\/\/ubuntuhandbook.org\/?p=48049"},"modified":"2025-01-30T16:15:07","modified_gmt":"2025-01-30T16:15:07","slug":"block-ips-nginx-wordpress-login","status":"publish","type":"post","link":"https:\/\/ubuntuhandbook.org\/index.php\/2025\/01\/block-ips-nginx-wordpress-login\/","title":{"rendered":"How to Block IPs in Nginx \/ WordPress Login Page"},"content":{"rendered":"<p><a href=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo.webp\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-thumbnail wp-image-45344\" src=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo-250x250.webp\" alt=\"\" width=\"250\" height=\"250\" srcset=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo-250x250.webp 250w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo-300x300.webp 300w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo-700x700.webp 700w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo-768x768.webp 768w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2024\/01\/nginx-logo.webp 1200w\" sizes=\"auto, (max-width: 250px) 100vw, 250px\" \/><\/a><\/p>\n<p>This is a step by step beginner&#8217;s guide shows how to configure Nginx to block certain IPs or IP range from accessing your website, and block all others while only you (and specified IPs) can access the wordpress login pages.<\/p>\n<p>This site was under attack a few days ago. Someone made tens of thousands of constant requests that slowed down the server response. And, here&#8217;s what I did to manually block attacker&#8217;s IPs and restrict access to the login page.<br \/>\n<!--more--><\/p>\n<p><b>NOTE: For large amount of DDoS attack, it&#8217;s recommended to use 3rd party tools\/services, e.g., <a href=\"https:\/\/github.com\/fail2ban\/fail2ban\" target=\"_blank\" rel=\"noopener\">fail2ban<\/a> or <a href=\"https:\/\/www.cloudflare.com\/ddos\/\" target=\"_blank\" rel=\"noopener\">CloudFlare<\/a>, to mitigate by automatically banning the IPs.<\/b><\/p>\n<h3>Step 1: Find out Attacker&#8217;s IPs<\/h3>\n<p>1. First, connect to your Linux server and run command to edit Nginx configuration file:<\/p>\n<pre>sudo nano \/etc\/nginx\/nginx.conf<\/pre>\n<p>Then, make sure it includes the <code>access_log \/var\/log\/nginx\/access.log;<\/code> line for the access log.<\/p>\n<p>2. If access log was not enabled, then you need to manually add that line and save file (press Ctrl+S then Ctrl+X).<\/p>\n<p>And, apply change by doing configuration check and restarting the service:<\/p>\n<pre>sudo nginx -t<\/pre>\n<pre>sudo systemctl restart nginx.service<\/pre>\n<p>3. Without browsing the log file and counting the IP accesses manually, you may run the single command below in server:<\/p>\n<pre>sudo awk '{print $1}' \/var\/log\/nginx\/access.log | sort | uniq -c | sort -nr |more<\/pre>\n<p>This command will look for the log file (<code>\/var\/log\/nginx\/access.log<\/code>) and print the top IPs and count how many requests they sent.<\/p>\n<p><a href=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips.webp\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-48050\" src=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips-700x477.webp\" alt=\"\" width=\"610\" height=\"416\" srcset=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips-700x477.webp 700w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips-300x204.webp 300w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips-768x523.webp 768w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-accesslog-ips.webp 1150w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/a><\/p>\n<p><b>NOTE: If you use CloudFlare CDN for your website, then Nginx by default does NOT show the real IPs from visitors.<\/b><\/p>\n<p>In the case, you need to create a configuration file for Nginx by running the command below in server:<\/p>\n<pre>sudo nano \/etc\/nginx\/conf.d\/nginx-cloudflare-realip.conf<\/pre>\n<p>Then, add following lines to tell to show the real IPs for visits from CloudFlare:<\/p>\n<pre>set_real_ip_from 173.245.48.0\/20;\r\nset_real_ip_from 103.21.244.0\/22;\r\nset_real_ip_from 103.22.200.0\/22;\r\nset_real_ip_from 103.31.4.0\/22;\r\nset_real_ip_from 141.101.64.0\/18;\r\nset_real_ip_from 108.162.192.0\/18;\r\nset_real_ip_from 190.93.240.0\/20;\r\nset_real_ip_from 188.114.96.0\/20;\r\nset_real_ip_from 197.234.240.0\/22;\r\nset_real_ip_from 198.41.128.0\/17;\r\nset_real_ip_from 162.158.0.0\/15;\r\nset_real_ip_from 104.16.0.0\/13;\r\nset_real_ip_from 104.24.0.0\/14;\r\nset_real_ip_from 172.64.0.0\/13;\r\nset_real_ip_from 172.70.0.0\/16;\r\nset_real_ip_from 131.0.72.0\/22;\r\nset_real_ip_from 2400:cb00::\/32;\r\nset_real_ip_from 2606:4700::\/32;\r\nset_real_ip_from 2803:f800::\/32;\r\nset_real_ip_from 2405:b500::\/32;\r\nset_real_ip_from 2405:8100::\/32;\r\nset_real_ip_from 2a06:98c0::\/29;\r\nset_real_ip_from 2c0f:f248::\/32;\r\n#real_ip_header CF-Connecting-IP;\r\nreal_ip_header X-Forwarded-For;<\/pre>\n<p>Then, press <code>Ctrl+S<\/code> to save file and <code>Ctrl+X<\/code> to exit. Finally, run the 2 commands mentioned above to check configuration and restart service.<\/p>\n<p>NOTE 1: Cloudflare may add\/remove IPs in future! See <a href=\"https:\/\/www.cloudflare.com\/ips\/\" target=\"_blank\" rel=\"noopener\">this page<\/a> for the latest.<br \/>\nNOTE 2: This configuration needs <a href=\"http:\/\/nginx.org\/en\/docs\/http\/ngx_http_realip_module.html\" target=\"_blank\" rel=\"noopener\">ngx_http_realip_module<\/a> model, which is enabled by default in Ubuntu &amp; Debian.<\/p>\n<p><a href=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips.webp\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-48051\" src=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips-700x460.webp\" alt=\"\" width=\"610\" height=\"401\" srcset=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips-700x460.webp 700w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips-300x197.webp 300w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips-768x505.webp 768w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/cloudflare-realips.webp 930w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/a><\/p>\n<h3>Step 2: Block IPs or IP range in Nginx<\/h3>\n<p>Once you found out the attacker&#8217;s IP addresses, run command below to create a configuration file:<\/p>\n<pre>sudo nano \/etc\/nginx\/conf.d\/block.conf<\/pre>\n<p>Then, add similar lines below to tell to block certain IPs and IP range (<b><i>replace IP addresses below with the ones you got in last step<\/i><\/b>) for all the NGINX web servers in this host:<\/p>\n<pre>deny 206.189.129.37;\r\ndeny 143.110.180.216;\r\ndeny 167.172.87.180;\r\ndeny 167.99.77.92;\r\ndeny 152.42.178.38;\r\ndeny 2600:3c03::f03c:91ff:fe69:a353;\r\ndeny 139.59.108.0\/24;\r\ndeny 128.199.0.0\/16;<\/pre>\n<p>Here <code>deny 139.59.108.0\/24;<\/code> means to block IP range from &#8216;139.59.108.0&#8217; to &#8216;139.59.108.255&#8217;. And, <code>128.199.0.0\/16;<\/code> means IP range from &#8216;128.199.0.0&#8217; to &#8216;128.199.255.255&#8217;. You may replace them accordingly for your desired IP range.<\/p>\n<p><a href=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip.webp\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-48052\" src=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip-700x455.webp\" alt=\"\" width=\"610\" height=\"397\" srcset=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip-700x455.webp 700w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip-300x195.webp 300w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip-768x499.webp 768w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-blockip.webp 1193w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/a><\/p>\n<p>For choice, you may use the rules below instead to allow only IP <code>1.2.3.4<\/code> and <code>2.3.4.5<\/code> (replace accordingly) but block all others.<\/p>\n<pre>allow 1.2.3.4;\r\nallow 2.3.4.5;\r\ndeny all;<\/pre>\n<p>When done editing the file, press Ctrl+S to save and Ctrl+X to exit. Finally, check configuration and restart service to apply changes:<\/p>\n<pre>sudo nginx -t<\/pre>\n<pre>sudo systemctl restart nginx.service<\/pre>\n<h3>Step 3: Restrict Access to WordPress Login Page (wp-admin, wp-login.php)<\/h3>\n<p>For wordpress website, it&#8217;s a good choice to block all others from visiting the wp-admin\/wp-login.php page, leaving only you and users from specified IP addresses being able to access.<\/p>\n<p>1. First, connect to the Linux server and run command to edit the Nginx configuration file for your website:<\/p>\n<pre>sudo nano \/etc\/nginx\/sites-available\/wordpress<\/pre>\n<p>In command you need to replace file-name <code>wordpress<\/code> with yours. Use <code>ls \/etc\/nginx\/sites-available<\/code> to list all files in that directory.<\/p>\n<p>2. When files opens, scroll down and add &#8220;<b>location = \/wp-login.php{}<\/b>&#8221; block with similar rules below:<\/p>\n<pre>location = \/wp-login.php {\r\n    allow 1.2.3.4;\r\n    allow 2.3.4.5;\r\n    deny all;\r\n}<\/pre>\n<p>Here replace <code>1.2.3.4<\/code> and <code>2.3.4.5<\/code> with the IPs you want to allow them to access the login page. And, you may add more or remove <code>allow<\/code> lines to add\/remove IPs.<\/p>\n<p><b>NOTE: Both\u00a0&#8220;location = \/wp-login.php {}&#8221; and &#8220;location ~ \/.php$ {}&#8221; (<i>meaning any end with &#8216;.php&#8217;<\/i>) blocks match the wordpress login page URL (wp-login.php), but the former one has higher priority.<\/b><\/p>\n<p>Meaning when visiting <code>wp-login.php<\/code> page, rules under <code>location ~ \/.php$<\/code> will be ignored! In the case, it may try downloading file instead of rendering the web page.<\/p>\n<p>To workaround it, you also need to add the rules under &#8220;<code>location ~ \/.php$ {}<\/code>&#8221; , so it will look like:<\/p>\n<pre>location = \/wp-login.php {\r\n    <b>include snippets\/fastcgi-php.conf;<\/b>\r\n    <b>fastcgi_pass unix:\/run\/php\/php8.4-fpm.sock;<\/b>\r\n    allow 1.2.3.4;\r\n    allow 2.3.4.5;\r\n    deny all;\r\n}<\/pre>\n<p>NOTE: you need to replace <code>include snippets\/fastcgi-php.conf;<\/code> and <code>fastcgi_pass unix:\/run\/php\/php8.4-fpm.sock;<\/code> according to the rules under &#8220;location ~\\.php$ {}&#8221; block.<\/p>\n<p><a href=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin.webp\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-48053\" src=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin-700x460.webp\" alt=\"\" width=\"610\" height=\"401\" srcset=\"https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin-700x460.webp 700w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin-300x197.webp 300w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin-768x505.webp 768w, https:\/\/ubuntuhandbook.org\/wp-content\/uploads\/2025\/01\/nginx-block-wpadmin.webp 930w\" sizes=\"auto, (max-width: 610px) 100vw, 610px\" \/><\/a><\/p>\n<p>When done. Save file (press Ctrl+S, then Ctrl+X), check configuration and restart service to apply changes.<\/p>\n<pre>sudo nginx -t<\/pre>\n<pre>sudo systemctl restart nginx.service<\/pre>\n<p><b>Tips:<\/b> After made changes to <code>location<\/code> blocks, you may need to clear browser cache then verify if it works.<\/p>\n<h3>More about Nginx location blocks<\/h3>\n<p>Nginx configuration has different types of location blocks. They include:<\/p>\n<ul>\n<li><code>location \/abc<\/code> &#8211; prefix match, <em>example.com\/abc<\/em>, <em>example.com\/abcde<\/em>, <em>example.com\/abc\/123<\/em>, <em>example.com\/abc?123<\/em>.<\/li>\n<li><code>location = \/abc<\/code>, exact match, <em>example.com\/abc<\/em>, <em>example.com\/abc?123<\/em>, but NOT for <em>example.com\/abcde<\/em>, <em>example.com\/abc\/<\/em>.<\/li>\n<li><code>location ~ ^\/abc$<\/code>, regex matches <em>example.com\/abc<\/em>, <em>example.com\/abc?123<\/em>, but NOT for <em>example.com\/abcde<\/em>, <em>example.com\/abc\/<\/em>.<\/li>\n<li><code>location ~* ^\/abc$<\/code>, similar to <code>location ~ ^\/abc$<\/code> but case-insensitive. It also matches <em>example.com\/ABC<\/em>.<\/li>\n<li><code>location ^~ \/abc<\/code>, similar to <code>location \/abc<\/code>, but higher priority and no regex.<\/li>\n<\/ul>\n<p>The priority from high to low: <code>location =<\/code> <b>&gt;<\/b> <code>location ^~<\/code> <b>&gt;<\/b> <code>location ~<\/code> = <code>location ~*<\/code> <b>&gt;<\/b> <code>location \/<\/code>.<\/p>","protected":false},"excerpt":{"rendered":"<p>This is a step by step beginner&#8217;s guide shows how to configure Nginx to block certain IPs or IP range from accessing your website, and block all others while only you (and specified IPs) can access the wordpress login pages. This site was under attack a few days ago. Someone made tens of thousands of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":45344,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[2057],"class_list":["post-48049","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-howtos","tag-web"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/posts\/48049","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/comments?post=48049"}],"version-history":[{"count":0,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/posts\/48049\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/media\/45344"}],"wp:attachment":[{"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/media?parent=48049"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/categories?post=48049"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ubuntuhandbook.org\/index.php\/wp-json\/wp\/v2\/tags?post=48049"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}