Complete Guide to htaccess Commands for Linux Hosting

htaccess commands that actually work, processing order, and commands that cause a 500 error on shared hosting. With ready-to-copy examples.

10 min Updated 19 Sep 2026

Your htaccess file returns a 500 error and you don't know which line is responsible

You've just added a command to your .htaccess file and now your site is down with a 500 Internal Server Error. The first thing you do is download the file via FTP and examine it line by line. The problem is that Apache doesn't show the exact error, and you don't know which command caused the entire site to become inaccessible.

Quick solution: save the file under a different name, such as .htaccess.bak, and create a new empty file. The site comes back. Now add the commands one by one until the 500 error returns. The last command you added is the culprit. This line-by-line testing method is the only approach that works in a shared environment because Apache error logs are usually not accessible to you.

htaccess command processing order: where everything goes wrong

Apache does not execute .htaccess commands from top to bottom. This common misconception is the source of most redirect errors. RewriteRule rules execute in their apparent order, but Redirect rules from the mod_alias module work in exactly the opposite way: the last rule executes first.

This means if you have two redirect rules that conflict with each other, the result will differ from what you expect. That's why combining Redirect and RewriteRule in one file almost always produces unpredictable results. Here's where people make mistakes: they add a Redirect 301 rule for domain changes and a RewriteRule for removing www. The result is chained redirects and slow site performance.

Remember my rule: use only one module for each task. If you want to perform redirects, write all rules with RewriteRule. If you want to move a specific page, use Redirect. Mixing these two is an error I constantly see in practice.

Basic commands you should know

First, let's review the basic structure. The .htaccess file is placed in the root of public_html and applies to all subdirectories unless they have their own separate file. This cascading behavior means a command in the root affects all subdirectories.

# Enable the rewrite engine
RewriteEngine On

# Set custom error pages
ErrorDocument 404 /404.html
ErrorDocument 403 /forbidden.html

# Block access to the htaccess file
<Files ".htaccess">
    Require all denied
</Files>

The Require all denied command in Apache 2.4 replaced Deny from all, which was used in older versions. If your hosting uses Apache 2.2, the new command won't work and vice versa. To determine the version, create a phpinfo.php file and check the SERVER_SOFTWARE value.

301 redirects: domain migration and www removal

A 301 redirect tells search engines that the page has been permanently moved. This is the most important command you'll write in .htaccess, especially when changing your site's domain. If you do this incorrectly, you'll lose years of SEO value.

# Redirect from www to non-www
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]

# Redirect from HTTP to HTTPS
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

Note that the www removal rule should come before the HTTPS rule. If it's the other way around, you'll first be redirected to HTTPS and then www is removed, creating two consecutive redirects. Each additional redirect means a full round-trip and an increase in TTFB of 100 to 300 milliseconds.

For a complete domain migration to a new domain, the rule is simpler:

RewriteEngine On
RewriteCond %{HTTP_HOST} ^old-domain\.com$ [NC,OR]
RewriteCond %{HTTP_HOST} ^www\.old-domain\.com$ [NC]
RewriteRule ^(.*)$ https://new-domain.com/$1 [R=301,L]

If you have a domain migration ahead, read the guide on changing your site's domain without losing SEO. This guide shows exactly what order to follow for redirects so that indexed pages retain their authority.

Browser caching and compression: two commands that save speed

Most WordPress sites on shared hosting run without any browser-level caching. The result is that every visitor downloads images, CSS, and JavaScript files again. With two simple blocks, you can change this situation.

# Browser caching for static files
<IfModule mod_expires.c>
    ExpiresActive On
    ExpiresByType image/jpg "access plus 1 year"
    ExpiresByType image/jpeg "access plus 1 year"
    ExpiresByType image/png "access plus 1 year"
    ExpiresByType image/webp "access plus 1 year"
    ExpiresByType text/css "access plus 1 month"
    ExpiresByType application/javascript "access plus 1 month"
</IfModule>

# Gzip compression
<IfModule mod_deflate.c>
    AddOutputFilterByType DEFLATE text/html text/css application/javascript image/svg+xml
</IfModule>

One year for images is not an exaggeration. If the image file name doesn't change, the browser will use the local cache for up to a year without sending a request to the server. But never set a one-year cache for HTML, because page content needs to stay up to date.

Here's where people make mistakes: the mod_deflate module is not enabled on all hosting servers. If you add the command and the module doesn't exist, you'll get a 500 error. That's why we put commands inside <IfModule>. This tag tells Apache to silently skip if the module isn't available and not throw an error.

Commands that are not allowed on shared hosting

Shared hosting means you're a tenant on a server where dozens of other sites are also running. So it's natural that some commands are disabled to maintain security and stability for everyone. These commands typically result in a 500 error or an Invalid command message in the logs.

Command Reason for being disabled Alternative
php_value memory_limit Changing PHP's allocated memory at the directory level Change in php.ini or request from support
Options +FollowSymLinks Security: allowing symbolic links to be followed Usually already enabled or not needed
RewriteRule with target outside public_html Access to files outside the web root Move the file into public_html
SetEnvIf for specific headers May conflict with server security settings Use .user.ini or php.ini

If you write a command and get a 500 error, first assume the command is disabled at the server level, not that the syntax is wrong. A quick way to test: put the command inside <IfModule>. If the error goes away, the module or command isn't available.

To see the exact resource limits on shared hosting, check the complete reference for hosting resource limits. This document shows what each number in the control panel counts and where you'll hit the ceiling.

