How to Prevent Image Hotlinking with .htaccess Rules

Hotlinking drains your server bandwidth when other websites embed your images directly. This guide shows you how to block hotlinked images using Apache .htaccess rewrite rules, protecting your hosting resources without affecting legitimate visitors.

What is Hotlinking?

Hotlinking happens when someone embeds your image on their website by pointing directly to your server URL rather than hosting the file themselves.

For example, if another site uses this code:

<img src="https://yoursite.com/images/photo.jpg" />

Your server delivers the image every time their page loads. Multiply that across dozens of sites and high-traffic pages, and you’ll see CPU spikes, bandwidth overages, and slower performance for your actual visitors.

Why Hotlink Protection Matters

Hotlinking creates two problems:

Resource theft. Every hotlinked request consumes your server’s CPU, memory, and bandwidth allocation. On Shared Hosting plans, excessive hotlinking can trigger resource limit warnings or account throttling.

Content misuse. Your images appear on other websites without attribution or permission, often in contexts you didn’t authorize.

Blocking hotlinks stops both issues while still allowing your images to load normally for your own site visitors.

Block Hotlinking with .htaccess

The most reliable method for preventing hotlinking is adding Apache mod_rewrite rules to your .htaccess file. These rules run at the server level before PHP or WordPress even loads, making them efficient and universally compatible.

Basic Hotlink Protection

This code blocks direct access to common image formats from external domains:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yoursite\.com/.*$ [NC]
RewriteRule \.(jpg|jpeg|gif|png|bmp|webp)$ - [F]

Replace yoursite.com with your actual domain.

How it works:

  • RewriteEngine on enables Apache’s rewrite module
  • RewriteCond %{HTTP_REFERER} !^$ allows requests with no referrer (direct browser access)
  • RewriteCond %{HTTP_REFERER} !^https://(www\.)?yoursite\.com/.*$ [NC] allows requests from your own domain
  • RewriteRule \.(jpg|jpeg|gif|png|bmp|webp)$ - [F] returns a 403 Forbidden error for blocked image requests

The [NC] flag makes the domain match case-insensitive. The [F] flag sends an HTTP 403 status code.

Allow Multiple Domains

If you manage multiple sites or want to allow specific partner domains:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yoursite\.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^https://(www\.)?partnerdomain\.com/.*$ [NC]
RewriteCond %{HTTP_REFERER} !^https://(www\.)?anotherdomain\.net/.*$ [NC]
RewriteRule \.(jpg|jpeg|gif|png|bmp|webp)$ - [F]

Add one RewriteCond line for each domain you want to whitelist.

Redirect to a Warning Image

Instead of showing a broken image, redirect hotlinkers to a replacement image explaining the policy:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yoursite\.com/.*$ [NC]
RewriteRule \.(jpg|jpeg|gif|png|bmp|webp)$ https://yoursite.com/images/hotlink-warning.png [R,L]

Create a simple hotlink-warning.png image with text like “This image is hosted at yoursite.com” and upload it to your /images/ directory. The [R,L] flags trigger a redirect and stop processing further rules.

This approach maintains visual consistency on the offending site while making it clear the image belongs to you.

Redirect to a Custom Error Page

For non-image hotlinking attempts (like direct video or PDF access), send users to an HTML page:

RewriteEngine on
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https://(www\.)?yoursite\.com/.*$ [NC]
RewriteRule \.(jpg|jpeg|gif|png|bmp|webp|mp4|pdf)$ https://yoursite.com/restricted.html [R,L]

Where to Add .htaccess Rules

Your .htaccess file lives in your website’s root directory, typically public_html or www.

To edit via cPanel File Manager:

  1. Log into cPanel.
  2. Open File Manager under the Files section
  3. Navigate to your site’s root directory
  4. Right-click .htaccess and select Edit
  5. Add the rewrite rules at the top of the file, before any existing WordPress or application rules
  6. Save changes

To edit via SSH:

nano /home/username/public_html/.htaccess

Add the rules, then save with Ctrl+O and exit with Ctrl+X.

Directory-Specific Protection

To protect only certain directories (like /wp-content/uploads/ for WordPress sites), create or edit the .htaccess file in that specific folder:

nano /home/username/public_html/wp-content/uploads/.htaccess

This narrows protection to uploaded media files without affecting theme images or other assets.

Testing Your Configuration

