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.
$ 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.
$ sudo vi /etc/apache2/sites-available/000-default.conf
<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.
$ sudo apache2ctl configtest Syntax OK
Related: How to test Apache configuration
$ 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.
$ 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.
$ 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.