Password-protecting directories

Sometimes you need to hide a directory from public view, such as a test environment or admin panel. The standard method uses .htpasswd, which is placed outside public_html so it can't be downloaded.

# In the .htaccess file inside the target directory
AuthType Basic
AuthName "Restricted Area"
AuthUserFile /home/username/.htpasswd
Require valid-user

Replace the path /home/username/.htpasswd with the actual path on your hosting. To create the password file, use the following command in SSH:

htpasswd -c /home/username/.htpasswd admin

If you don't have SSH, online .htpasswd generators also work, but make sure the password hash is of type bcrypt or apr1. Simple old MD5 hashes are not supported in Apache 2.4 and will cause authentication errors.

See the complete guide on password-protecting directories on hosting if you want to do this for a test environment or subdomain. This method works on all Linux hosting and doesn't require plugins or additional tools.

Blocking IPs and preventing malicious requests

If you look at the server logs, you'll see that bots and scanners are constantly searching for vulnerable paths. Blocking specific IPs at the .htaccess level is simple but has limitations.

# Block a specific IP
<RequireAll>
    Require all granted
    Require not ip 123.45.67.89
    Require not ip 203.0.113.0/24
</RequireAll>

The limitation of this method: if the attacker uses a dynamic IP or comes from different networks, this list becomes useless. For real attacks, it's better to use application-level firewalls like Wordfence or the hosting's own security tools. .htaccess is good for blocking a few specific nuisance IPs, not for defending against an attack.

You can also inspect request headers and block bad bots:

RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (ahrefsbot|mj12bot|semrushbot) [NC]
RewriteRule ^ - [F,L]

The [F] flag returns a 403 status code, and [L] means stop processing subsequent rules. This combination is effective for blocking specific bots, but be careful not to accidentally block useful bots like Googlebot.

Fixing common errors: white screen and redirect loops

The two errors we see most in support are the white screen and redirect loops. The white screen usually has nothing to do with .htaccess and comes from a PHP error. But sometimes a wrong command like php_flag display_errors on can make the problem worse.

Redirect loops, however, are almost always from .htaccess. Its sign in the browser: the message ERR_TOO_MANY_REDIRECTS. The usual cause is that your HTTPS rule also applies to requests that are already HTTPS. The solution is to add a re-check condition:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]

The second condition checks the X-Forwarded-Proto header. If your site is behind a CDN or proxy, this header indicates that the original connection was HTTPS and shouldn't be redirected again. Without this condition, an infinite loop is created between the server and the CDN.

If you're facing a white screen, follow the guide on fixing the white screen in WordPress and PHP. Most of the time, the problem is PHP memory, not .htaccess. But if the white screen appeared after changing .htaccess, first revert the file to its previous state.

Testing commands before applying them to your main site

Never test a new command directly on your main site. Create a test directory, put the .htaccess file there, and check the behavior. This takes two minutes and saves you an hour of debugging.

To verify that redirect rules work correctly, use the curl command-line tool:

curl -I -L https://example.com/old-page

The output shows all chained redirects. If you see more than two consecutive redirects, your rules aren't optimized. Each additional redirect increases loading time for real users.

To check DNS and ensure records are configured correctly, use the DNS and network checker tool. Sometimes the redirect problem is DNS-related, not .htaccess. If the domain points to the old server, no matter how correct your rules are, users won't reach the right destination.

When htaccess doesn't work: what to do

Sometimes the command is correct, the syntax is correct, but there's no effect. This usually means Apache doesn't have permission to process .htaccess in that directory. The AllowOverride None setting in the server configuration disables all .htaccess files.

On shared hosting, this situation is rare but can occur for certain directories. A simple test: put a deliberate error in the file, such as an extra character. If the site doesn't return a 500 error, the file isn't being read at all. If it does return an error, the file is being processed and the problem is elsewhere.

If you're on a dedicated server, you can change the AllowOverride settings in the virtual host configuration file. But on shared hosting, this isn't in your control and you'll need to contact support. Most of the time, the problem is elsewhere: site caching. If you're using page caching, changes to .htaccess may not take effect until the cache is cleared.

To check whether your site uses server-side caching that's making commands ineffective, inspect the response headers with curl -I. If you see a header like X-Cache: HIT or similar, clear the cache and test again.

Frequently asked questions

Why do I get a 500 error after changing htaccess?

A 500 error after changing .htaccess is almost always from a syntax error or using a command that's disabled on your hosting. Save the file under a different name to bring the site back, then add commands one by one until the 500 error returns. The last command you added is the culprit.

What's the difference between Redirect and RewriteRule in htaccess?

Redirect comes from the mod_alias module and is only used for simple transfers from one URL to another. RewriteRule comes from mod_rewrite and allows conditional logic with RewriteCond. For conditional redirects like removing www or redirecting to HTTPS, use RewriteRule. Combining these two in one file produces unpredictable results.

How do I do a 301 redirect from HTTP to HTTPS in htaccess?

The standard rule is: RewriteCond %{HTTPS} off followed by RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]. If your site is behind a CDN, also add the second condition RewriteCond %{HTTP:X-Forwarded-Proto} !https to prevent a redirect loop.

Can I change the PHP memory limit in htaccess?

The php_value memory_limit command is disabled on most shared hosting because it compromises server security. If you need more memory, ask your hosting support or use the .user.ini file. On ServerNet Linux hosting, these limits are clearly stated, and you know exactly what amount you have available.

Was this page helpful?