Hotlink Protection: Preventing Image Bandwidth Theft

If your host's bandwidth runs out for no reason, other sites are probably hotlinking your images. Here you'll learn how to stop it, without breaking social media previews.

6 min Updated 10 Oct 2026

You look at your monthly bandwidth and see it's been used three times more than last month. Your site traffic hasn't increased, there's no attack in the logs, but your image files are being served from your server for other sites. This is exactly what hotlink protection was built for: preventing other sites from loading your images directly on their pages and eating up your bandwidth.

Before doing anything, you need to make sure the problem is really hotlinking and not something else. A quick way: in the server access log, look for requests whose Referer is not your own domain.

grep -i "\.jpg\|\.png\|\.webp" /var/log/nginx/access.log | awk '{print $11}' | sort | uniq -c | sort -rn | head -20

If foreign domains were at the top of the list, the problem is confirmed. If it was only your own domain and search engines, you need to look elsewhere; for example, scraping bots or a layer 7 DDoS attack.

Why hotlink protection differs on Apache and Nginx

On Apache, the main tool is the .htaccess file. On Nginx, this is done in the location block and .htaccess is not read at all. If you're on Linux shared hosting, you're almost always dealing with Apache or LiteSpeed and .htaccess works. On a dedicated server with Nginx, you have to edit the config directly.

On Apache with htaccess

Put this block in the site root or the images folder:

RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?google\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?bing\. [NC]
RewriteRule \.(jpe?g|png|gif|webp|svg)$ - [F,NC,L]

The first line disables the condition for requests without a Referer. This is important because some users turn off Referer in their browser, and if you remove that line, images won't load for them. The following lines exclude your own domain and search engines. The last line blocks the rest with a 403 Forbidden code.

If you're on shared hosting and aren't sure which .htaccess directives are enabled on your plan, the complete reference of htaccess directives for Linux hosting has a detailed list of supported modules.

On Nginx

location ~* \.(jpe?g|png|gif|webp|svg)$ {
    valid_referers none blocked server_names
                   *.example.com
                   *.google.* *.bing.*;
    if ($invalid_referer) {
        return 403;
    }
}

The valid_referers directive covers several cases at once: none for requests without a Referer, blocked for a malformed Referer, and server_names for domains defined in the config. After every change, run nginx -t and then systemctl reload nginx. If nginx -t throws an error and you don't reload, your site stays up with the old config and you'll think the changes weren't applied.

The side effect that catches everyone off guard: social media previews

This is where many people run into trouble. When someone sends a link to your article on Telegram, WhatsApp, or LinkedIn, that platform's server fetches the featured image (og:image) from your site. The Referer of this request is either empty or the platform's own domain. If you've removed none in Nginx or removed the !^$ line in Apache, that request gets rejected with a 403 and your link is displayed without a preview image.

The symptom is this: a user says "I sent your link but it had no image." You see the image in your own browser because you have a Referer. This difference is exactly what makes diagnosis hard.

The solution: exclude known preview domains. For Apache:

RewriteCond %{HTTP_REFERER} !^https?://([^.]+\.)?(facebook|telegram|whatsapp|linkedin|twitter|x)\. [NC]

And for Nginx, add them to the valid_referers list. If the number of platforms grows and maintaining the list becomes hard, another option is to return a small placeholder image instead of a 403:

RewriteRule \.(jpe?g|png|gif|webp)$ /images/blocked.webp [R=302,L]

This method uses less bandwidth than the original image while not breaking the attacker's page. But it has a cost: every hotlink request still gets a TCP connection and an HTTP response. If the volume of foreign requests is very high, the 403 is lighter since it has no response body.

This is where they go wrong

The most common mistake I see in support tickets is that the site admin locks the entire uploads folder, then complains that "the site's PDF files and videos won't open." The reason is that they applied the RewriteRule pattern to all extensions, not just images. If you have a video or PDF that loads from your own domain, there's no problem, but if the video player uses a separate CDN, that CDN is also seen as a foreign domain and the file gets blocked.

The sign is this: everything is fine in your own browser, but users say the video won't play. In the browser's Network tab, you see a 403 response on the .mp4 file and the Referer is that CDN. The solution: add the CDN domain to the exclusion list too.

Comparison of methods

MethodAdvantageCost
403 with htaccessLightweight, no response bodyBreaks social media previews if none is removed
Redirect to placeholder imageDoesn't break the attacker's page, sends an indirect messageStill consumes bandwidth
URL signing with tokenMost precise control, suitable for CDNRequires changing application code and managing token expiry
Watermark on imagesPreserves brand valueDoesn't reduce bandwidth, only lessens the impact of theft

If you just want to save your bandwidth, I'd choose the 403 with htaccess. If your images have commercial value and you want to make sure no one can get even a single intact copy, URL signing with a token is the only real way, but you have to accept its implementation cost.

What to check after enabling

  1. Put an image from your site on a hotlink test site and see if it gets a 403.
  2. Send the same link on Telegram and make sure the preview has an image.
  3. Check in Search Console that Googlebot is indexing the images.
  4. Look at the server log 24 hours later and see how much bandwidth usage has dropped.

For the third step, if you're not sure which IPs Googlebot comes from, DNS and network lookup comes in handy. And if you want to monitor bandwidth usage more precisely, free webmaster tools provide good analytical reports.

A practical note: if your site is on shared hosting and your image traffic is high, your bandwidth may stay high even after enabling hotlink protection, because scraping bots send fake Referers. In that case, you should consider migrating to a dedicated server or using a CDN. For small and medium sites, Linux hosting with full .htaccess support is enough and you don't need to change your infrastructure.

If your site doesn't come up with a 500 error after enabling, you probably have a syntax error in .htaccess. Restore the file to its previous state via FTP and test again with a smaller block. To learn more directives, ServerNet's documentation and knowledge base is a good reference.

Frequently asked questions

Does hotlink protection have a negative effect on SEO?

If you exclude search engines, no. Googlebot requests images with its own Referer, and if Google's domain is in the allowed list, images will still be indexed. The problem arises when you block all requests without a Referer; in that case, some crawlers may not be able to see the images.

Why did link previews break on Telegram and WhatsApp after enabling?

Because these platforms' servers request the featured image with an empty Referer or their own domain, and they're not in your allowed list. Add the domains telegram.org, whatsapp.com, facebook.com, and linkedin.com to the exclusion list so the preview comes back.

Can I enable hotlink protection for just one specific folder?

Yes. Put the .htaccess file inside that folder, not in the site root. .htaccess directives are applied recursively to subfolders too, so if you only want to protect the images folder, place the file there and remove it from the root.

What's the difference between hotlink protection and rate limiting?

Hotlink protection decides based on the Referer, meaning it checks the source of the request. Rate limiting works based on the number of requests in a time window and doesn't care about the Referer. The two are complementary: the former prevents bandwidth theft, the latter prevents volumetric attacks.

Was this page helpful?