After adding rules, verify they work:

  1. Test from your own site. Images should load normally when viewing your pages
  2. Test direct browser access. Navigate to an image URL directly (like https://yoursite.com/images/photo.jpg). This should still work because the referrer is empty
  3. Test external embedding. Create a test HTML file on another domain with an <img> tag pointing to your image. The image should either break (with 403 rules) or show your replacement image (with redirect rules)

Check your Apache error logs for any issues. Blocked requests appear with 403 status codes.

Performance Impact

Hotlink protection rules execute before PHP, so they add minimal overhead. On WordPress Hosting or VPS plans with thousands of images, you’ll actually improve performance by reducing unauthorized bandwidth consumption.

If you notice any slowdown, confirm mod_rewrite is enabled. On InMotion VPS and Dedicated Servers, this module loads by default. On other hosting environments, contact Support if rewrites aren’t processing.

When to Use Hotlink Protection

Implement these rules if:

  • Your bandwidth usage suddenly spikes without traffic increases
  • Server monitoring shows high I/O for the /images/ or /uploads/ directory
  • You discover your images embedded on scraper sites or content farms
  • You’re approaching bandwidth limits on Shared Hosting

Skip hotlink protection if:

  • Your images are meant to be shared (infographics, charts, public resources)
  • You use a CDN that handles delivery separately (the CDN manages this at the edge)
  • Your site receives minimal traffic and bandwidth isn’t a concern

For high-traffic sites or ecommerce stores where image delivery affects performance, hotlink protection is a straightforward way to reclaim server resources without impacting your actual customers.

Share this Article
Carrie Smaha
Carrie Smaha Senior Manager Marketing Operations

Carrie Smaha is a Senior Marketing Operations leader with over 20 years of experience in digital strategy, web development, and IT project management. She specializes in go-to-market programs and SaaS solutions for WordPress and VPS Hosting, working closely with technical teams and customers to deliver high-performance, scalable platforms. At InMotion Hosting, she drives product marketing initiatives that blend strategic insight with technical depth.

More Articles by Carrie

8 thoughts on “How to Prevent Image Hotlinking with .htaccess Rules

  1. I keep clicking the enable Hotlink Protection Button and then I get a green message saying it was enabled but when I go back to the Hotlink Protection page it says that Hotlink Protection is disabled. I’ve refreshed my page several times and it still shows the same way. Is this a glitch on the cpanel? 

  2. hi , im building a website based on offering free downloads to a ZIP , RAR files the question is can i use the same method with such files with such files with this kind of accessabily ? 

    in another way … i want visitors to be able to downlad the file from my site , but i dont want them to use that downloading link in other places outside my site .. or at least prevent them from consuming my bandwidth 

    1. In principal, this should work the same as with images. You may want to try out the steps in the section on protecting and redirecting from a certain page. cPanel has a built-in tool to help with this.

  3. Hello Scott,

    am just trying to enable image hotlinking through htaccess I tried too many times but it won’t work

    here is my file:

     

    ###Close Directory Listening
    Options -Indexes

    ###Redirecting non-www to www
    RewriteEngine on
    RewriteCond %{HTTP_HOST} ^eddiesmarket\.net [NC]
    RewriteRule ^(.*)$ https://www.eddiesmarket.net/$1 [L,R=301,NC]

    ### Removing Extensions (.html)
    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond %{REQUEST_FILENAME}\.html -f
    RewriteRule ^(.*)$ $1.html

    ###

    ### Caching
    <FilesMatch “\.(ico|pdf|jpg|jpeg|png|gif|html|htm|xml|txt|xsl)$”>
    Header set Cache-Control “max-age=31536050”
    </FilesMatch>

    ### Redirect 404 & 403 to the Homepage
    ErrorDocument 404 https://www.eddiesmarket.net
    ErrorDocument 403 https://www.eddiesmarket.net

    ### Disable Image Hotlinking
    RewriteEngine on
    RewriteCond %{HTTP_REFERER} !^$
    RewriteCond %{HTTP_REFERER} !^https://(www\.)?eddiesmarket.net/.*$ [NC]
    RewriteRule \.(jpg|jpeg|gif|png|bmp)$ https://www.eddiesmarket.net/restricted.html [R,L]

    ###Compressing G-Zip
    <IfModule mod_deflate.c>

            <IfModule mod_setenvif.c>
                    <IfModule mod_headers.c>
                            SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
                            RequestHeader append Accept-Encoding “gzip,deflate” env=HAVE_Accept-Encoding
                    </IfModule>
            </IfModule>

            # Compress all output labeled with one of the following MIME-types
            # (for Apache versions below 2.3.7, you don’t need to enable `mod_filter`
            #    and can remove the `<IfModule mod_filter.c>` and `</IfModule>` lines
            #    as `AddOutputFilterByType` is still in the core directives).
            <IfModule mod_filter.c>
                AddOutputFilterByType DEFLATE application/atom+xml \
                  application/javascript \
                  application/json \
                  application/rss+xml \
                  application/vnd.ms-fontobject \
                  application/x-font-ttf \
                  application/x-web-app-manifest+json \
                  application/xhtml+xml \
                  application/xml \
                  font/opentype \
                  image/svg+xml \
                  image/x-icon \
                  text/css \
                  text/html \
                  text/plain \
                  text/x-component \
                  text/xml
            </IfModule>

    </IfModule>

    ### Set Expires Headers
    <IfModule mod_expires.c>
            ExpiresActive on
            ExpiresDefault                                    “access plus 1 month”

        # CSS
            ExpiresByType text/css                            “access plus 1 year”

        # Data interchange
            ExpiresByType application/json                    “access plus 0 seconds”
            ExpiresByType application/xml                     “access plus 0 seconds”
            ExpiresByType text/xml                            “access plus 0 seconds”

        # Favicon (cannot be renamed!)
            ExpiresByType image/x-icon                        “access plus 1 week”

        # HTML components (HTCs)
            ExpiresByType text/x-component                    “access plus 1 month”

        # HTML
            ExpiresByType text/html                           “access plus 0 seconds”

        # JavaScript
            ExpiresByType application/javascript              “access plus 1 year”

        # Manifest files
            ExpiresByType application/x-web-app-manifest+json “access plus 0 seconds”
            ExpiresByType text/cache-manifest                 “access plus 0 seconds”

        # Media
            ExpiresByType audio/ogg                           “access plus 1 month”
            ExpiresByType image/gif                           “access plus 1 month”
            ExpiresByType image/jpeg                          “access plus 1 month”
            ExpiresByType image/png                           “access plus 1 month”
            ExpiresByType video/mp4                           “access plus 1 month”
            ExpiresByType video/ogg                           “access plus 1 month”
            ExpiresByType video/webm                          “access plus 1 month”

        # Web feeds
            ExpiresByType application/atom+xml                “access plus 1 hour”
            ExpiresByType application/rss+xml                 “access plus 1 hour”

        # Web fonts
            ExpiresByType application/font-woff2              “access plus 1 month”
            ExpiresByType application/font-woff               “access plus 1 month”
            ExpiresByType application/vnd.ms-fontobject       “access plus 1 month”
            ExpiresByType application/x-font-ttf              “access plus 1 month”
            ExpiresByType font/opentype                       “access plus 1 month”
            ExpiresByType image/svg+xml                       “access plus 1 month”
    </IfModule>

    ### Turn E-tags off
    <IfModule mod_headers.c>
            Header unset ETag
    </IfModule>
    FileETag None

    THANK YOU

    1. Hello Fadi,

      Your best bet is probably to clear all of the code that you added in .htaccess for hotlink protection and then follow the article’s suggestions using the cPanel to set your hotlink protection. Check out this video for further assistance on its use.

      If you have any further questions or comments, please let us know.

      Regards,
      Arnel C.

  4. Hi. You show an example of how to redirect to specific page above in the article.

    But you do not show how to link to a graphic which would then appear in place of the graphic that the hot linker is trying to link to.

    I know this is possible as I used to do this but have not done so for many years and cannot remember the correct syntax for the Rewrite rule line.

    hope you can help

    Vicky

    1. Hello Vicky,

      In that case, the syntax is very similar:

      RewriteEngine on
      RewriteCond %{HTTP_REFERER} !^https://(.+\.)?example\.com/ [NC]
      RewriteCond %{HTTP_REFERER} !^$
      RewriteRule .*\.(jpe?g|gif|bmp|png)$ https://site-where-image-lives.com/image.gif [L]

      One important thing to note is that the ‘replacement image’ cannot be on a folder that is protected by the hotlinking. Use of an image site such as imgur.com is recommended.

      Kindest Regards,
      Scott M

Comments are closed.