One of the big problems for Cloudflare users is that hackers may find a way to connect directly to your server’s IP address, instead of using the domain name. This would bypass Cloudflare and the protections it offers. Though the issue may affect any website, it is especially common on shared hosting, where website administrators often lack the capability to restrict access using server configuration files or IP tables.

Note: This post was updated on November, 2021 to reflect a new Cloudflare product called Transform Rules. The original post with a similar solution, but using Cloudflare Workers instead, is available here. Transform Rules are available for free, while Cloudflare Workers are available for a monthly fee plus eventual usage fees. You may prefer to use Cloudflare Workers, though, if you have already used up all Transform Rules available on your plan.

Here’s a solution involving Transform Rules, a few .htaccess directives, and a Cloudflare Firewall Rule.

With a very simple Transform Rule, we can add a request header that Cloudflare will send from its edge to your origin, and therefore won’t be visible to site visitors. The word “edge” refers to any of Cloudflare’s over 200 datacenters, and “origin” to the server at the hosting provider where your website is located.

As long as the site admin keeps header name and value as a secret, any request not coming through Cloudflare will not have such header, therefore triggering a rewrite condition at the origin server. That will redirect the request back to, well, Cloudflare — where the Firewall Rule will block it.

The Transform Rule

There are three types of Transform Rules: URL Rewrite, HTTP Request Header Modification, and HTTP Response Header Modification. For this solution, we need to create a single HTTP Request Header Modification.

Go to your Cloudflare Dashboard under Rules, and choose Transform Rules. Then click on Create Transform Rule, and Modify Request Header.

First, give it a name.

Then set the condition that will trigger the rule. In our case, we want the header to be added to all requests, so a matching condition could be

Hostname contains example.com

Then you click on Set Static, and fill up the name and value fields.

The header name and value could be anything permissible under Apache’s specifications. But you should refrain from using non-alphanumeric characters, other than perhaps a dash or an underscore, as they may lead to parsing issues somewhere down the processing pipeline.

To confirm the Transform Rule is working properly and sending the specified header you set on Cloudflare, you can add an .htaccess directive to make your origin server return that request headers back as a response header. So if you name your header “Secret-Header”, you can try adding this directive to your .htaccess file:

Header echo Secret-Header

The above .htaccess directive takes no value, only the name of the header.

You can verify the presence of the header and value using your browser’s Developers Tools or similar web page inspection feature.

Once you are satisfied that the Worker is doing its job correctly, you should rename the header, and add the directives to your .htaccess file.

.htaccess

Place the following directives at the top of the.htaccess file.

# Route visitors not coming from Cloudflare to, well, Cloudflare
<IfModule mod_rewrite.c>
   RewriteEngine On
   RewriteBase /
   # Both the header and the value should be kept secret
   RewriteCond "%{HTTP:Secret-Header}" "!SeCrEt-k3y"
   # Uncomment and edit w/ IP of origin to allow services such as certs, cron, Softaculous etc
   # RewriteCond "%{REMOTE_HOST}" "!^xxx\.xxx\.xxx\.xxx$"
   RewriteRule .* "accessdenied.php" [R,L]
</IfModule>

These directives check every request to see if it comes with a request header named “Secret-Header” and if its value contains the string “SeCrEt-k3y”.

Requests coming from Cloudflare will have the proper header and key, and therefore will not be redirected.

But requests coming directly to the server, bypassing Cloudflare, will not have the header, or not have the key, and will be redirected (with a 302 HTTP status code) to a non-existing file. You can call this file anything. It is named here accessdenied.php.

To verify that the .htaccess is working properly and is actively blocking attempts at reaching your site via IP address, you can edit and run the following Curl command in your command line terminal:

# Replace example.com/1.2.3.4 with your domain and its IP address
curl -svo /dev/null https://example.com --connect-to ::1.2.3.4

The response may contain lots of information on the SSL negotiation, but should also include the following lines, confirming the redirect to the accessdenied.php URL:

< HTTP/2 302
< location: https://example.com/accessdenied.php

Firewall Rule

The name accessdenied.php points to a fictitious, non-existing file. You need to create a Firewall Rule so that Cloudflare blocks it should the bot follow the redirect set by the .htaccess directive above (not all bots follow redirects):

(http.request.uri.path eq "/accessdenied.php")

The Firewall Rule action should be set to Block.

The reason we prefer to redirect these requests to Cloudflare instead of blocking them at the origin is because a redirect consumes less bandwidth and CPU than a 403 error page. We could rewrite the 403 error page down to a few bytes, but we prefer to keep the site functional for legit visitors, and that includes meaningful error pages whenever they face one.

Blocking intruders at Cloudflare also sends the right signal to probing hackers, that your site has the right configuration in place.

One consequence of this approach is that if you monitor your origin server logs, you’ll find it may contain both regular 302s as well as 302s for the URLs the occasional bot may be trying to reach.

The Cloudflare Firewall Events log will then have the entries for the blocks executed for URL "/accessdenied.php".

Legit Bots, Cronjobs, Etc

After implementing this solution, you may find that there are 302s on your server log that have no match on the Firewall Events log. This is because bots may be programmed not to follow redirects.

Also, it’s important to note that legit bots may be accessing directly your site to provide services such as cronjobs, certificate renewals etc. For these situations, there’s a bypass rule on the .htaccess directives above. You just need to uncomment and edit it to include the service’s own IP address.

Cost Issues

Cloudflare Transform Rules is included in all plans, including the Free Plan. The number of Transform Rules allowed per domain depends on the plan level. The Free Plan includes 2 Transform Rules.

Comments

Please send any comments as replies to the tweet below. Click on the date of the tweet to open it on Twitter.