How to prevent hotlinking in Apache

Hotlinking lets another site embed your images directly from your server, which spends your bandwidth and cache capacity without sending readers through your pages. Blocking those cross-site requests keeps the origin focused on visitors who actually loaded your site and makes sudden referral spikes less likely to turn into a static-asset drain.

Apache can make that decision from the request's Referer header before the asset is served. In the flow below, mod_rewrite checks whether the request came from one of your own approved hostnames and returns 403 Forbidden when a different site tries to embed the file.

The Referer header is optional, and modern browser referrer policies often reduce it to only the origin or remove it entirely, so hotlink protection is best treated as traffic control rather than hard access control. The example keeps direct requests working by allowing an empty Referer, prefers a virtual host or include file over .htaccess for performance, and uses the Debian or Ubuntu packaging layout for commands while calling out the common httpd differences where they matter.

Steps to prevent hotlinking in Apache:

  1. Enable mod_rewrite if your packaged Apache build does not already load it.
    $ sudo a2enmod rewrite
    Enabling module rewrite.
    To activate the new configuration, you need to run:
      service apache2 restart

    The a2enmod helper is the standard module toggle on Debian and Ubuntu systems. On RHEL-family systems, mod_rewrite is usually already available, and you can verify it with sudo httpd -M | grep rewrite.

    You can ignore the helper's restart hint until after the new hotlink rules pass a syntax test.

  2. Open the Apache virtual host file or include file that serves the directory containing the assets to protect.
    $ sudo vi /etc/apache2/sites-available/000-default.conf
  3. Add a directory-scoped rewrite block that allows your own domains and denies foreign referers for the extensions you want to protect.
    <Directory "/var/www/html/images">
        RewriteEngine On
     
        RewriteCond %{HTTP_REFERER} !^$
        RewriteCond %{HTTP_REFERER} !^https?://(www\.)?host\.example\.net(/|$) [NC]
        RewriteCond %{HTTP_REFERER} !^https?://(www\.)?files\.example\.net(/|$) [NC]
     
        RewriteRule \.(?:avif|gif|jpe?g|png|webp)$ - [F,NC,L]
    </Directory>

    If you only have .htaccess access, use the same rules without the <Directory> wrapper and make sure the parent configuration allows at least AllowOverride FileInfo for that path. Apache's current docs still prefer the main server configuration when you have access to it, because distributed config files add extra filesystem checks and per-request regex work.

    Keep the allowed-domain regex strict. Escaped dots and the ( /|$ ) boundary stop look-alike hosts such as host.example.net.evil.tld from matching as approved referers.

    The RewriteCond %{HTTP_REFERER} !^$ line keeps direct requests working when the browser sends no referer. Remove that line only if you intentionally want blank-referer requests blocked too.

  4. Save the configuration file.
  5. Validate the Apache configuration syntax.
    $ sudo apache2ctl configtest
    Syntax OK
  6. Reload the Apache service so the new rules take effect without dropping active connections.
    $ sudo systemctl reload apache2

    When systemd is not managing the service, use sudo apachectl -k graceful or sudo httpd -k graceful instead. On RHEL-family systems, the unit name is commonly httpd.

  7. Send a test request with an approved Referer header and confirm the file still returns 200 OK.
    $ curl -I -sS -e https://host.example.net/ http://host.example.net/images/example.jpg
    HTTP/1.1 200 OK
    Server: Apache/2.4.58 (Ubuntu)
    Content-Length: 12
    Content-Type: image/jpeg

    Replace /images/example.jpg with a real file path that exists on the server.

  8. Send the same request with an unapproved Referer header and confirm Apache returns 403 Forbidden.
    $ curl -I -sS -e https://othersite.example/ http://host.example.net/images/example.jpg
    HTTP/1.1 403 Forbidden
    Server: Apache/2.4.58 (Ubuntu)
    Content-Type: text/html; charset=iso-8859-1

    Browser tests can be misleading due to cache and referrer policy; a curl request with --referer shows the server-side decision clearly.