<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[PaidHosting Dev Notes]]></title><description><![CDATA[PaidHosting Dev Notes]]></description><link>https://paidhosting.hashnode.dev</link><image><url>https://cdn.hashnode.com/uploads/logos/6ad08282949d175d0dfded82/71fa6189-6632-45bf-bd8e-751400635cf1.jpg</url><title>PaidHosting Dev Notes</title><link>https://paidhosting.hashnode.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Wed, 28 Oct 2026 09:21:33 GMT</lastBuildDate><atom:link href="https://paidhosting.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Moving from Apache to Nginx? Your .htaccess rules won't come with you]]></title><description><![CDATA[Moving from Apache to Nginx? Copy-ready HTTPS, www and AI bot blocking rules for Apache, Nginx, Caddy and Cloudflare, plus how to fix redirect chains.]]></description><link>https://paidhosting.hashnode.dev/moving-from-apache-to-nginx-your-htaccess-rules-won-t-come-with-you</link><guid isPermaLink="true">https://paidhosting.hashnode.dev/moving-from-apache-to-nginx-your-htaccess-rules-won-t-come-with-you</guid><category><![CDATA[nginx]]></category><category><![CDATA[apache]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[Devops]]></category><dc:creator><![CDATA[Jay Sullivan]]></dc:creator><pubDate>Thu, 15 Oct 2026 10:27:09 GMT</pubDate><content:encoded><![CDATA[<p>If you've ever moved a site from shared hosting to a VPS, you've probably found out the hard way that your <code>.htaccess</code> rules stopped working. Nginx ignores <code>.htaccess</code> completely, Caddy has its own syntax, and Cloudflare wants its rules in a dashboard.</p>
<p>Below are two jobs almost every site needs, written for all four, plus a quick check you can run on your redirect list today.</p>
<p>If you'd rather not copy anything by hand, our free <a href="https://www.paidhosting.com/htaccess-nginx-generator/">.htaccess, Nginx &amp; Caddy Rule Generator</a> writes all of these for you.</p>
<h2>1. Force HTTPS and drop www, in one redirect</h2>
<p>The goal: <code>http://www.example.com/page</code> goes straight to <code>https://example.com/page</code> in a single hop, not two.</p>
<p><strong>Apache / LiteSpeed (.htaccess)</strong></p>
<pre><code class="language-apache">RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,R=301]
</code></pre>
<p>The third condition captures the domain without <code>www.</code>, so one rule fixes both problems at once. Behind Cloudflare or another proxy, <code>%{HTTPS}</code> can read <code>off</code> even when the visitor is on HTTPS; use <code>RewriteCond %{HTTP:X-Forwarded-Proto} !https [OR]</code> instead.</p>
<p><strong>Nginx</strong></p>
<pre><code class="language-nginx">server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}
</code></pre>
<p>You also need a second <code>server</code> block for <code>https://www.example.com</code> that returns the same redirect, with your certificate on it. No <code>if</code>, no rewrite: a separate server block is the fastest and clearest way.</p>
<p><strong>Caddy</strong></p>
<pre><code class="language-caddy">www.example.com, http://www.example.com, http://example.com {
    redir https://example.com{uri} permanent
}
</code></pre>
<p>Caddy redirects HTTP to HTTPS on its own, so you only list the addresses that should land on the main one.</p>
<p><strong>Cloudflare</strong></p>
<p>No rule needed: turn on <strong>SSL/TLS &gt; Edge Certificates &gt; Always Use HTTPS</strong>, and create a redirect rule from the <strong>Redirect from WWW to root</strong> template under <strong>Rules</strong>.</p>
<h2>2. Block AI training crawlers</h2>
<p>The crawlers that collect training data identify themselves in the User-Agent. (List shortened here; the full, current list is in the generator.)</p>
<p><strong>Apache / LiteSpeed</strong></p>
<pre><code class="language-apache">RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (GPTBot|ClaudeBot|CCBot|Bytespider) [NC]
RewriteRule ^ - [F,L]
</code></pre>
<p><strong>Nginx</strong> (the <code>map</code> goes once inside <code>http {}</code>, the <code>if</code> inside your <code>server {}</code>)</p>
<pre><code class="language-nginx">map $http_user_agent $blocked_ua {
    default 0;
    "~*(GPTBot|ClaudeBot|CCBot|Bytespider)" 1;
}

server {
    # ...
    if ($blocked_ua) { return 403; }
}
</code></pre>
<p><strong>Caddy</strong></p>
<pre><code class="language-caddy">example.com {
    @ai_train header_regexp User-Agent "(?i)(GPTBot|ClaudeBot|CCBot|Bytespider)"
    respond @ai_train 403
}
</code></pre>
<p><strong>Cloudflare</strong> (Security &gt; Security rules &gt; Create rule &gt; Edit expression, action: Block)</p>
<pre><code class="language-plaintext">(lower(http.user_agent) contains "gptbot")
or (lower(http.user_agent) contains "claudebot")
or (lower(http.user_agent) contains "ccbot")
or (lower(http.user_agent) contains "bytespider")
</code></pre>
<p>Add the same names to <code>robots.txt</code> as well: well-behaved crawlers stop there, and the server rule catches the rest.</p>
<h2>3. The redirect-list mistake: chains</h2>
<p>After a few redesigns, a redirect list ends up like this:</p>
<pre><code class="language-plaintext">/old-page   /new-page
/2019/sale  /sale
/sale       /offers
</code></pre>
<p>A visitor to <code>/2019/sale</code> now takes two hops: to <code>/sale</code>, then to <code>/offers</code>. Search engines follow chains, but each hop is wasted time, and long chains get abandoned. Fix the list so every old URL points at its final address:</p>
<pre><code class="language-plaintext">/2019/sale  /offers
/sale       /offers
</code></pre>
<p>Worse is a loop (<code>/a → /b</code>, <code>/b → /a</code>), which redirects forever until the browser gives up. Check for both every time you add lines.</p>
<h2>Skip the copy-pasting</h2>
<p>We put all of this, and a lot more, into a free tool at <a href="https://www.paidhosting.com/">PaidHosting.com</a>: the <a href="https://www.paidhosting.com/htaccess-nginx-generator/">.htaccess, Nginx &amp; Caddy Rule Generator</a>. Flip the switches once and it writes matching rules for Apache, Nginx, Caddy and Cloudflare. It also fixes redirect chains and loops for you, splits AI crawlers into training and search bots, and gives you a share link to your exact setup.</p>
<p>Every output was tested on real Apache, Nginx, Caddy, LiteSpeed and Cloudflare setups before release, and the code is open source (MIT): <a href="https://github.com/PaidHost/server-rules-generator">https://github.com/PaidHost/server-rules-generator</a>. If something misbehaves on your server, open an issue and we'll fix it.</p>
]]></content:encoded></item></channel></rss>