I’m looking to provide some Caddy examples for the WordPress support article Brute Force Attacks that presently has examples for Apache, NginX and IIS. More details in the next post.
If you decide to lock down wp-login.php or wp-admin, you may find you get a 404 or 401 error when accessing those pages. To avoid that, you will need to add the following to your .htaccess file.
ErrorDocument 401 default
You can have the 401 point to 401.html, but the point is to aim it at not WordPress.
For Nginx you can use the error_page directive but must supply an absolute url.
error_page 401 http://example.com/forbidden.html;
On IIS web servers you can use the httpErrors element in your web.config, set errorMode="custom":
# Trigger errors for certain paths
error /wp-login.php "Unauthorized" 401
error /wp-admin* "Unauthorized" 401
# Handle the error by serving an HTML page
handle_errors {
rewrite * /401.html
file_server
}
If my Caddy approach is incorrect here, please let me know. If not, I’ll raise a query in the WP forum just to see if WP is now trapping errors, which may mean this section of the documentation is out of date.
This is saying “if you enable any of the below methods, then be aware of this”. That in of itself isn’t a way to “protect your server”. That’s just throwing an error all the time which isn’t useful It’s also specific to Apache, due to the way it deals with errors. Not needed for Caddy.
This is easy, just use basicauth with a path matcher.
Also easy, remote_ip matcher paired with respond or error or abort.
This would involve a header matcher on the Referer header, paired with respond or error or abort.
I’m not so sure about this Examples were also provided for NginX and IIS.
I’m interpreting this in the following manner now. A WP web designer has completed building a website for a client. They adopt a ‘belts and braces’ approach and lock down the site by preventing access to the WP admin area. Rather than throwing up a 400 series error, they choose to direct requests to the admin area to another page.
What’s not clear to me is the Caddy code that allows me to achieve this. For instance, I can force a 401 error using the following code:
That’s just because of they way they handle cascading errors. It would be the equivalent of using the error handler then using handle_errors to render the error. But if you use respond or abort, that’s not necessary.
My understanding is that they just intend to block access to the admin to some users by doing selective blocking. The point of this is that /wp-login.php is ripe for bots to hammer with requests to try to brute force password attempts, which can also make your server use a ton of extra CPU because password hashing is very slow/costly to compute on purpose. It’s not really useful to block it for everyone, cause that means locking yourself out too.
If Caddy is behind a proxy, then you need forwarded. If it’s not, then you don’t. Not enough context there to really say much else.
You understand that remote_ip looks at the IP address on the incoming TCP connection? If the request was proxied, then that IP address would be the one from the proxy rather than the actual client.
I think I understand. The @block matcher is in Caddyfile for the upstream Caddy webserver. The @split matcher is in the Caddyfile on my frontend Caddy RP.
I think I’m out of my depth with this one. Headers are still a bit of a mystery to me. I could do with a little extra help here please I’m guessing it will be easier to translate the NginX example than either the Apache or IIS examples provided in the article.