Skip to content

How to Restrict Access to Media Uploads With .htaccess (Apache 2.4)

Updated October 2026 by Marius: rewritten for Apache 2.4 and tested on Apache 2.4.69. Originally published by Hardeep Asrani in 2014.

There are two reasons to restrict what the web server will serve from your uploads folder. The important one is security: if an attacker manages to upload a PHP file through a vulnerable plugin or form, the server must never run it. The other is control: serving only images and documents and refusing everything else. Both take a small .htaccess file inside the uploads folder, which on WordPress is wp-content/uploads/. Never add these rules to the main .htaccess of your site (see why below).

Block PHP in the uploads folder

This is the rule every WordPress site on Apache should have. WordPress itself never runs PHP from wp-content/uploads, and well-built plugins do not either. Create wp-content/uploads/.htaccess (or add to it if it already exists) with:

# Never run or serve PHP files from the uploads folder
<FilesMatch "\.(?i:php\d*|phtml|phar)$">
    Require all denied
</FilesMatch>Code language: Apache (apache)

Without it, a test file shell.php in uploads ran on my Apache 2.4 test server. With it, the same request returns 403 Forbidden while images, PDFs and every other file type still load. The pattern also covers .phtml, .phar and names like .php7, which some server setups also run as PHP, and (?i:...) makes it ignore upper and lower case. Many security plugins can write this file for you; check that the one you use did.

Serve only the file types you allow

The stricter version refuses every file in the folder except the types you list:

# Serve only these file types from the uploads folder
Require all denied
<FilesMatch "\.(?i:jpe?g|png|gif|webp|avif|pdf)$">
    Require all granted
</FilesMatch>Code language: Apache (apache)

Before you use it, find out what your uploads folder really contains. Page builders, caching plugins and font plugins often write CSS, JavaScript, font and JSON files there (Elementor keeps its generated CSS in wp-content/uploads/elementor/css/, for example), and if their extensions are not on the list, your pages lose their styling. This command, run in your WordPress folder over SSH, lists the file types with a count of each:

find wp-content/uploads -type f | sed 's/.*\.//' | sort | uniq -c | sort -rnCode language: Bash (bash)

Add every extension you need to the list, separated by |, for example css|js|woff2|json|mp4|docx. Then open a few pages of your site and check the browser’s console for 403 errors.

Why the old snippet from this post broke sites

The 2014 version of this post told you to add a rule like this to your .htaccess file:

<Files ~ ".*\..*">
    Order Allow,Deny
    Deny from all
</Files>
<FilesMatch "\.(jpg|jpeg|jpe|gif|png|tif|tiff)$">
    Order Deny,Allow
    Allow from all
</FilesMatch>Code language: Apache (apache)

In the main .htaccess of a site, that blocks every file with a dot in its name except those images, including index.php. On my test server the home page returned 403 Forbidden. Inside the uploads folder it does what it promises, but its list predates WebP and AVIF, which WordPress now accepts as uploads, so those images and every PDF were refused too.

It also uses the Apache 2.2 syntax. Order, Allow and Deny only work on Apache 2.4 when the mod_access_compat module is loaded, and Apache marks them as deprecated. Apache’s documentation also warns against mixing the old directives with the new Require ones, so if your uploads .htaccess already has one style, replace it rather than adding the other.

Other servers

These rules work on Apache and on servers that read .htaccess files. Nginx ignores .htaccess completely. There the same restriction has to go into the server configuration, which on managed hosting usually means asking the host’s support.

1 thought on “How to Restrict Access to Media Uploads With .htaccess (Apache 2.4)”

Leave a Reply

Your email address will not be published. Required fields are marked *