{"id":1955,"date":"2017-08-24T12:34:04","date_gmt":"2017-08-24T07:04:04","guid":{"rendered":"https:\/\/pheonixsolutions.com\/blog\/?p=1955"},"modified":"2026-09-03T15:26:10","modified_gmt":"2026-09-03T09:56:10","slug":"setup-redirection-one-domain-another-domain-htaccess","status":"publish","type":"post","link":"https:\/\/pheonixsolutions.com\/blog\/setup-redirection-one-domain-another-domain-htaccess\/","title":{"rendered":"Setup redirection from one domain to another domain on .htaccess"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">Introduction<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">This guide explains how to <strong>set up domain redirection with .htaccess<\/strong>, covering the full process \u2014 from verifying Apache&#8217;s rewrite module is enabled through writing a rule that correctly handles both HTTP and HTTPS traffic, which a lot of quick-reference examples skip entirely.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">There are common scenarios where you need to redirect one domain to another: consolidating multiple domains into one, migrating a site to a new domain name, or redirecting a retired domain to its replacement so existing links and bookmarks don&#8217;t break. Apache&#8217;s <code>.htaccess<\/code> file, combined with the <code>mod_rewrite<\/code> module, is the standard way to handle this at the web server level.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Implementation<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">I. Prerequisites<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before you set up domain redirection with .htaccess, make sure you have:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>An Ubuntu or CentOS server running Apache (2.4 or 2.2)<\/li>\n\n\n\n<li>Access to the domain&#8217;s document root<\/li>\n\n\n\n<li>The <code>mod_rewrite<\/code> module available (verified in Step III)<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">II. Architecture Overview<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Before editing any files, it helps to understand what actually happens when a redirect rule fires:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A browser sends an HTTP or HTTPS request for <code>domain.com<\/code><\/li>\n\n\n\n<li>Apache receives the request and, for the matching virtual host, checks whether a <code>.htaccess<\/code> file exists in the document root (and whether it&#8217;s permitted to read one \u2014 covered in Step V)<\/li>\n\n\n\n<li>If <code>mod_rewrite<\/code> is enabled and a matching <code>RewriteCond<\/code>\/<code>RewriteRule<\/code> pair is found, Apache generates an HTTP redirect response (301 or 302) pointing the browser to the new domain, instead of serving the requested page<\/li>\n\n\n\n<li>The browser receives that redirect response and automatically issues a new request to the new domain<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-scaled.png\"><img fetchpriority=\"high\" decoding=\"async\" width=\"1024\" height=\"602\" src=\"https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-1024x602.png\" alt=\"\" class=\"wp-image-11343\" srcset=\"https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-1024x602.png 1024w, https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-300x176.png 300w, https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-768x452.png 768w, https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-1536x904.png 1536w, https:\/\/pheonixsolutions.com\/blog\/wp-content\/uploads\/2017\/08\/htaccess_redirect_architecture-2048x1205.png 2048w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">This matters because a <code>.htaccess<\/code> redirect never actually &#8220;serves&#8221; the old domain&#8217;s content \u2014 it&#8217;s a server-level instruction that gets caught before the requested page loads at all, which is what makes it reliable for handling every single request to the old domain, regardless of which specific page was requested.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">III. Verify the Rewrite Module Is Enabled<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Domain redirection via <code>.htaccess<\/code> depends on Apache&#8217;s <code>mod_rewrite<\/code> module. Confirm it&#8217;s loaded:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">apachectl -M\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Look for <code>rewrite_module<\/code> in the output. If it isn&#8217;t listed, enable it:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On Ubuntu\/Debian:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo a2enmod rewrite\nsudo systemctl restart apache2\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On CentOS\/RHEL<\/strong>, <code>mod_rewrite<\/code> is typically compiled in by default with Apache from the standard package, but if it&#8217;s missing, ensure the corresponding line in <code>httpd.conf<\/code> is uncommented:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">LoadModule rewrite_module modules\/mod_rewrite.so\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then restart Apache:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo systemctl restart httpd\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">IV. Locate the Document Root<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">You&#8217;ll need to know the correct document root to place or edit the <code>.htaccess<\/code> file in the right location.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On a cPanel server:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/home\/username\/public_html\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>On a plain Ubuntu server:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/var\/www\/html\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Alternatively, confirm the exact document root Apache is actually using for a specific virtual host with:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">apachectl -S\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This lists all configured virtual hosts along with their document root paths \u2014 useful when a server hosts multiple domains and you need to be certain you&#8217;re editing the right one.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">V. Confirm .htaccess Overrides Are Allowed<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">This step is easy to overlook, and its absence is one of the most common reasons a correctly written redirect rule silently does nothing. By default, some Apache configurations set <code>AllowOverride None<\/code> for a given directory, which causes Apache to <strong>ignore <code>.htaccess<\/code> files entirely<\/strong> \u2014 no error is shown, the rule just never takes effect.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Check your virtual host or Apache configuration file for the relevant <code>&lt;Directory&gt;<\/code> block, and confirm it allows overrides:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;Directory \/var\/www\/html>\n    AllowOverride All\n&lt;\/Directory>\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If you had to change this, restart Apache to apply it:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo systemctl restart apache2\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">(Substitute <code>httpd<\/code> for the service name on CentOS\/RHEL.)<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">VI. Create or Edit the .htaccess File<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Navigate to the document root you identified in Step IV, and open (or create) the <code>.htaccess<\/code> file:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">cd \/var\/www\/html\nvi .htaccess\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">VII. Add the Redirect Rule<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Here&#8217;s a corrected, complete version of the redirect rule. A commonly seen mistake in quick-reference examples is missing the <code>RewriteEngine On<\/code> directive \u2014 without it, <code>mod_rewrite<\/code> won&#8217;t process any <code>RewriteCond<\/code> or <code>RewriteRule<\/code> lines at all, even if the module itself is enabled server-wide:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">RewriteEngine On\nRewriteCond %{HTTP_HOST} ^(www\\.)?domain\\.com$ [NC]\nRewriteRule (.*) https:\/\/www.newdomain.com\/$1 [R=301,L]\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What each line does:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-table\"><table class=\"has-fixed-layout\"><thead><tr><th>Line<\/th><th>Purpose<\/th><\/tr><\/thead><tbody><tr><td><code>RewriteEngine On<\/code><\/td><td>Turns on the rewrite engine for this <code>.htaccess<\/code> file \u2014 required before any rule will function<\/td><\/tr><tr><td><code>RewriteCond %{HTTP_HOST} ...<\/code><\/td><td>Matches requests to <code>domain.com<\/code> or <code>www.domain.com<\/code>, with <code>[NC]<\/code> making the match case-insensitive<\/td><\/tr><tr><td><code>RewriteRule (.*) https:\/\/www.newdomain.com\/$1<\/code><\/td><td>Redirects to the new domain, preserving the original request path via <code>$1<\/code><\/td><\/tr><tr><td><code>[R=301,L]<\/code><\/td><td><code>R=301<\/code> issues a permanent redirect (important for SEO \u2014 see Step XI); <code>L<\/code> stops processing further rewrite rules once this one matches<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Note on HTTPS:<\/strong> The example above hardcodes <code>https:\/\/<\/code> in the destination. If your old domain serves both HTTP and HTTPS traffic and you want to preserve that dynamically rather than forcing everything to HTTPS, you can reference <code>%{HTTPS}<\/code> conditionally \u2014 though in nearly all modern cases, redirecting everything to HTTPS on the new domain (as shown) is the better practice regardless, given HTTPS is now the standard expectation for any public-facing site.<\/p>\n<\/blockquote>\n\n\n\n<p class=\"wp-block-paragraph\">Replace <code>domain\\.com<\/code> with your actual old domain (keeping the backslash before each literal dot, since <code>.<\/code> is a special regex character that needs escaping to match a literal period), and <code>newdomain.com<\/code> with your actual new domain.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">VIII. Test the Redirect<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Save the file, then test it in a browser by visiting:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">http:\/\/domain.com\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">and<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">http:\/\/www.domain.com\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Both should automatically redirect to <code>https:\/\/www.newdomain.com<\/code>, preserving whatever path was originally requested \u2014 for example, <code>domain.com\/blog\/post-1<\/code> should land on <code>newdomain.com\/blog\/post-1<\/code>, not just the new domain&#8217;s homepage.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Tip:<\/strong> Browsers aggressively cache 301 redirects. If you&#8217;re testing changes and not seeing the expected behavior, test in a private\/incognito window or clear your browser cache to rule out a stale cached redirect from a previous test.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">IX. Common Redirect Variations<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Redirect only a specific subdirectory, not the whole domain:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">RewriteEngine On\nRewriteCond %{HTTP_HOST} ^(www\\.)?domain\\.com$ [NC]\nRewriteRule ^oldsection\/(.*)$ https:\/\/www.newdomain.com\/newsection\/$1 [R=301,L]\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Redirect everything to a single fixed URL, without preserving the path:<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">RewriteEngine On\nRewriteCond %{HTTP_HOST} ^(www\\.)?domain\\.com$ [NC]\nRewriteRule ^(.*)$ https:\/\/www.newdomain.com\/ [R=301,L]\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Redirect non-www to www on the same domain (a common companion rule):<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">RewriteEngine On\nRewriteCond %{HTTP_HOST} ^domain\\.com$ [NC]\nRewriteRule (.*) https:\/\/www.domain.com\/$1 [R=301,L]\n<\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">X. Troubleshooting Common Issues<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The redirect doesn&#8217;t happen at all, and no error appears:<\/strong> This is almost always the <code>AllowOverride None<\/code> issue from Step V \u2014 Apache is silently ignoring the <code>.htaccess<\/code> file entirely. Double-check the <code>&lt;Directory&gt;<\/code> block for the relevant document root.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>&#8220;Internal Server Error&#8221; (500) after adding the rule:<\/strong> Check Apache&#8217;s error log for specifics:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">sudo tail -f \/var\/log\/apache2\/error.log\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">(Path may differ on CentOS \u2014 commonly <code>\/var\/log\/httpd\/error_log<\/code>.) A malformed regex or a missing <code>RewriteEngine On<\/code> combined with other rewrite rules elsewhere in the file are common causes.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The redirect works but creates a redirect loop:<\/strong> This typically happens when the new domain&#8217;s own <code>.htaccess<\/code> also matches the same condition, redirecting back to itself indefinitely. Double-check that your <code>RewriteCond<\/code> pattern only matches the <em>old<\/em> domain, not the new one.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>The path isn&#8217;t preserved after redirecting:<\/strong> Confirm you&#8217;re using <code>$1<\/code> in the destination (as shown in Step VII) and that your <code>RewriteRule<\/code> pattern actually captures the path with <code>(.*)<\/code>. Omitting the capture group, as shown in the &#8220;fixed URL&#8221; variation in Step IX, is sometimes done intentionally but will drop the path if that wasn&#8217;t the goal.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">XI. Companion Rule: Forcing HTTPS on the New Domain<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Once traffic is redirecting to the new domain, it&#8217;s worth also confirming the new domain itself forces HTTPS, rather than allowing HTTP access to remain available alongside it. Add this rule to the new domain&#8217;s own <code>.htaccess<\/code> file:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">RewriteEngine On\nRewriteCond %{HTTPS} off\nRewriteRule ^(.*)$ https:\/\/%{HTTP_HOST}%{REQUEST_URI} [R=301,L]\n<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">This checks whether the request arrived over plain HTTP (<code>%{HTTPS} off<\/code>), and if so, redirects to the same path over HTTPS instead. Combined with the domain-to-domain redirect from Step VII, this ensures visitors always end up on the new domain over an encrypted connection, regardless of which protocol or domain they originally typed or clicked.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p class=\"wp-block-paragraph\"><strong>Note:<\/strong> If you already handle HTTP-to-HTTPS redirection elsewhere \u2014 for example, in your Apache virtual host configuration or via a reverse proxy\/load balancer in front of Apache \u2014 adding this same logic again in <code>.htaccess<\/code> is redundant. Check your existing setup first to avoid an unnecessary duplicate redirect hop, which adds latency for no benefit.<\/p>\n<\/blockquote>\n\n\n\n<h3 class=\"wp-block-heading\">XII. SEO Considerations for Domain Redirects<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Always use a 301 (permanent), not 302 (temporary), redirect for genuine domain migrations.<\/strong> Search engines treat these very differently \u2014 a 301 signals that link equity and rankings should transfer to the new domain, while a 302 does not, and can leave your new domain without the SEO value your old domain had built up.<\/li>\n\n\n\n<li><strong>Avoid redirect chains.<\/strong> If <code>domain.com<\/code> redirects to <code>newdomain.com<\/code>, which itself redirects somewhere else, each additional hop adds latency and can dilute the SEO signal. Redirect directly to the final destination in one hop wherever possible.<\/li>\n\n\n\n<li><strong>Update your sitemap and Search Console<\/strong> for the new domain once the redirect is live, and use Google Search Console&#8217;s &#8220;Change of Address&#8221; tool if this is a permanent domain migration, so search engines process the change more efficiently.<\/li>\n\n\n\n<li><strong>Give it time.<\/strong> Search engines don&#8217;t instantly re-index everything after a domain migration \u2014 expect a transition period of weeks to a couple of months before rankings fully reflect the new domain.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">XIII. Conclusion<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Setting up domain redirection with <code>.htaccess<\/code> comes down to a few key pieces: confirming <code>mod_rewrite<\/code> is enabled, making sure <code>AllowOverride All<\/code> is actually permitted for the directory in question, and writing a rule that includes the often-missing <code>RewriteEngine On<\/code> directive alongside a correctly escaped domain pattern. With HTTPS handled explicitly and a 301 status code in place, this approach reliably redirects an entire domain \u2014 preserving paths and SEO value \u2014 with a single small file.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For the complete reference on Apache&#8217;s rewrite syntax and available flags, see the <a href=\"https:\/\/httpd.apache.org\/docs\/current\/mod\/mod_rewrite.html\" target=\"_blank\" rel=\"noopener\">official mod_rewrite documentation<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently Asked Questions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Why doesn&#8217;t my redirect rule work even though the syntax looks correct?<\/strong> The two most common causes are a missing <code>RewriteEngine On<\/code> directive (required once per <code>.htaccess<\/code> file, even if <code>mod_rewrite<\/code> is enabled server-wide) and <code>AllowOverride None<\/code> on the relevant directory, which causes Apache to ignore <code>.htaccess<\/code> files entirely without any visible error.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Should I redirect at the .htaccess level or in the main Apache virtual host configuration?<\/strong> Both work, but placing rewrite rules directly in the virtual host configuration (rather than <code>.htaccess<\/code>) is generally faster, since Apache doesn&#8217;t need to check for and parse a <code>.htaccess<\/code> file on every single request. If you have access to the main server configuration, that&#8217;s the more efficient long-term choice \u2014 <code>.htaccess<\/code> remains useful when you only have access to the document root itself, such as on shared hosting.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Will this redirect preserve query strings, like ?ref=email?<\/strong> Not by default with the examples shown here \u2014 you&#8217;d need to add the <code>QSA<\/code> (Query String Append) flag to the rule, for example <code>[R=301,L,QSA]<\/code>, to automatically carry query parameters through to the new URL.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Can I redirect multiple old domains to the same new domain?<\/strong> Yes \u2014 adjust the <code>RewriteCond<\/code> pattern to match multiple domains using alternation, for example: <code>RewriteCond %{HTTP_HOST} ^(www\\.)?(olddomain1\\.com|olddomain2\\.com)$ [NC]<\/code>, which matches either old domain and redirects both to the same destination.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>What&#8217;s the difference between RewriteRule and the simpler Redirect directive?<\/strong> <code>Redirect<\/code> (and <code>RedirectMatch<\/code>) is a simpler, more limited directive from <code>mod_alias<\/code> that handles basic path-based redirects without the pattern-matching power of <code>mod_rewrite<\/code>. <code>RewriteRule<\/code>, used throughout this guide, supports conditional logic via <code>RewriteCond<\/code>, regex capture groups, and far more complex matching \u2014 which is why it&#8217;s the standard choice for domain-level redirects that need to preserve paths or match multiple conditions.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p class=\"wp-block-paragraph\">If you have any questions about this setup or run into an issue not covered here, feel free to reach out to us at <a href=\"https:\/\/pheonixsolutions.com\/\">Pheonix Solutions<\/a> \u2014 we&#8217;re happy to help.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Related Articles:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/blog\/how-to-enable-htaccess-file-in-mac-os-x\/\" target=\"_blank\" rel=\"noreferrer noopener\">How to Enable htaccess file in Mac OS X<\/a><\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/pheonixsolutions.com\/blog\/how-to-block-ips-via-htaccess-file\/\" target=\"_blank\" rel=\"noreferrer noopener\">How to block ips via .htaccess file ?<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction This guide explains how to set up domain redirection with .htaccess, covering the full process \u2014 from verifying Apache&#8217;s [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[1024],"tags":[365,278,366],"class_list":["post-1955","post","type-post","status-publish","format-standard","hentry","category-security","tag-htaccess","tag-apache","tag-redirection","psol-cat-security"],"jetpack_publicize_connections":[],"jetpack_shortlink":"https:\/\/wp.me\/phn2x7-vx","jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1955","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/comments?post=1955"}],"version-history":[{"count":1,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1955\/revisions"}],"predecessor-version":[{"id":11344,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/posts\/1955\/revisions\/11344"}],"wp:attachment":[{"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/media?parent=1955"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/categories?post=1955"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pheonixsolutions.com\/blog\/wp-json\/wp\/v2\/tags?post=1955"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}