Search engines can group duplicate pages under a representative URL, but conflicting site signals make that choice less predictable. An accidental duplicate should send visitors and crawlers to one reachable preferred page while the canonical element, internal links, and sitemap all name the same address.

This method uses a static site served by Nginx on Ubuntu or Debian. The active HTTPS server block is www.example.com under /etc/nginx/sites-available, the document root is /var/www/www.example.com/public, the retired path is /products/widget-old, and the preferred path is /products/widget.

Use permanent consolidation only when the old page is a true duplicate with no distinct content, language, regional purpose, or required public use. The deployed checks can prove that the site's signals agree immediately, while Google's indexed URL Inspection result remains the authority for Google's later canonical choice.

Steps to fix a canonical URL conflict in Nginx:

  1. Create a backup archive of the active Nginx server block and static document root.
    $ sudo tar --create --gzip --file /root/www.example.com-canonical-backup.tar.gz /etc/nginx/sites-available/www.example.com /var/www/www.example.com/public

    The exact-path redirect retires the duplicate public address, and the archive preserves both routing and page content for rollback.

  2. Locate every static file that still contains the retired product path.
    $ grep --recursive --line-number --fixed-strings 'products/widget-old' /var/www/www.example.com/public
    /var/www/www.example.com/public/sitemap.xml:3:  <url><loc>https://www.example.com/products/widget-old</loc></url>
    /var/www/www.example.com/public/index.html:14:  <a href="/products/widget-old">Widget</a>
  3. Add the exact-path redirect inside the www.example.com HTTPS server block under /etc/nginx/sites-available.
    www.example.com
    location = /products/widget-old {
        return 301 https://www.example.com/products/widget;
    }

    The equals sign limits the redirect to the retired path, and the backup remains the rollback source until the deployed checks pass.

  4. Set one self-referencing canonical element in the head of products/widget.html below the document root /var/www/www.example.com/public.
    <link rel="canonical" href="https://www.example.com/products/widget">

    One absolute preferred URL in the HTML head avoids a second value from client-side code.
    Tool: Meta Tag Generator

  5. Replace every internal href value reported in the static document root with /products/widget.

    For the recorded match, change href="/products/widget-old" to href="/products/widget" in /var/www/www.example.com/public/index.html.

  6. Replace the retired loc entry in sitemap.xml under /var/www/www.example.com/public with the absolute preferred URL.
    sitemap.xml
    <url>
      <loc>https://www.example.com/products/widget</loc>
    </url>
  7. Test the complete Nginx configuration syntax.
    $ sudo nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
  8. Reload Nginx to activate the exact-path redirect.
    $ sudo nginx -s reload
  9. Confirm that the preferred page is reachable without an HTTP error.
    $ curl --fail --silent --show-error --output /dev/null --write-out 'HTTP %{http_code}\n' https://www.example.com/products/widget
    HTTP 200
  10. Confirm that the preferred page returns its own canonical element.
    $ curl --fail --silent --show-error https://www.example.com/products/widget
    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>Widget</title>
      <link rel="canonical" href="https://www.example.com/products/widget">
    </head>
    <body><h1>Widget</h1></body>
    </html>
  11. Search the static document root for any remaining retired product path.
    $ grep --recursive --line-number --fixed-strings 'products/widget-old' /var/www/www.example.com/public

    No output with exit status 1 means no matching internal link, canonical element, or sitemap entry remains; any printed line identifies a conflicting file.

  12. Confirm that the deployed sitemap contains only the preferred product URL.
    $ curl --fail --silent --show-error https://www.example.com/sitemap.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url><loc>https://www.example.com/products/widget</loc></url>
    </urlset>
  13. Confirm that the retired URL returns one direct permanent redirect to the preferred URL.
    $ curl --head https://www.example.com/products/widget-old
    HTTP/1.1 301 Moved Permanently
    Server: nginx
    Location: https://www.example.com/products/widget

    Google may take up to two weeks to reassess a duplicate cluster after the site changes. The indexed URL Inspection result exposes User-declared canonical and Google-selected canonical after recrawl; the live test cannot predict the final selection.
    Related: search-console-request-indexing

Share this guide