Hotlink Protection in .htaccess
Hotlinking occurs when another website embeds your images, videos, or other media files directly on their pages by linking to the files on your server. Every time someone visits their site, your server pays the bandwidth cost for delivering content that benefits someone else. On high-traffic sites, hotlinking can consume significant bandwidth, increase hosting costs, and degrade performance for your actual visitors.
This guide explains what hotlinking is, how to block it using mod_rewrite and the HTTP_REFERER header, how to whitelist your own domains and search engines, and how to serve a placeholder image instead of the original resource.
What Is Hotlinking
When you host an image at https://example.com/images/photo.jpg and display it on your own page, the browser requests the image from your server. This is normal and expected. Hotlinking happens when someone else's website includes your image directly in their HTML:
<img src="https://example.com/images/photo.jpg" alt="Stolen image">
Every visitor to their page triggers a request to your server. You pay for the bandwidth. They get the content for free.
Why Hotlinking Is a Problem
| Impact | Description |
|---|---|
| Bandwidth theft | Your server delivers files for someone else's audience. On shared hosting, this can push you over bandwidth limits and trigger overage charges. |
| Server load | Each hotlinked request consumes CPU, memory, and connection slots on your server, potentially slowing down your own site. |
| Cost increase | If you pay for bandwidth (CDN, cloud hosting, VPS), hotlinking directly increases your bill. |
| Loss of control | Your images appear on sites you have no association with, potentially next to objectionable content. |
| SEO dilution | Search engines may associate your images with the hotlinking site rather than yours. |
Hotlinking is not limited to images. It can affect any publicly accessible file:
- Images (JPEG, PNG, GIF, WebP, SVG)
- Videos (MP4, WebM)
- Audio files (MP3, OGG)
- PDFs and documents
- JavaScript and CSS files (though these are less commonly hotlinked)
How Hotlinking Is Detected
When a browser requests a resource embedded on a page, it sends a Referer header (note the historical misspelling) that indicates which page triggered the request:
GET /images/photo.jpg HTTP/1.1
Host: example.com
Referer: https://other-site.com/their-page.html
The Referer header reveals that the request for your image came from other-site.com, not from your own site. This is the mechanism Apache uses to detect and block hotlinking.
The Referer header is not always present. Some browsers, privacy extensions, and security configurations strip or suppress it. Hotlink protection cannot block requests that arrive without a Referer header. This is by design. Blocking requests without a referer would also block direct visits (someone typing the image URL into their browser), bookmarks, and requests from privacy-conscious users.
RewriteCond HTTP_REFERER Approach
The standard method for blocking hotlinks uses mod_rewrite to check the Referer header and reject requests that come from unauthorized domains.
Basic Hotlink Protection
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|bmp|ico)$ - [F,NC,L]
</IfModule>
Let's break down each line:
RewriteCond %{HTTP_REFERER} !^$
This condition checks that the Referer header is not empty. The ! negates the match, so this condition passes when a referer IS present. Requests without a referer (direct visits, bookmarks, privacy tools) are allowed through.
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
This checks that the referer does not start with your own domain. The ! means "does not match." The pattern https?:// matches both http:// and https://. The (www\.)? makes the www. prefix optional. The [NC] flag makes the match case-insensitive.
When this condition passes, it means the referer is present AND it is not from your domain, which indicates hotlinking.
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|bmp|ico)$ - [F,NC,L]
This matches requests for image files (by extension) and returns a 403 Forbidden response ([F] flag). The - substitution means "do not rewrite the URL." The [L] flag stops further rule processing.
The combined effect: if someone requests an image file and the referer indicates the request came from a site other than yours, the server returns 403 Forbidden instead of the image.
What Users See
| Request Scenario | Result |
|---|---|
Image loaded on https://example.com/gallery | Image served normally |
Image loaded on https://other-site.com/page | 403 Forbidden |
| Image URL typed directly into browser (no referer) | Image served normally |
| Image loaded via bookmark or privacy browser (no referer) | Image served normally |
| Image loaded in email client (usually no referer) | Image served normally |
Protecting Additional File Types
Extend the pattern to cover more file types:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|avif|bmp|ico|mp4|webm|ogg|mp3|wav|pdf)$ - [F,NC,L]
</IfModule>
Be careful when protecting CSS and JavaScript files from hotlinking. If your site uses a CDN or loads resources from a different subdomain, you may accidentally block your own assets. Stick to media files unless you have a specific reason to protect other file types.
Allowing Your Own Domains
Most websites operate across multiple domains or subdomains. Your main site, CDN, staging environment, and development server all need to load your images legitimately. Each domain must be whitelisted with its own RewriteCond.
<IfModule mod_rewrite.c>
RewriteEngine On
# Allow empty referer (direct access, bookmarks, etc.)
RewriteCond %{HTTP_REFERER} !^$
# Allow your main domain
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
# Allow your CDN
RewriteCond %{HTTP_REFERER} !^https?://cdn\.example\.com [NC]
# Allow your staging environment
RewriteCond %{HTTP_REFERER} !^https?://staging\.example\.com [NC]
# Allow a partner or sister site
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?partner-site\.com [NC]
# Block everything else
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|avif)$ - [F,NC,L]
</IfModule>
All RewriteCond directives before a RewriteRule are joined with implicit AND logic. The RewriteRule only fires when all conditions are true. So the rule fires when:
- The referer is NOT empty AND
- The referer is NOT from
example.comAND - The referer is NOT from
cdn.example.comAND - The referer is NOT from
staging.example.comAND - The referer is NOT from
partner-site.com
If the referer matches any of the allowed domains, that condition fails (returns false), the AND chain breaks, and the rule does not fire. The image is served normally.
Common Mistake: Forgetting the www Variant
Wrong approach:
# Only allows example.com, not www.example.com
RewriteCond %{HTTP_REFERER} !^https?://example\.com [NC]
If a visitor accesses your site at www.example.com, the referer will be https://www.example.com/page. This does not match https://example.com, so the condition passes (because ! means "does not match") and the image is blocked on your own site.
Correct approach:
# Allows both example.com and www.example.com
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
The (www\.)? makes www. optional, covering both variants.
Common Mistake: Forgetting HTTP and HTTPS
Wrong approach:
# Only allows https, not http
RewriteCond %{HTTP_REFERER} !^https://(www\.)?example\.com [NC]
If any page on your site is still accessible over HTTP (during migration, for example), images on those pages would be blocked because the referer starts with http:// rather than https://.
Correct approach:
# Allows both http and https
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
The https? pattern matches both http and https.
Allowing Search Engines
Search engine image crawlers (Google Images, Bing Images, etc.) need to access your images to index them and display them in image search results. If you block search engine crawlers, your images will disappear from image search, which can significantly reduce traffic.
Search engine crawlers may send a referer from their own domain (e.g., when recrawling from search results pages), so you should whitelist their domains:
<IfModule mod_rewrite.c>
RewriteEngine On
# Allow empty referer
RewriteCond %{HTTP_REFERER} !^$
# Allow your own domain(s)
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
# Allow Google
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?google\. [NC]
# Allow Bing
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?bing\. [NC]
# Allow DuckDuckGo
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?duckduckgo\. [NC]
# Allow Yahoo
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?yahoo\. [NC]
# Allow Yandex
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?yandex\. [NC]
# Block hotlinking for image files
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|avif)$ - [F,NC,L]
</IfModule>
A few notes on the search engine patterns:
(.+\.)?google\.matchesgoogle.com,www.google.com,images.google.com,google.co.uk, and all other Google subdomains and country-specific TLDs. The trailing dot without a TLD is intentional as it matches any Google domain regardless of the suffix.- The same pattern is used for each search engine to cover subdomains and international variants.
Allowing Social Media Platforms
If you want your images to display correctly when your pages are shared on social media, whitelist the major platforms:
# Allow Facebook/Meta
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?facebook\.com [NC]
# Allow Twitter/X
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?twitter\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?x\.com [NC]
# Allow LinkedIn
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?linkedin\.com [NC]
# Allow Pinterest
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?pinterest\. [NC]
Social media crawlers (like Facebook's Open Graph crawler) often do not send a Referer header when fetching images for link previews. Since the first condition !^$ allows empty referers, these crawlers are usually not affected by hotlink protection. However, when users click through from social media to your site, the subsequent page load sends a referer from the social platform, which is why whitelisting them is still important.
Serving a Placeholder Image
Instead of returning a 403 error (which shows a broken image icon), you can serve a placeholder image that replaces hotlinked images. This approach is more visible and can discourage future hotlinking.
Basic Placeholder
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?google\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?bing\. [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ /images/hotlink-placeholder.png [L,NC]
</IfModule>
The key difference from the blocking approach is the RewriteRule substitution. Instead of - [F] (which returns 403), this rule rewrites the request to /images/hotlink-placeholder.png. The hotlinker's page displays your placeholder image instead of the stolen content.
The placeholder image could say:
- "This image is hosted on example.com"
- "Image hotlinking is not permitted"
- Simply display your logo or website URL
Preventing a Redirect Loop
There is an important subtlety: the placeholder image itself must not be blocked by the hotlink protection rules, otherwise you create an infinite loop (the placeholder request triggers the rule, which rewrites to the placeholder, which triggers the rule again).
The simplest way to prevent this is to ensure the placeholder image does not match the RewriteRule pattern, or add an explicit exclusion:
<IfModule mod_rewrite.c>
RewriteEngine On
# Don't apply hotlink rules to the placeholder image itself
RewriteCond %{REQUEST_URI} !^/images/hotlink-placeholder\.png$ [NC]
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?google\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?bing\. [NC]
RewriteRule \.(jpg|jpeg|png|gif|webp)$ /images/hotlink-placeholder.png [L,NC]
</IfModule>
The additional RewriteCond %{REQUEST_URI} !^/images/hotlink-placeholder\.png$ ensures the rule is never applied to the placeholder file itself.
Placeholder vs Blocking: Which to Choose
| Approach | Pros | Cons |
|---|---|---|
| 403 Forbidden | Minimal server resources. Clean rejection. | Shows a broken image icon. Hotlinker may not notice. |
| Placeholder image | Visible. Discourages hotlinking. Can promote your brand. | Still uses some bandwidth for the placeholder. |
For most sites, the 403 approach is sufficient and simpler. The placeholder approach is more useful when you want to actively discourage hotlinking or promote your site to the hotlinker's audience.
Complete Production Configuration
Here is a comprehensive hotlink protection setup ready for production:
<IfModule mod_rewrite.c>
RewriteEngine On
# === Hotlink Protection ===
# Skip the placeholder image to prevent loops
RewriteCond %{REQUEST_URI} !^/images/hotlink-placeholder\.png$ [NC]
# Allow empty referer (direct access, bookmarks, privacy tools)
RewriteCond %{HTTP_REFERER} !^$
# Allow your own domains
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://cdn\.example\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://staging\.example\.com [NC]
# Allow major search engines
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?google\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?bing\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?duckduckgo\. [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?yahoo\. [NC]
# Allow social media platforms
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?facebook\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?twitter\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?x\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?linkedin\.com [NC]
RewriteCond %{HTTP_REFERER} !^https?://(.+\.)?pinterest\. [NC]
# Serve placeholder for hotlinked images
RewriteRule \.(jpg|jpeg|png|gif|webp|svg|avif)$ /images/hotlink-placeholder.png [L,NC]
# Block hotlinked video and audio files entirely
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.com [NC]
RewriteRule \.(mp4|webm|ogg|mp3|wav)$ - [F,NC,L]
</IfModule>
This configuration serves a placeholder for hotlinked images (where visual feedback is useful) and returns 403 for hotlinked media files (where a placeholder would not make sense). Search engines and social media platforms are whitelisted to preserve SEO and sharing functionality.
Hotlink protection is not foolproof. The Referer header can be spoofed, some browsers and extensions suppress it, and determined hotlinkers can work around it by proxying your images through their own server. Think of hotlink protection as a deterrent that stops casual hotlinking, not as an absolute security boundary. For truly valuable assets, consider watermarking, signed URLs, or token-based access control at the application level.
Hotlink protection is a practical measure that reduces bandwidth waste and discourages unauthorized use of your media assets. The Referer-based approach handles the vast majority of hotlinking cases with minimal configuration. Whitelist your own domains, search engines, and social platforms, choose between blocking or placeholder responses, and your server stops paying for someone else's content delivery.