An .htaccess file is a small configuration file Apache (and Apache-compatible hosts such as many cPanel and LiteSpeed plans) reads for a single folder and everything under it. You can use it to fix redirects, force HTTPS, password-protect a staging area, serve custom error pages, and tidy messy URLs — without editing the main server config.
This guide is a practical rewrite for UK business sites and shared hosting: what .htaccess is, how to enable and create it, and copy-paste examples you can adapt. It is written in plain English with real snippets, not a product pitch.
What .htaccess is (and is not)
The leading dot means the file is hidden in Unix-style listings. Apache looks for it in the document root and parent directories (when allowed). Rules apply to that directory tree until a more specific file overrides them.
- Good for: shared hosting, Hostinger-style
public_html, WordPress pretty permalinks, quick redirects, directory password gates, custom 404 pages. - Not ideal for: high-traffic permanent rules on a VPS you fully control (put those in the virtual host config instead — fewer filesystem checks per request).
- Not used by: Nginx or Caddy natively. If you move off Apache, you must re-express the same behaviour in that server’s config.
Treat .htaccess like live production config: one typo can 500 the whole site. Always keep a backup and change one rule at a time.
Key points before you edit anything
- AllowOverride must allow it — if the host sets
AllowOverride None, your file is ignored. - Placement matters — put the site-wide file in the web root (often
public_html/or/var/www/yourdomain/). - Apache 2.4 prefers
Require— olderOrder/Allow/Denystill appears on older docs; prefer modernRequiresyntax on new setups. - Modules must be loaded — rewrites need
mod_rewrite; auth needs the auth modules; a missing module often surfaces as a 500.
Enable .htaccess (when you control Apache)
On a VPS you manage, open the site’s virtual host and allow overrides for the document root. Example shape (Ubuntu + Apache):
<VirtualHost *:80>
ServerName example.co.uk
ServerAlias www.example.co.uk
DocumentRoot /var/www/example.co.uk
<Directory /var/www/example.co.uk>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/example-error.log
CustomLog ${APACHE_LOG_DIR}/example-access.log combined
</VirtualHost>
Then enable rewrite (if needed) and reload:
sudo a2enmod rewrite
sudo systemctl reload apache2
On most shared hosts you cannot edit this. If redirects already work for WordPress, AllowOverride is usually already set — you only need a valid .htaccess in public_html.
Create the file
In the site document root:
# SSH example
cd ~/domains/example.co.uk/public_html
nano .htaccess
Via FTP/SFTP, create a file named exactly .htaccess (no .txt extension). If your file manager hides “dotfiles”, enable “show hidden files”.
Start with a comment block so future-you knows what lives here:
# example.co.uk — root .htaccess
# Last change: HTTPS + www canonical + security headers
Example 1 — Force HTTPS and a single hostname
Pick one canonical host (usually https://www. or bare domain) and redirect everything else. This helps SEO and cookies stay consistent.
RewriteEngine On
# Force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Force www (optional — invert if you prefer non-www)
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Test with:
curl -I http://example.co.uk/
curl -I https://example.co.uk/
You should see a single clean 301 chain ending on your canonical HTTPS URL — not a loop.
Example 2 — Simple permanent redirects (old → new)
When a page moves, send users and search engines to the new URL:
Redirect 301 /old-services.html /services/
Redirect 301 /about-us /about/
Redirect 301 /blog/2023/welcome /blog/welcome/
For host-level moves (domain change), use a full URL target:
Redirect 301 /pricing https://www.newbrand.co.uk/pricing/
Prefer 301 for permanent moves and 302 only for temporary tests so you do not train Google on a temporary destination.
Example 3 — Pretty URLs with mod_rewrite
WordPress and many PHP apps use rewrite rules so /blog/my-post/ maps to a front controller. A minimal front-controller pattern:
RewriteEngine On
RewriteBase /
# Existing files and folders are left alone
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
If the site lives in a subfolder (for example /staging/client/), set RewriteBase to that path or rewrites can 404:
RewriteBase /staging/client/
Example 4 — Custom error pages
Default Apache error pages look unfinished. Point common status codes at branded templates:
ErrorDocument 400 /errors/400.php
ErrorDocument 401 /errors/401.php
ErrorDocument 403 /errors/403.php
ErrorDocument 404 /errors/404.php
ErrorDocument 500 /errors/500.php
Make sure those error scripts themselves do not trigger another error (for example a broken include that causes a second 500).
Example 5 — Password-protect a directory (Basic Auth)
Useful for staging sites, client previews, or a private PDF folder. First create a password file outside the public web root:
sudo htpasswd -c /home/you/private/.htpasswd clientname
# add more users without -c
sudo htpasswd /home/you/private/.htpasswd teammate
Then in the directory you want to lock (or in a nested .htaccess):
AuthType Basic
AuthName "Staging — authorised access only"
AuthUserFile /home/you/private/.htpasswd
Require valid-user
On shared hosting, paths often look like /home/u123456789/domains/example.co.uk/private/.htpasswd. Confirm the absolute path with your host’s file manager or SSH pwd.
Example 6 — Block hotlinking and hide sensitive files
Stop other sites embedding your images (bandwidth theft) and block direct access to config-like files:
# Optional: only allow images from your own host
RewriteEngine On
RewriteCond %{HTTP_REFERER} !^$
RewriteCond %{HTTP_REFERER} !^https?://(www\.)?example\.co\.uk/ [NC]
RewriteRule \.(jpe?g|png|gif|webp|svg)$ - [F,NC,L]
# Deny access to hidden / sensitive names
<FilesMatch "(^\.env|composer\.(json|lock)|\.git|wp-config\.php)$">
Require all denied
</FilesMatch>
Adjust the domain and file list to match your stack. WordPress already has its own protective rules in many installs — do not blindly stack conflicting blocks.
Example 7 — MIME types and browser caching
If a file type is not served with the right content type, or you want longer cache headers for static assets:
# Example MIME type
AddType audio/mp4 .m4a
AddType font/woff2 .woff2
# Cache static assets (tune max-age to your deploy habit)
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 7 days"
ExpiresByType application/javascript "access plus 7 days"
ExpiresByType image/jpeg "access plus 30 days"
ExpiresByType image/png "access plus 30 days"
ExpiresByType image/webp "access plus 30 days"
ExpiresByType font/woff2 "access plus 30 days"
</IfModule>
Example 8 — Security headers (lightweight starter)
Headers are often set in the main vhost or a CDN, but on Apache you can start here:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
# Content-Security-Policy is powerful — draft carefully; a bad CSP breaks scripts and embeds
</IfModule>
Speed and security trade-offs
When AllowOverride is enabled, Apache may check for .htaccess on every request as it walks the directory path. On a normal small business site the cost is tiny. On a busy server with deep trees, permanent rules belong in the virtual host config instead.
Security-wise, .htaccess is powerful because it is easy to edit and applies immediately — which is also the risk. Anyone with FTP/SFTP write access to the web root can change redirects, auth, and rewrite behaviour. Protect credentials, limit who can deploy, and keep secrets out of the public tree.
Troubleshooting: 500s, ignored rules, redirect loops
500 Internal Server Error after a change
- Restore the previous
.htaccessimmediately if the site is down. - Check the error log for the real line (often “Invalid command” or “RewriteEngine not allowed”).
- Confirm modules:
sudo a2enmod rewrite headers expiresthen reload Apache. - Re-add rules one block at a time.
# Typical log locations
sudo tail -n 50 /var/log/apache2/error.log
# Hostinger / shared hosts: use the panel “Error Log” for the domain
Rules seem to do nothing
AllowOverridemay beNone(or too narrow).- File is in the wrong folder (not the actual document root).
- File permissions block the web user from reading it.
- You are on Nginx or a CDN that never sees the file.
Redirect loops
- HTTPS rule fighting a host rule (www vs non-www) — simplify to one clear chain.
- App-level redirects (WordPress site URL settings) fighting server rules.
- Debug with
curl -Iand watchLocationheaders, not only the browser address bar.
FAQ
What is the .htaccess file used for?
Per-directory Apache configuration: redirects, rewrites, authentication, error pages, MIME types, caching headers, and light security rules when you cannot (or should not) edit the main server config.
Where should I put .htaccess?
In the website document root for site-wide rules — often public_html/ on shared hosting, or /var/www/yourdomain/ on a VPS. Nested folders can have their own files for local overrides.
Why is my .htaccess not working?
Most often AllowOverride is disabled, the file is in the wrong directory, a required module is missing, or a syntax error is causing Apache to reject the file (check the error log).
Does .htaccess slow the site down?
It can add a small amount of work per request because Apache may scan for the file. For typical UK SME traffic this is rarely noticeable. For permanent high-traffic rules on a server you control, prefer the main Apache config.
Can I use .htaccess with Nginx?
No. Translate the behaviour into Nginx server / location blocks (or use Apache / LiteSpeed if you need .htaccess compatibility).
Is .htaccess safe for WordPress?
Yes when rules are correct. WordPress manages its own rewrite block between markers — edit outside that block or use a child of those markers carefully so updates do not wipe your custom rules.
A sensible workflow
- Download / copy the current
.htaccessbefore editing. - Change one concern at a time (HTTPS, then a single redirect, then headers).
- Test with
curl -Iand a private browser window. - Watch error logs for five minutes after deploy.
- Document non-obvious rules in comments inside the file.
Good .htaccess work is boring: short rules, clear comments, reversible changes, and no surprise loops.
Need help with redirects, staging gates or a broken 500?
I’m Jamie Freeman — a UK web designer and developer. I fix Apache / LiteSpeed configuration issues on business sites, set up clean HTTPS and redirect maps, and harden staging areas so clients can preview safely.
If a rewrite is looping, a host is ignoring your rules, or you want a tidy production .htaccess without guesswork: get a free quote →