{"id":3908,"date":"2026-01-01T16:54:06","date_gmt":"2026-01-01T13:54:06","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/seo-safe-url-structure-changes-with-301-redirects-in-htaccess-and-nginx\/"},"modified":"2026-01-01T16:54:06","modified_gmt":"2026-01-01T13:54:06","slug":"seo-safe-url-structure-changes-with-301-redirects-in-htaccess-and-nginx","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/seo-safe-url-structure-changes-with-301-redirects-in-htaccess-and-nginx\/","title":{"rendered":"SEO\u2011Safe URL Structure Changes with 301 Redirects in .htaccess and Nginx"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>At dchost.com we see the same pattern over and over: a website grows, the content team wants cleaner URLs, the dev team wants a new framework, or the marketing team wants to re\u2011organise categories. Technically it is just a few rewrite rules, but from Google\u2019s perspective you are reshuffling the entire map of your site. Done carefully, you keep rankings and even gain performance; done carelessly, you ship weeks of 404s, duplicate pages and lost organic traffic.<\/p>\n<p>This article focuses on the practical middle ground: how to change URL structures in a way that is safe for SEO, using clean 301 redirects on both Apache (.htaccess) and Nginx. We will look at the SEO rules that really matter, the most common redirect patterns (HTTP\u2192HTTPS, non\u2011www\u2192www, trailing slash, moved folders, removed file extensions), and how to translate them into working configuration examples. We will also cover how to test, debug and clean up once your changes go live, so you can evolve your URL structure without fearing a ranking crash.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Why_URL_Structure_Changes_Matter_for_SEO\"><span class=\"toc_number toc_depth_1\">1<\/span> Why URL Structure Changes Matter for SEO<\/a><\/li><li><a href=\"#Planning_an_SEOSafe_URL_Migration\"><span class=\"toc_number toc_depth_1\">2<\/span> Planning an SEO\u2011Safe URL Migration<\/a><ul><li><a href=\"#Step_1_Inventory_your_current_URLs\"><span class=\"toc_number toc_depth_2\">2.1<\/span> Step 1: Inventory your current URLs<\/a><\/li><li><a href=\"#Step_2_Define_the_new_structure_and_mapping_table\"><span class=\"toc_number toc_depth_2\">2.2<\/span> Step 2: Define the new structure and mapping table<\/a><\/li><li><a href=\"#Step_3_Decide_on_your_canonical_rules\"><span class=\"toc_number toc_depth_2\">2.3<\/span> Step 3: Decide on your canonical rules<\/a><\/li><li><a href=\"#Step_4_Test_on_staging_if_you_can\"><span class=\"toc_number toc_depth_2\">2.4<\/span> Step 4: Test on staging if you can<\/a><\/li><\/ul><\/li><li><a href=\"#301_Redirect_Patterns_in_Apache_htaccess\"><span class=\"toc_number toc_depth_1\">3<\/span> 301 Redirect Patterns in Apache .htaccess<\/a><ul><li><a href=\"#Basic_onetoone_301_redirect\"><span class=\"toc_number toc_depth_2\">3.1<\/span> Basic one\u2011to\u2011one 301 redirect<\/a><\/li><li><a href=\"#HTTP_to_HTTPS_redirect_global\"><span class=\"toc_number toc_depth_2\">3.2<\/span> HTTP to HTTPS redirect (global)<\/a><\/li><li><a href=\"#Nonwww_to_www_or_the_reverse\"><span class=\"toc_number toc_depth_2\">3.3<\/span> Non\u2011www to www (or the reverse)<\/a><\/li><li><a href=\"#Combining_HTTPS_and_host_canonicalisation\"><span class=\"toc_number toc_depth_2\">3.4<\/span> Combining HTTPS and host canonicalisation<\/a><\/li><li><a href=\"#Removing_or_adding_a_trailing_slash\"><span class=\"toc_number toc_depth_2\">3.5<\/span> Removing or adding a trailing slash<\/a><\/li><li><a href=\"#Moving_a_whole_folder_category_change\"><span class=\"toc_number toc_depth_2\">3.6<\/span> Moving a whole folder (category change)<\/a><\/li><li><a href=\"#Removing_file_extensions_php_html\"><span class=\"toc_number toc_depth_2\">3.7<\/span> Removing file extensions (.php, .html)<\/a><\/li><li><a href=\"#Handling_query_strings_safely\"><span class=\"toc_number toc_depth_2\">3.8<\/span> Handling query strings safely<\/a><\/li><li><a href=\"#When_to_use_410_Gone_instead_of_301\"><span class=\"toc_number toc_depth_2\">3.9<\/span> When to use 410 (Gone) instead of 301<\/a><\/li><\/ul><\/li><li><a href=\"#301_Redirect_Patterns_in_Nginx\"><span class=\"toc_number toc_depth_1\">4<\/span> 301 Redirect Patterns in Nginx<\/a><ul><li><a href=\"#Basics_return_vs_rewrite\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Basics: return vs rewrite<\/a><\/li><li><a href=\"#HTTP_to_HTTPS_redirect_server\"><span class=\"toc_number toc_depth_2\">4.2<\/span> HTTP to HTTPS redirect server<\/a><\/li><li><a href=\"#Nonwww_to_www_or_reverse_on_Nginx\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Non\u2011www to www (or reverse) on Nginx<\/a><\/li><li><a href=\"#Folder_move_with_regex\"><span class=\"toc_number toc_depth_2\">4.4<\/span> Folder move with regex<\/a><\/li><li><a href=\"#Adding_or_removing_trailing_slash\"><span class=\"toc_number toc_depth_2\">4.5<\/span> Adding or removing trailing slash<\/a><\/li><li><a href=\"#Removing_php_extension_in_Nginx\"><span class=\"toc_number toc_depth_2\">4.6<\/span> Removing .php extension in Nginx<\/a><\/li><li><a href=\"#Redirecting_individual_pages_clean_syntax\"><span class=\"toc_number toc_depth_2\">4.7<\/span> Redirecting individual pages (clean syntax)<\/a><\/li><li><a href=\"#Handling_query_strings_in_Nginx_redirects\"><span class=\"toc_number toc_depth_2\">4.8<\/span> Handling query strings in Nginx redirects<\/a><\/li><\/ul><\/li><li><a href=\"#Testing_Monitoring_and_Cleaning_Up_After_the_Change\"><span class=\"toc_number toc_depth_1\">5<\/span> Testing, Monitoring and Cleaning Up After the Change<\/a><ul><li><a href=\"#How_to_test_your_redirects\"><span class=\"toc_number toc_depth_2\">5.1<\/span> How to test your redirects<\/a><\/li><li><a href=\"#Update_internal_links_canonicals_and_sitemaps\"><span class=\"toc_number toc_depth_2\">5.2<\/span> Update internal links, canonicals and sitemaps<\/a><\/li><li><a href=\"#Watch_logs_and_Search_Console\"><span class=\"toc_number toc_depth_2\">5.3<\/span> Watch logs and Search Console<\/a><\/li><li><a href=\"#Special_case_changing_domain_names\"><span class=\"toc_number toc_depth_2\">5.4<\/span> Special case: changing domain names<\/a><\/li><\/ul><\/li><li><a href=\"#Wrapping_Up_Practical_Checklist_and_Next_Steps\"><span class=\"toc_number toc_depth_1\">6<\/span> Wrapping Up: Practical Checklist and Next Steps<\/a><\/li><\/ul><\/div>\n<h2><span id=\"Why_URL_Structure_Changes_Matter_for_SEO\">Why URL Structure Changes Matter for SEO<\/span><\/h2>\n<p>Search engines don\u2019t care about your specific folder names, but they care a lot about consistency, crawlability and signals. When you change URL structures, you are changing the primary keys of your content in Google\u2019s index. That can be positive or negative depending on how you handle redirects and internal links.<\/p>\n<p>From an SEO and hosting perspective, three things matter most:<\/p>\n<ul>\n<li><strong>Correct status codes:<\/strong> Use 301 (permanent) when a URL has a new home, 302 only for temporary moves, and 404\/410 when content is truly gone. If you need a refresher, we explain this in detail in our guide on <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-durum-kodlari-seo-ve-hosting-icin-301-302-404-410-ve-5xx-rehberi\/\">what HTTP status codes mean for SEO and hosting<\/a>.<\/li>\n<li><strong>Avoiding redirect chains and loops:<\/strong> Multiple hops slow users down and dilute signals. Google will follow some redirects, but you don\u2019t want \/old \u2192 \/older \u2192 \/newest if you can go \/old \u2192 \/new directly.<\/li>\n<li><strong>Maintaining one canonical URL per piece of content:<\/strong> www vs non\u2011www, HTTP vs HTTPS, trailing slash vs no trailing slash \u2013 every ambiguity must be normalised.<\/li>\n<\/ul>\n<p>When you build your redirects with those principles in mind, structure changes become a low\u2011risk, routine operation instead of a stressful \u201cdon\u2019t touch anything\u201d moment.<\/p>\n<h2><span id=\"Planning_an_SEOSafe_URL_Migration\">Planning an SEO\u2011Safe URL Migration<\/span><\/h2>\n<p>Before we touch .htaccess or Nginx, we need a plan. Most SEO damage does not come from the syntax of redirect rules, but from missing or incomplete mapping.<\/p>\n<h3><span id=\"Step_1_Inventory_your_current_URLs\">Step 1: Inventory your current URLs<\/span><\/h3>\n<p>Export as many existing URLs as you can:<\/p>\n<ul>\n<li>From your CMS (posts, pages, categories, products)<\/li>\n<li>From your web server logs (high\u2011traffic URLs over the last 6\u201312 months)<\/li>\n<li>From tools like Search Console and crawlers<\/li>\n<\/ul>\n<p>Prioritise URLs that already receive organic traffic or backlinks. These deserve pixel\u2011perfect 301 mappings.<\/p>\n<h3><span id=\"Step_2_Define_the_new_structure_and_mapping_table\">Step 2: Define the new structure and mapping table<\/span><\/h3>\n<p>Create a spreadsheet with at least two columns:<\/p>\n<ul>\n<li><strong>Old URL path<\/strong> (e.g. \/blog\/2022\/09\/seo-tips.html)<\/li>\n<li><strong>New URL path<\/strong> (e.g. \/blog\/seo-tips\/)<\/li>\n<\/ul>\n<p>Whenever possible, use predictable patterns instead of one\u2011off rules. For example, if all your blog posts will move from \/blog\/YYYY\/MM\/slug\/ to \/blog\/slug\/, you can cover hundreds of URLs with a single regex redirect \u2013 we will show examples for both Apache and Nginx.<\/p>\n<h3><span id=\"Step_3_Decide_on_your_canonical_rules\">Step 3: Decide on your canonical rules<\/span><\/h3>\n<p>Decide once and apply everywhere:<\/p>\n<ul>\n<li>Will you use <strong>www<\/strong> or <strong>bare domain<\/strong> as canonical?<\/li>\n<li>Will directories end <strong>with or without trailing slash<\/strong>?<\/li>\n<li>Will you show <strong>file extensions<\/strong> in URLs (.php, .html) or hide them?<\/li>\n<li>Are you enforcing <strong>HTTPS<\/strong> everywhere?<\/li>\n<\/ul>\n<p>Once you decide, your redirect configuration should funnel every variant into a single canonical version (for example, http:\/\/example.com\/blog to https:\/\/www.example.com\/blog\/).<\/p>\n<h3><span id=\"Step_4_Test_on_staging_if_you_can\">Step 4: Test on staging if you can<\/span><\/h3>\n<p>If your hosting setup includes dev or staging environments (for example on a separate <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a> or subdomain), deploy your URL changes there first. That is the safest way to catch redirect loops and broken patterns before they affect real users. If you do not yet have a multi\u2011environment workflow, our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/gelistirme-test-ve-canli-ortamlar-icin-hosting-mimarisi\/\">hosting architecture for dev, staging and production environments<\/a> is a good place to start.<\/p>\n<h2><span id=\"301_Redirect_Patterns_in_Apache_htaccess\">301 Redirect Patterns in Apache .htaccess<\/span><\/h2>\n<p>On shared hosting and many cPanel setups, Apache\u2019s .htaccess file is where most URL rewriting happens. The rules live inside your web root (often public_html). Below are commonly used, SEO\u2011safe patterns.<\/p>\n<h3><span id=\"Basic_onetoone_301_redirect\">Basic one\u2011to\u2011one 301 redirect<\/span><\/h3>\n<p>For a small number of changed URLs, keep it explicit and readable.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Old article to new article\nRedirect 301 \/blog\/2022\/09\/seo-tips.html \/blog\/seo-tips\/\n\n# Old product to new product\nRedirect 301 \/shop\/product-123.html \/store\/new-product-slug\/\n<\/code><\/pre>\n<p><strong>Notes:<\/strong><\/p>\n<ul>\n<li>Use relative paths; Apache will prepend your domain automatically.<\/li>\n<li>Place specific Redirect lines before generic regex rules to avoid conflicts.<\/li>\n<\/ul>\n<h3><span id=\"HTTP_to_HTTPS_redirect_global\">HTTP to HTTPS redirect (global)<\/span><\/h3>\n<p>If you are migrating to HTTPS (and you should), you want a single 301 from every HTTP URL to its HTTPS twin. For the hosting side of a full certificate move, we have a detailed walkthrough in <a href=\"https:\/\/www.dchost.com\/blog\/en\/httpden-httpse-gecis-rehberi-301-yonlendirme-hsts-ve-seoyu-korumak\/\">our full HTTPS migration guide with 301 redirects, HSTS and SEO safeguards<\/a>. The core .htaccess rule looks like this:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Force HTTPS\nRewriteCond %{HTTPS} off\nRewriteRule ^(.*)$ https:\/\/%{HTTP_HOST}%{REQUEST_URI} [L,R=301]\n<\/code><\/pre>\n<p>This preserves the host (www or non\u2011www) and the path\/query untouched, only changing the scheme to https:\/\/.<\/p>\n<h3><span id=\"Nonwww_to_www_or_the_reverse\">Non\u2011www to www (or the reverse)<\/span><\/h3>\n<p>Pick one as canonical. Example: redirect non\u2011www to www.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Redirect example.com to www.example.com\nRewriteCond %{HTTP_HOST} !^www.example.com$ [NC]\nRewriteRule ^(.*)$ https:\/\/www.example.com\/$1 [L,R=301]\n<\/code><\/pre>\n<p>To go the other way (www \u2192 non\u2011www), invert the condition and target host:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Redirect www.example.com to example.com\nRewriteCond %{HTTP_HOST} ^www.(.+)$ [NC]\nRewriteRule ^(.*)$ https:\/\/%1\/$1 [L,R=301]\n<\/code><\/pre>\n<h3><span id=\"Combining_HTTPS_and_host_canonicalisation\">Combining HTTPS and host canonicalisation<\/span><\/h3>\n<p>To keep things simple and avoid extra hops, combine HTTPS and host rules into a single redirect, sending everything straight to your chosen canonical form:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Force HTTPS and www together\nRewriteCond %{HTTPS} off [OR]\nRewriteCond %{HTTP_HOST} !^www.example.com$ [NC]\nRewriteRule ^(.*)$ https:\/\/www.example.com\/$1 [L,R=301]\n<\/code><\/pre>\n<p>This means http:\/\/example.com\/page, http:\/\/www.example.com\/page and https:\/\/example.com\/page all become https:\/\/www.example.com\/page in one hop.<\/p>\n<h3><span id=\"Removing_or_adding_a_trailing_slash\">Removing or adding a trailing slash<\/span><\/h3>\n<p>Again, choose one canonical style. Example: enforce trailing slash on directory\u2011like URLs, but keep extensions unchanged.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Add trailing slash if missing and no file extension\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_URI} !.[a-zA-Z0-9]{2,6}$\nRewriteRule ^(.+[^\/])$ \/$1\/ [L,R=301]\n<\/code><\/pre>\n<p>To <strong>remove<\/strong> trailing slashes instead, flip the logic:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Remove trailing slash from non-root URLs\nRewriteCond %{REQUEST_URI} .+\/$\nRewriteRule ^(.+)\/$ \/$1 [L,R=301]\n<\/code><\/pre>\n<h3><span id=\"Moving_a_whole_folder_category_change\">Moving a whole folder (category change)<\/span><\/h3>\n<p>Suppose \/blog\/ is being renamed to \/articles\/ and all posts keep the same slug.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Move \/blog\/slug\/ to \/articles\/slug\/\nRewriteRule ^blog\/(.*)$ \/articles\/$1 [L,R=301]\n<\/code><\/pre>\n<p>This pattern is powerful. Be sure there is no overlap with other rules, and that \/articles\/ is fully ready to serve equivalent content.<\/p>\n<h3><span id=\"Removing_file_extensions_php_html\">Removing file extensions (.php, .html)<\/span><\/h3>\n<p>Hiding file extensions is common when modernising old PHP sites. Here\u2019s a two\u2011part approach:<\/p>\n<ol>\n<li>Rewrite extension\u2011less URL to internal PHP script (no redirect).<\/li>\n<li>Redirect old .php URLs to the extension\u2011less version (301).<\/li>\n<\/ol>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">RewriteEngine On\n\n# Internally serve \/page from \/page.php if it exists\nRewriteCond %{REQUEST_FILENAME} !-d\nRewriteCond %{REQUEST_FILENAME}.php -f\nRewriteRule ^(.+)$ $1.php [L]\n\n# Redirect \/page.php to \/page\nRewriteRule ^(.+).php$ \/$1 [L,R=301]\n<\/code><\/pre>\n<p>This way users and search engines end up on \/page, but your application still uses page.php behind the scenes.<\/p>\n<h3><span id=\"Handling_query_strings_safely\">Handling query strings safely<\/span><\/h3>\n<p>By default, Apache keeps the query string when you use Redirect or RewriteRule unless you explicitly change it. Example: redirect an old UTM\u2011heavy campaign URL to a clean landing page.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Redirect specific campaign URL ignoring its query string\nRewriteCond %{QUERY_STRING} (^|&amp;)utm_campaign=old-promo(&amp;|$)\nRewriteRule ^landing.php$ \/new-landing\/ [L,R=301,QSD]\n<\/code><\/pre>\n<p>The <strong>QSD<\/strong> flag (Query String Discard) drops the query string so \/new-landing\/ is clean.<\/p>\n<h3><span id=\"When_to_use_410_Gone_instead_of_301\">When to use 410 (Gone) instead of 301<\/span><\/h3>\n<p>Some URLs should simply die: outdated campaigns, thin content you intentionally removed, or spammy old pages. In those rare cases you can explicitly say the content is gone:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># URL permanently removed, no replacement\nRedirect 410 \/old-section\/bad-content.html\n<\/code><\/pre>\n<p>For more on deciding between 404, 410 and 301, again see our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/http-durum-kodlari-seo-ve-hosting-icin-301-302-404-410-ve-5xx-rehberi\/\">HTTP status codes and their SEO impact<\/a>.<\/p>\n<h2><span id=\"301_Redirect_Patterns_in_Nginx\">301 Redirect Patterns in Nginx<\/span><\/h2>\n<p>On VPS, <a href=\"https:\/\/www.dchost.com\/dedicated-server\">dedicated server<\/a>s and many high\u2011traffic WordPress or Laravel stacks, Nginx often sits in front (sometimes with PHP\u2011FPM or as a reverse proxy). Nginx does not use .htaccess; configuration lives in server blocks (typically under \/etc\/nginx\/sites-available\/). Changes require a reload, but performance and clarity are better.<\/p>\n<h3><span id=\"Basics_return_vs_rewrite\">Basics: return vs rewrite<\/span><\/h3>\n<ul>\n<li><strong>return 301 \u2026<\/strong> is preferred for simple, one\u2011to\u2011one redirects and canonical rules: it is fast and easy to reason about.<\/li>\n<li><strong>rewrite \u2026<\/strong> is useful when you need regex captures and more advanced logic, but should be used carefully.<\/li>\n<\/ul>\n<h3><span id=\"HTTP_to_HTTPS_redirect_server\">HTTP to HTTPS redirect server<\/span><\/h3>\n<p>Common pattern: one server block for HTTP that only redirects, and another for HTTPS that serves content.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    listen 80;\n    listen [::]:80;\n    server_name example.com www.example.com;\n\n    return 301 https:\/\/$host$request_uri;\n}\n<\/code><\/pre>\n<p>This is the Nginx equivalent of the .htaccess HTTPS rule, but more efficient.<\/p>\n<h3><span id=\"Nonwww_to_www_or_reverse_on_Nginx\">Non\u2011www to www (or reverse) on Nginx<\/span><\/h3>\n<p>Example: enforce www.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\"># Redirect non-www to www\nserver {\n    listen 80;\n    listen [::]:80;\n    server_name example.com;\n\n    return 301 https:\/\/www.example.com$request_uri;\n}\n\n# Main www virtual host\nserver {\n    listen 443 ssl http2;\n    listen [::]:443 ssl http2;\n    server_name www.example.com;\n\n    # SSL config, root, etc...\n}\n<\/code><\/pre>\n<p>To enforce non\u2011www, swap the hostnames.<\/p>\n<h3><span id=\"Folder_move_with_regex\">Folder move with regex<\/span><\/h3>\n<p>Move everything from \/blog\/ to \/articles\/ while preserving the rest of the path.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    # ...\n\n    location ~* ^\/blog\/(.*)$ {\n        return 301 \/articles\/$1;\n    }\n\n    # other locations...\n}\n<\/code><\/pre>\n<p>Because we are using <strong>return 301<\/strong> with a captured group, the redirect is both fast and easy for crawlers to follow.<\/p>\n<h3><span id=\"Adding_or_removing_trailing_slash\">Adding or removing trailing slash<\/span><\/h3>\n<p>Example: enforce trailing slash, but leave files untouched.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    # ...\n\n    # Add trailing slash for paths without extension\n    location ~ ^(.+[^\/])$ {\n        if ($request_uri ~* &quot;.[a-z0-9]{2,6}$&quot;) {\n            break; # has extension, do nothing\n        }\n        return 301 $1\/;\n    }\n}\n<\/code><\/pre>\n<p>If you prefer to <strong>remove<\/strong> the trailing slash:<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    # ...\n\n    # Remove trailing slash from non-root URLs\n    location ~ ^(.+)\/$ {\n        return 301 $1;\n    }\n}\n<\/code><\/pre>\n<p>Be careful not to conflict with application\u2011level routing (e.g. frameworks that already normalise slashes). Always test these on staging first.<\/p>\n<h3><span id=\"Removing_php_extension_in_Nginx\">Removing .php extension in Nginx<\/span><\/h3>\n<p>As with Apache, we want users to see \/about while PHP executes about.php internally.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    listen 443 ssl http2;\n    server_name www.example.com;\n    root \/var\/www\/html;\n\n    # Redirect \/page.php to \/page\n    location ~ ^\/(.+).php$ {\n        return 301 \/$1;\n    }\n\n    # Try to serve \/page as \/page.php\n    location \/ {\n        try_files $uri $uri\/ $uri.php =404;\n    }\n\n    location ~ .php$ {\n        include fastcgi_params;\n        fastcgi_pass unix:\/run\/php\/php-fpm.sock;\n        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;\n    }\n}\n<\/code><\/pre>\n<p>The <strong>try_files<\/strong> directive handles internal rewrites without changing the URL in the browser.<\/p>\n<h3><span id=\"Redirecting_individual_pages_clean_syntax\">Redirecting individual pages (clean syntax)<\/span><\/h3>\n<p>For small sets of changed URLs where you do not need regex, keep it readable with exact locations:<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\">server {\n    # ...\n\n    location = \/blog\/2022\/09\/seo-tips.html {\n        return 301 \/blog\/seo-tips\/;\n    }\n\n    location = \/shop\/product-123.html {\n        return 301 \/store\/new-product-slug\/;\n    }\n}\n<\/code><\/pre>\n<p><strong>location =<\/strong> matches the path exactly, so there is no ambiguity.<\/p>\n<h3><span id=\"Handling_query_strings_in_Nginx_redirects\">Handling query strings in Nginx redirects<\/span><\/h3>\n<p>Nginx keeps the query string automatically when you use <code>$request_uri<\/code>. If you want to strip it, just omit it from your target.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># Preserve query string (default)\nreturn 301 https:\/\/www.example.com$request_uri;\n\n# Drop query string entirely\nreturn 301 https:\/\/www.example.com\/clean-landing\/;\n<\/code><\/pre>\n<p>To match specific query parameters, you can use <code>if ($arg_...)<\/code> carefully:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">if ($arg_utm_campaign = &quot;old-promo&quot;) {\n    return 301 \/new-landing\/;\n}\n<\/code><\/pre>\n<p>Nginx <code>if<\/code> has caveats when used inside <code>location<\/code>, so keep logic simple and test thoroughly.<\/p>\n<h2><span id=\"Testing_Monitoring_and_Cleaning_Up_After_the_Change\">Testing, Monitoring and Cleaning Up After the Change<\/span><\/h2>\n<p>Writing redirect rules is only half of the job. The rest is proving they behave as intended and updating all the surrounding SEO signals.<\/p>\n<h3><span id=\"How_to_test_your_redirects\">How to test your redirects<\/span><\/h3>\n<ul>\n<li><strong>Browser tests:<\/strong> Manually hit your top 20\u201350 old URLs, watch the address bar and status codes (use developer tools &gt; Network).<\/li>\n<li><strong>Command line:<\/strong> Use curl to see the exact response chain:<br \/>\n    <code>curl -I -L http:\/\/example.com\/old-url\/<\/code><\/li>\n<li><strong>Crawler:<\/strong> Run a small crawl (hundreds or thousands of URLs) to check for 404s, redirect loops and long chains.<\/li>\n<\/ul>\n<p>Fix any 302s where you meant 301, and collapse chains (A\u2192B\u2192C) into a single hop (A\u2192C) whenever you can.<\/p>\n<h3><span id=\"Update_internal_links_canonicals_and_sitemaps\">Update internal links, canonicals and sitemaps<\/span><\/h3>\n<p>Redirects are a safety net, not a permanent crutch. Once your new structure is live:<\/p>\n<ul>\n<li><strong>Update internal links<\/strong> in menus, body content and footers to use the new URLs directly.<\/li>\n<li>Ensure <strong>rel=&#8221;canonical&#8221;<\/strong> tags point to the canonical version (HTTPS, www\/non\u2011www, trailing slash policy).<\/li>\n<li>Refresh your XML sitemaps with only the new URLs. We explain this step\u2011by\u2011step in our guide to <a href=\"https:\/\/www.dchost.com\/blog\/en\/robots-txt-ve-sitemap-xml-dogru-kurulumu-adim-adim-seo-ve-hosting-rehberi\/\">setting up robots.txt and sitemap.xml correctly for SEO and hosting<\/a>.<\/li>\n<\/ul>\n<p>If you are also consolidating multiple domains (for example redirecting regional domains into one main site), coordinate your redirect rules with canonical tags and Hreflang. Our article on <a href=\"https:\/\/www.dchost.com\/blog\/en\/birden-fazla-alan-adini-ayni-siteye-yonlendirmek-seo-301-canonical-ve-park-alan-adi-stratejileri\/\">pointing multiple domains to one website with 301 redirects and canonical tags<\/a> dives into those patterns.<\/p>\n<h3><span id=\"Watch_logs_and_Search_Console\">Watch logs and Search Console<\/span><\/h3>\n<p>After deployment, your server logs are your best friend:<\/p>\n<ul>\n<li>Filter for <strong>404 responses<\/strong> and see which paths are still being requested. Decide whether each should get a 301 to an equivalent page or remain a 404\/410.<\/li>\n<li>Monitor <strong>5xx errors<\/strong> (500, 502, 504) that might indicate misconfiguration or loops.<\/li>\n<\/ul>\n<p>In Google Search Console, expect a short\u2011term spike in \u201cMoved\u201d and \u201cFound\u201d statuses as Google recrawls. Over a few weeks, old URLs should be gradually replaced by the new ones in index coverage and performance reports.<\/p>\n<h3><span id=\"Special_case_changing_domain_names\">Special case: changing domain names<\/span><\/h3>\n<p>If you are not just reshaping paths, but moving from one domain to another, the redirect rules are similar but the stakes are higher. You will want:<\/p>\n<ul>\n<li>A global 301 from every old\u2011domain URL to the matching new\u2011domain URL.<\/li>\n<li>Updated DNS, <a href=\"https:\/\/www.dchost.com\/ssl\">SSL certificate<\/a>s and email\/DNS records.<\/li>\n<li>Change of Address in Google Search Console.<\/li>\n<\/ul>\n<p>We have a dedicated walkthrough on <a href=\"https:\/\/www.dchost.com\/blog\/en\/alan-adi-degistirirken-seo-kaybetmemek\/\">how to change your domain without losing SEO<\/a>, including hosting\u2011side and DNS considerations.<\/p>\n<h2><span id=\"Wrapping_Up_Practical_Checklist_and_Next_Steps\">Wrapping Up: Practical Checklist and Next Steps<\/span><\/h2>\n<p>URL structure changes do not have to be scary. With a clear mapping of old to new paths, a handful of well\u2011tested 301 redirect patterns in .htaccess or Nginx, and a bit of log watching, you can evolve your site architecture without sacrificing hard\u2011earned rankings. The key is to treat every existing URL as an asset: either give it a clean new home with a 301, or consciously retire it with a 404\/410 instead of letting it break.<\/p>\n<p>From the hosting side, this is exactly the kind of work where a solid foundation helps. On shared hosting, that means .htaccess rules that are simple and predictable; on VPS, dedicated or colocation servers it means version\u2011controlled Nginx or Apache configs and a safe deployment workflow. If you are planning a larger redesign, replatform or domain change, combining the redirect patterns in this article with our <a href=\"https:\/\/www.dchost.com\/blog\/en\/yeni-web-sitesi-yayina-alirken-hosting-tarafinda-seo-ve-performans-kontrol-listesi\/\">new website launch checklist for hosting\u2011side SEO and performance<\/a> will give you a calm, step\u2011by\u2011step plan.<\/p>\n<p>And if you prefer not to worry about the low\u2011level details, our team at dchost.com can help you choose the right hosting stack \u2013 from classic shared hosting to VPS, dedicated servers or colocation \u2013 and configure redirects, SSL and DNS in a way that keeps both users and search engines happy.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>At dchost.com we see the same pattern over and over: a website grows, the content team wants cleaner URLs, the dev team wants a new framework, or the marketing team wants to re\u2011organise categories. Technically it is just a few rewrite rules, but from Google\u2019s perspective you are reshuffling the entire map of your site. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":3909,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-3908","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=3908"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/3908\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/3909"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=3908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=3908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=3908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}