Basic authentication is wonderfully small: Apache challenges the browser, checks a password-file entry, and either serves the resource or returns 401. That simplicity is also its boundary. It is suitable for a small internal preview or temporary gate—not a substitute for application sessions, MFA, account recovery, audit-rich identity, or fine-grained authorization.
Plan the protection boundary
Choose the exact hostname and URL subtree to protect.
Confirm HTTPS is already valid and HTTP redirects to it.
Decide whether every valid user is equivalent or groups/roles are needed.
Keep credentials outside
/var/wwwand any backup/export reachable from the site.Identify automation/API clients that may break when a 401 challenge is introduced.
Define rotation, removal, log-retention, rate-limit, and incident-response ownership.
1. Install the password utility
sudo apt update
sudo apt install apache2-utilsReview the package transaction, then confirm apache2-utils is installed.Risk level: caution. Review the command before running it.
This installs htpasswd, not Apache authentication policy
apache2-utilssupplieshtpasswdand other Apache utilities.apt updaterefreshes package metadata; installation changes system packages.Use supported Ubuntu repositories and the organization’s approved patch process.
Authentication modules may already be enabled with Ubuntu’s Apache packaging; verify rather than enabling random modules.
Package installation does not create users or change a virtual host.
2. Create a credential directory outside web content
sudo install -d -m 0750 -o root -g www-data /etc/apache2/auth
sudo htpasswd -cB /etc/apache2/auth/site-users alice
sudo chown root:www-data /etc/apache2/auth/site-users
sudo chmod 0640 /etc/apache2/auth/site-usersNew password:
Re-type new password:
Adding password for user aliceRisk level: caution. Review the command before running it.
Create the file once, then protect it
-ccreates or truncates the file; use it only for the first user.-Bselects bcrypt, a password-hashing scheme intended to be expensive to guess.The prompt avoids placing the password in shell history or the process list.
Root owns the file while Apache’s
www-datagroup can read it.The file is outside the document root so a web-server mapping mistake cannot serve it.
Back up and transfer it as a secret, not ordinary website content.
Add later users without -c
sudo htpasswd -B /etc/apache2/auth/site-users bobNew password:
Re-type new password:
Adding password for user bobRisk level: caution. Review the command before running it.
The missing -c is intentional
Running
htpasswd -cagain would replace the file and remove existing users.Choose unique personal usernames instead of one shared credential when accountability matters.
Use a password manager to generate/store strong unique passwords.
Do not use
-bwith a literal password; it exposes the secret through command history/process arguments.For many users or enterprise identity, move to an appropriate identity provider instead of scaling a flat file indefinitely.
3. Configure the canonical TLS virtual host
<VirtualHost *:443>
ServerName preview.example.com
DocumentRoot /var/www/preview
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/preview.example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/preview.example.com/privkey.pem
<Directory "/var/www/preview/private">
Options -Indexes
AllowOverride None
AuthType Basic
AuthName "Preview access"
AuthBasicProvider file
AuthUserFile /etc/apache2/auth/site-users
Require valid-user
</Directory>
ErrorLog ${APACHE_LOG_DIR}/preview-error.log
CustomLog ${APACHE_LOG_DIR}/preview-access.log combined
</VirtualHost>Scope access in server configuration
Edit the source vhost in
sites-available, not a generated/symlink target undersites-enabled.<Directory>matches a filesystem path; protect the narrow directory intended.AllowOverride Nonekeeps policy in reviewed server config instead of.htaccess.AuthUserFileuses an absolute path outside content.Require valid-userallows any account present in the password file.Options -Indexesprevents automatic directory listings but is not authentication.Certificate paths are deployment-specific placeholders; use the server’s valid managed certificate.
Protect by URL only when you mean URL
<Location> operates on URL space and can be appropriate for reverse-proxied/application endpoints; <Directory> operates on filesystem paths. They are not interchangeable, and overlapping authorization containers merge in ways that deserve explicit testing. Prefer the container that matches the resource architecture and avoid broad regexes.
4. Confirm required modules and site state
sudo apache2ctl -M | rg "auth_basic|authn_file|authz_user|ssl"
sudo apache2ctl -S auth_basic_module (shared)
authn_file_module (shared)
authz_user_module (shared)
ssl_module (shared)
VirtualHost configuration: ...Inspect before changing module state
-Mlists loaded modules used by the directives.-Sshows vhost parsing and hostname/port selection.If a required packaged module is absent, enable only that module with Ubuntu’s
a2enmodand revalidate.A request hitting the wrong default virtual host may appear to ignore authentication.
Resolve duplicate ServerName/listener/vhost issues before testing credentials.
5. Validate, enable, and reload safely
sudo apache2ctl configtest
sudo a2ensite example-ssl.conf
sudo apache2ctl configtest
sudo systemctl reload apache2
sudo systemctl --no-pager --full status apache2Syntax OK
Enabling site example-ssl.
Syntax OK
● apache2.service - The Apache HTTP Server
Active: active (running)Risk level: caution. Review the command before running it.
Configtest must precede every reload
The first check establishes the current configuration is healthy.
a2ensitemanages the enabled-site link fromsites-available.The second check validates the newly enabled configuration.
Reload applies valid configuration without intentionally terminating active connections like a full restart.
Service status is useful, but HTTP behavior and logs remain the final evidence.
Keep another privileged session available during remote changes to reduce lockout risk.
6. Verify unauthenticated behavior
curl -sS -o /dev/null -D - https://preview.example.com/private/HTTP/2 401
www-authenticate: Basic realm="Preview access"A protected resource should challenge
HTTP 401 proves the request reached a protected context without acceptable credentials.
WWW-Authenticateadvertises Basic and the configured realm.Verify the certificate and hostname normally; do not add
-kto hide TLS failures.A 200 response means the wrong vhost/path/container may be active or credentials are being injected upstream.
A 403 response points to authorization/filesystem access policy rather than the normal Basic challenge.
7. Verify credentials without shell-history leakage
read -r -p "Username: " AUTH_USER
read -r -s -p "Password: " AUTH_PASS
printf "\n"
curl --fail-with-body --user "$AUTH_USER:$AUTH_PASS" \
https://preview.example.com/private/
unset AUTH_PASS AUTH_USERProtected response body appears only for a valid account.Risk level: caution. Review the command before running it.
Treat client credentials as secrets too
Silent input keeps the password off the terminal display.
Quoted variables preserve special characters in the shell argument.
A process inspector may still briefly observe command arguments on some systems; use a dedicated secret-aware client/config mechanism for automation.
Unset variables after the test and avoid verbose/header traces in shared logs.
Test an invalid password and removed user as well as success.
Browsers may cache Basic credentials for the realm until the session closes, complicating logout testing.
Password file verification without printing hashes
sudo htpasswd -v /etc/apache2/auth/site-users alicePassword:
Password for user alice correct.Do not cat the credential file
htpasswd -vverifies a prompted password against the stored entry.Printing hashes adds no operational value and can leak them into terminals, tickets, recordings, or logs.
File readability should be checked with ownership/mode tools, not by exposing contents.
A valid file entry does not prove the correct vhost references that file.
Rotate a user password
sudo htpasswd -B /etc/apache2/auth/site-users aliceNew password:
Re-type new password:
Updating password for user aliceRisk level: caution. Review the command before running it.
Rotation updates the entry in place
No Apache reload is normally needed for a flat-file password change; verify on the actual deployment.
Distribute the replacement through a password manager or approved secret channel.
Browser-cached credentials can make immediate negative testing confusing.
Rotate after staff changes, suspected exposure, accidental publication, or policy interval.
Changing one Basic password does not invalidate already proxied application sessions downstream.
Remove a user deliberately
sudo htpasswd -D /etc/apache2/auth/site-users bob
sudo htpasswd -v /etc/apache2/auth/site-users bobDeleting password for user bob
Password verification failed.Risk level: caution. Review the command before running it.
Verify revocation end to end
-Ddeletes the named entry without recreating the file.Keep a recoverable secret backup under the organization’s retention policy before bulk changes.
Test the removed account through HTTPS and confirm 401.
Review caches, reverse proxies, and application sessions if the protected resource establishes another authenticated state.
Record who authorized and performed access removal without recording the password/hash.
Restrict to named users or groups
AuthType Basic
AuthName "Operations preview"
AuthBasicProvider file
AuthUserFile /etc/apache2/auth/site-users
Require user alice carolAuthorization follows authentication
Require valid-usertrusts every entry in the file.Require usernarrows authorization to listed authenticated usernames.For larger sets, use an appropriate group provider/file or external identity system.
Usernames are operational identities; normalize naming and removal ownership.
Do not build complex business authorization in Apache flat files when the application/identity provider owns that domain.
Reverse proxy considerations
Decide whether Apache Basic auth is only an edge gate or the application should know the identity.
Do not blindly forward the incoming
Authorizationheader to an upstream that interprets it differently.Clear/set identity headers at the trusted proxy boundary and prevent clients from spoofing them.
Protect health checks and ACME challenge paths appropriately; broad auth can break automation.
Ensure cache keys never mix authenticated and unauthenticated responses.
Test WebSocket, streaming, uploads, APIs, and redirects through the protected path.
Brute-force and logging controls
Basic auth itself has no account lockout, MFA, recovery, or anomaly detection.
Use network allowlists/VPN, reverse-proxy rate limiting, or an identity-aware access proxy for higher-risk exposure.
Monitor repeated 401s while avoiding Authorization header logging.
Restrict access/error log permissions and retention; URLs can contain sensitive query data.
Do not put credentials in URLs (
https://user:pass@...); they leak through history and tooling.Strong bcrypt hashes protect the server-side file only; weak user passwords remain guessable online/offline.
Common failures decoded
No login prompt / HTTP 200: wrong vhost/path,
<Directory>mismatch, proxy handling, or authorization config not loaded.HTTP 500: inspect Apache error log for unreadable password file, unknown directives, or module/config problems.
HTTP 403: filesystem permissions or
Require/other authorization rules deny after/before authentication.Correct password still returns 401: wrong password file, username case/spelling, hash/file corruption, or browser-cached old credential.
Apache reload fails: run configtest, inspect exact file/line, fix syntax, and keep the previous running config.
Works on localhost only: DNS/vhost/TLS/firewall/proxy differences mean remote requests hit another path.
Adding a user deleted others:
htpasswd -cwas reused; restore the secret backup and recreate carefully.Hash file is downloadable: it was placed under the document root or aliased path; remove exposure and rotate every credential immediately.
When Basic auth is the wrong tool
Public/customer accounts needing signup, recovery, session logout, consent, and auditing.
Administrative access requiring MFA, device posture, SSO, or centralized revocation.
Per-resource roles and application-domain authorization.
Large/changing organizations where flat-file lifecycle cannot be governed safely.
APIs needing scoped, short-lived machine credentials rather than reusable human passwords.
In those cases use an identity-aware proxy, OIDC/SAML integration, VPN/mTLS, or application authentication appropriate to the threat model.
Production completion checklist
HTTPS certificate/redirect are valid before the auth gate is exposed.
Password file is outside web roots, bcrypt-hashed, root-owned, group-readable only by Apache, backed up as a secret.
Canonical
sites-availableconfig protects the exact intended directory/location.Modules and vhost selection are verified.
Configtest passes before enable/reload and rollback access is retained.
Unauthenticated and invalid requests return 401; valid users return expected content.
Removed/rotated users are tested and browser/proxy caches understood.
Authorization headers/hashes/passwords never enter logs, shell history, tickets, or article examples.
Rate limiting/network boundary/monitoring match the exposure risk.
An owner and expiry/review date exist for temporary gates.
Official Apache and Ubuntu references
Apache authentication and authorization explains providers, realms, password files, and Require directives.
mod_auth_basic documents Basic authentication and its TLS requirement.
htpasswd documents create/update/delete/verify flags and hashing algorithms.
Apache Directory directive defines filesystem container matching.
Ubuntu Apache installation/configuration describes the Debian/Ubuntu sites-available/enabled layout and service management.
Comments and corrections