If your bandwidth usage keeps climbing but your own traffic hasn't grown, there's a decent chance someone else is linking straight to your images. Every time their page loads, your server pays for it — not theirs. cPanel has a feature built exactly for this called Hotlink Protection, and most people never turn it on until the bandwidth bill (or the suspension notice) forces the question.
Symptom: Bandwidth Climbing, Images Showing Up on Other Sites
The usual way people find out is one of these:
- WHM or cPanel's bandwidth graph shows a spike with no matching rise in visits to your own pages.
- You spot your product photo or blog image embedded on a forum, a Pinterest-style aggregator, or someone else's WordPress post — and the image is loading directly from your domain.
- AWStats or your raw access logs show thousands of GET requests for a handful of
.jpg/.pngfiles, with referrers pointing to a domain you don't own. - You've already hit a "Bandwidth Limit Exceeded" suspension and, digging through the logs, most of the traffic isn't even for your pages — just your media folder.
Check quickly with grep on the access log:
grep -Ei "\.(jpg|jpeg|png|gif|webp)" access-ssl.log | awk -F'"' '{print $4}' | sort | uniq -c | sort -rn | head -20
If that turns up a wall of external domains you don't recognize, you've got hotlinkers.
Cause: Nothing Stops a Remote Page From Pointing at Your Files
An <img src="https://yourdomain.com/wp-content/uploads/photo.jpg"> tag works from anywhere on the web by default. The browser fetching the image doesn't care whose page it's embedded in — it just requests the file from your server and your server happily serves it, using your CPU, your bandwidth allowance, and (on shared hosting) counting against limits that can get your account suspended. Without an explicit rule telling Apache or Nginx to check where the request came from, there's nothing stopping this.
Fix 1: Enable Hotlink Protection in cPanel
This is the fastest option on shared or reseller hosting:
- Log in to cPanel → go to Security → Hotlink Protection.
- Click Enable.
- Under URLs to allow access, list your own domain and any you actually use (with and without
www, plus any CDN or staging domain you rely on) — one per line. - In Block direct access for the following extensions, list the file types being stolen:
jpg,jpeg,png,gif,bmp,webp,mp4(add or drop types as needed — don't blockcssorjsunless you mean to). - Leave Allow direct requests checked. This matters more than it looks: some browsers, RSS readers, and email clients send no referrer header at all, and without this checked those requests get blocked too, breaking legitimate image loads.
- Set a Redirect the request to the following URL if you want hotlinkers to get a "please don't do this" placeholder image instead of a broken image icon. Otherwise leave it blank for a plain 403.
- Save.
Behind the scenes, cPanel just writes RewriteCond/RewriteRule lines into your domain's .htaccess. You can see them appear at the top of the file after saving.
Fix 2: Manual .htaccess Rule (More Control)
If you want to hand-tune it — say, allow Google's image crawler through, or protect only one folder — add this above any existing RewriteEngine block:
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?yourdomain\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?google\. [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ - [F,NC,L]
The first condition (!^$) is what lets empty-referrer requests through, same as cPanel's "Allow direct requests" checkbox.
Fix 3: VPS Running Nginx
cPanel's toggle only edits Apache config, so if you're serving through Nginx directly (or through LiteSpeed/OpenLiteSpeed with a custom vhost), add this inside the relevant server block or a matching location:
location ~* \.(jpg|jpeg|png|gif|webp)$ {
valid_referers none blocked yourdomain.com *.yourdomain.com;
if ($invalid_referer) {
return 403;
}
}
none covers requests with no referrer at all, and blocked covers referrers stripped by browser privacy settings or proxies. Reload with nginx -t && systemctl reload nginx after editing.
Fix 4: Cloudflare (If You're Proxied Through It)
If your DNS is orange-clouded through Cloudflare, you can block hotlinking at the edge instead of your origin, which saves your server the request entirely:
- Go to Scrape Shield in the Cloudflare dashboard and turn on Hotlink Protection — it's a single toggle and covers the common case.
- For finer control, create a WAF custom rule matching
http.referer contains "otherdomain.com"and action Block, or the inverse (block everything except your own referrer) using a Firewall Rule withnot http.referer contains "yourdomain.com"combined with a file-extension match.
Quick Comparison
| Method | Where it runs | Best for |
|---|---|---|
| cPanel Hotlink Protection | Apache, via .htaccess | Shared/reseller hosting, quick setup |
| Manual .htaccess | Apache | Custom exceptions (crawlers, specific folders) |
| Nginx valid_referers | Nginx/OpenLiteSpeed vhost | VPS sites not using Apache |
| Cloudflare Scrape Shield / WAF | CDN edge | Blocking before it hits your server at all, DDoS-adjacent hotlinking |
Test It
Fake a referrer with curl to confirm the rule works before you trust it:
curl -I -e "https://not-your-domain.com/" https://yourdomain.com/wp-content/uploads/photo.jpg
You should get a 403 Forbidden (or a redirect, if you set one). Then run it again with no -e flag, or with your own domain as the referrer, and confirm you get a normal 200.
Prevention: Don't Let It Creep Back
- Check AWStats or your CDN's analytics monthly for referrer spikes — hotlinking is easy to miss until the bandwidth graph makes it obvious.
- If you run WooCommerce or a photography site, consider serving full-resolution images only to logged-in users or via a signed/expiring URL, and hotlink-block everything else.
- Keep your allow-list current. A common failure mode is enabling hotlink protection, then adding a new CDN or a mobile app backend later and forgetting to whitelist it — which quietly breaks images for legitimate users.
- If someone's scraping content wholesale rather than just embedding an image or two, hotlink protection alone won't stop them — that's a rate-limiting or WAF problem, not a referrer-check problem.
Frequently Asked Questions
Will hotlink protection break my own site?
Not if you list your domain (with and without www) in the allow list and leave "Allow direct requests" enabled. Test with the curl commands above before assuming it's working correctly.
Why are my images still broken on my own site after enabling it?
Usually a missing variant of your domain in the allow list — a subdomain, a staging URL, or an app that loads images without sending a referrer header at all. Check "Allow direct requests" is checked, and add any missing domain.
Does this stop Google Images from indexing my photos?
It can, if Google's crawler request doesn't match your allow list. Add Google's crawler domains to the allowed referrers, or use the manual .htaccess rule above which explicitly whitelists it.
I'm on a VPS with Apache and WHM — does the cPanel toggle work the same way?
Yes, cPanel's Hotlink Protection writes standard Apache mod_rewrite rules into .htaccess regardless of whether you're on shared hosting or a cPanel-managed VPS. It only doesn't apply if you're serving requests through Nginx or LiteSpeed instead of Apache.
Can I hotlink-protect only one folder, like /uploads/?
Yes — place a separate .htaccess file with the rewrite rules inside that specific folder instead of your document root, and the rules will only apply to requests served from there.
