How to Set Up Password Protection for a Directory in Apache

How to set up password protection for a directory

How to set up password protection for a directory

Every staging site I’ve ever built eventually needs a quick way to keep it out of casual view — before there’s a real login system, before it’s ready for the public, sometimes just to keep search engines from indexing a half-finished page. Apache’s built-in Basic Authentication, backed by mod_authn_file and htpasswd, has been my go-to for this since I don’t need to write a single line of application code to set it up.

Here’s exactly how I configure it, plus a stronger alternative when I want it.

How Apache Basic Authentication Works

When a directory is protected, Apache responds to unauthenticated requests with a 401 Unauthorized and a WWW-Authenticate header. The browser prompts for a username and password, then re-sends it (base64-encoded, not encrypted) with each subsequent request — which is exactly why I never do this without HTTPS.

Prerequisites

sudo apt install apache2-utils      # Debian/Ubuntu
sudo dnf install httpd-tools         # RHEL/CentOS

Step 1: Create a Password File

I always create .htpasswd outside the web-servable document root so it can never be downloaded directly:

sudo htpasswd -c /etc/apache2/.htpasswd ahmad

That prompts for a password. The -c flag creates a new file — I drop it when adding more users to an existing file:

sudo htpasswd /etc/apache2/.htpasswd another_user

I check the file (hashed, never plaintext):

cat /etc/apache2/.htpasswd
ahmad:$apr1$eS3f8sd2$K9z...hashedvalue

Step 2: Configure Apache to Require Authentication

Option A: Inside the Virtual Host (my preference)

<Directory /var/www/html/admin>
    AuthType Basic
    AuthName "Restricted Area"
    AuthUserFile /etc/apache2/.htpasswd
    Require valid-user
</Directory>

I reload Apache:

sudo apachectl configtest
sudo systemctl reload apache2

Option B: Using .htaccess

When I don’t have access to the main config, I place this in a .htaccess file inside the directory:

AuthType Basic
AuthName "Restricted Area"
AuthUserFile /etc/apache2/.htpasswd
Require valid-user

This only works if AllowOverride AuthConfig (or All) is set on the parent directory:

<Directory /var/www/html/admin>
    AllowOverride AuthConfig
</Directory>

.htaccess is convenient, but I prefer the virtual host method when I have server config access, since Apache re-reads .htaccess on every request.

Step 3: Test It

curl -I http://example.com/admin/

I expect HTTP/1.1 401 Unauthorized, then test with credentials:

curl -I -u ahmad:yourpassword http://example.com/admin/

I expect HTTP/1.1 200 OK.

Restricting Access to Specific Users

If I want only certain named users, not anyone in the password file:

Require user ahmad admin_backup

Combining Authentication with IP Restrictions

I sometimes require both a valid login and a trusted network location using RequireAll/RequireAny (Apache 2.4+):

<Directory /var/www/html/admin>
    AuthType Basic
    AuthName "Restricted Area"
    AuthUserFile /etc/apache2/.htpasswd

    <RequireAll>
        Require valid-user
        Require ip 203.0.113.0/24
    </RequireAll>
</Directory>

That means a visitor has to both authenticate and connect from an allowed IP range.

Using Digest Authentication (Stronger Alternative)

Basic Authentication sends credentials base64-encoded (trivially decodable) on every request, relying entirely on HTTPS for protection. Digest Authentication hashes credentials before transmission, adding a layer of protection even without TLS — though I still use HTTPS regardless.

sudo htdigest -c /etc/apache2/.htdigest "Restricted Area" ahmad
<Directory /var/www/html/admin>
    AuthType Digest
    AuthName "Restricted Area"
    AuthDigestProvider file
    AuthUserFile /etc/apache2/.htdigest
    Require valid-user
</Directory>

Requires mod_auth_digest:

sudo a2enmod auth_digest

In practice I mostly just pair Basic Authentication with HTTPS rather than reaching for Digest, since HTTPS already protects credentials in transit and I need it for other reasons anyway.

Real-World Use Cases

Mistakes I’ve Made

Security Best Practices

Performance Considerations

Troubleshooting

No login prompt appears, page loads directly I confirm the <Directory> block matches the actual requested path, and that mod_auth_basic is enabled:

apache2ctl -M | grep auth_basic

“Internal Server Error” after adding auth config Usually a syntax error or a missing/mispathed AuthUserFile:

sudo apachectl configtest
sudo tail -f /var/log/apache2/error.log

Correct password rejected I check for trailing whitespace accidentally copied into the password, and confirm .htpasswd uses a hash format Apache’s built-in modules support (the default htpasswd output works fine).

FAQs

Is Basic Authentication secure enough for sensitive data? Only combined with HTTPS. Even then, I’d only use it for low-to-moderate sensitivity use cases like staging sites or internal tools — for anything more sensitive, I use a full application-level auth system.

Can I protect an entire site, not just one directory? Yes — apply the same AuthType/AuthUserFile/Require valid-user block to the <Directory> matching the document root.

Do I need a separate password file for each protected directory? Not necessarily — I often reuse one .htpasswd across multiple directories and use Require user to control access per directory.

Summary and Key Takeaways

References

Exit mobile version