301 redirect check: chains, loops and the road to HTTPS

· 8 min read

Every redirect costs an extra request; every unnecessary one costs load time, crawl budget and a slice of link equity. Yet on many websites, chains of http, www and trailing slash build up over the years without anyone planning them. This article shows how to check 301 redirects, which status code belongs where, and how to write the rules for nginx, Apache and Caddy so that every variant reaches the target in a single hop.

Why redirects deserve attention

A redirect is a response with a 3xx status code and a Location header, and browsers and crawlers then request the URL named there. Once is harmless. On many websites, though, it happens three or four times in a row: http://example.com redirects to https://example.com, which redirects to https://www.example.com, which redirects to https://www.example.com/, which finally redirects to the homepage with a language prefix. Each hop is a separate round trip with DNS lookup, TLS handshake and waiting time.

For search engines there is a second aspect: redirects carry signals. A link to the old URL is supposed to count for the new one, and a crawled URL is supposed to update the index. With a direct 301 that works reliably. With a long chain, the wrong status code or a target that itself returns 404, that connection is lost.

301, 302, 307 and 308: which status code goes where

The status code tells the client whether the move is permanent or temporary. That decides whether Google adopts the new URL into its index and whether browsers cache the redirect.

  • 301 Moved Permanently: permanent. Search engines index the target URL and pass on the signals of the old one. The default for http to https, www to non-www and for a domain move.
  • 302 Found: temporary. The old URL stays in the index and the target does not become canonical. Right for maintenance pages or a seasonal campaign, wrong for anything that is meant to stay.
  • 307 Temporary Redirect: like 302, but the HTTP method is preserved, so a POST stays a POST. Chrome also displays the HSTS redirect, which never reaches the server, as an internal 307 in its developer tools.
  • 308 Permanent Redirect: like 301 with the method preserved. Useful for APIs; for websites that only see GET requests it makes no difference compared to 301.

Google treats 301 and 308 as equivalent and eventually treats a long-standing 302 as permanent too. Do not rely on that: if you move a page for good, send a 301. Many hosting panels and CMS plugins default to 302, which is why the status code belongs in every check.

One canonical variant: http, www and trailing slash

Every website is reachable under at least four addresses: with and without https, with and without www. Add trailing slashes, mixed case or an index.html and you quickly have eight variants of the same page. Exactly one of them is the canonical address; every other variant has to point at it with a single 301.

Whether to use www or not is a matter of taste with no SEO impact. What matters is that you decide, reflect the decision consistently in the sitemap, canonical tags, internal links and Search Console, and do not serve the other variant with a 200 as well. Two reachable variants mean duplicate content and split signals. The trailing slash follows the same rule: /imprint and /imprint/ are two URLs to Google.

The redirect from http to https is the only one where there is no choice. It belongs on every hostname the domain serves, including www. If it is missing there, that variant stays reachable unencrypted and HSTS never kicks in.

Redirect chains and redirect loops

A redirect chain forms when the target of a redirect is itself a redirect. The typical case is three rules maintained in three places: the hosting provider redirects http to https, the server configuration redirects www to non-www, and the CMS appends the trailing slash. Each rule is correct on its own; together they make three hops.

Googlebot follows up to ten redirects in a chain and gives up after that; the target URL is then not crawled and Search Console reports a redirect error. Well before that limit, every hop burns crawl budget, delays the indexing of new content and weakens the association between links and the destination page.

The rule is therefore simple: every redirect points directly at the final URL. If a page moved from /old to /new and later to /newer, you change the first rule to /newer instead of adding a second one. When canonicalizing, you combine http, www and trailing slash into one rule. The one exception is the HSTS preload list: it requires http://example.com to redirect to https://example.com first. If www is your canonical variant, two hops are unavoidable there, but no more than that.

A redirect loop is the special case where the chain returns to its starting point. The classic example is a CMS that redirects to https while running behind a proxy or CDN that talks to the server over http: the CMS always sees http, redirects, the proxy delivers http again, forever. Browsers show ERR_TOO_MANY_REDIRECTS and the site is unreachable. The fix is to honour the proxy's X-Forwarded-Proto header or to perform the redirect at the proxy only.

Redirects for a domain move

When a site changes its domain, redirects are the main tool for keeping rankings. The crucial point is that every old URL sends a 301 to its exact counterpart on the new domain, not everything to the new homepage. Google treats a blanket redirect to the homepage as a soft 404, and the signals of the individual pages are lost.

  1. Collect every URL of the old domain from the sitemap, server logs and Search Console.
  2. Define the target on the new domain for each URL. If the structure stays the same, one rule with $request_uri is enough; otherwise you need a mapping table.
  3. Resolve any existing chains on the old domain first, then redirect the old domain to the new one with a 301 in a single hop.
  4. Keep renewing the certificate of the old domain for as long as the redirect runs. A 301 over https only works with a valid certificate.
  5. Submit the change of address in Search Console and keep the old domain redirecting for at least a year, preferably permanently.
# nginx: redirect the old domain 1:1 to the new one
server {
    listen 80;
    listen 443 ssl;
    server_name old-domain.com www.old-domain.com;
    ssl_certificate     /etc/letsencrypt/live/old-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/old-domain.com/privkey.pem;
    return 301 https://new-domain.com$request_uri;
}

Configuration for nginx, Apache and Caddy

The examples redirect http and www to https://example.com in a single step and keep path and query string intact. In nginx the redirect belongs in its own server block, not in an if construct inside the main block. In Apache the rule lives in .htaccess or, better, directly in the VirtualHost. Caddy redirects http to https automatically, so you only need to canonicalize the www variant.

# nginx: http (both hosts) and https://www to https://example.com in one hop
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name www.example.com;
    ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    return 301 https://example.com$request_uri;
}

# Apache (.htaccess or VirtualHost, mod_rewrite)
RewriteEngine On
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]

# Caddy (Caddyfile), http to https is handled by Caddy itself
www.example.com {
    redir https://example.com{uri} permanent
}

example.com {
    root * /var/www/example
    file_server
}

The HTTPS block for www.example.com needs a certificate that covers www, otherwise visitors see a certificate warning before the redirect even runs. In Apache, %{HTTPS} off does not do what you expect behind a proxy; replace the condition there with %{HTTP:X-Forwarded-Proto} !https.

Common mistakes

Most problems are not caused by one wrong rule but by several correct rules in different places: at the hosting provider, in the web server, in the CMS and in the CDN. These patterns show up in almost every check.

  • A chain of http, https, www and trailing slash: three or four hops because each rule is maintained somewhere else. Consolidate the rules in one place.
  • A loop caused by a proxy or CDN: the server only ever sees http and redirects endlessly. Honour X-Forwarded-Proto or move the redirect to the proxy.
  • A redirect to a 404: the rule points at a URL that no longer exists. To Google that is a deleted page, and the signals of the old URL expire.
  • 302 instead of 301 for permanent changes: the old URL stays in the index and the new one never becomes canonical.
  • Mixed case: /Imprint and /imprint are different resources on Linux servers and two URLs to Google. Link consistently in lowercase and normalize with a rule.
  • Redirects via meta refresh or JavaScript: Google does not treat either as a clean 301, and crawlers without JavaScript see no redirect at all. Always redirect server-side.
  • Path or query string gets lost: the rule redirects to the bare domain without $request_uri, and every deep link ends up on the homepage.

Checking redirects: redirect checker and curl

The browser is a poor tool for checking: it follows the chain so quickly that you only see the result, it caches 301 responses, and it shows the HSTS redirect as an internal 307. With curl you see every hop individually:

curl -sIL http://www.example.com/imprint | grep -iE '^(HTTP|location)'

The DomainWarn Redirect Checker does the same without a terminal: it shows the complete chain with the status code of every hop, the final URL and the number of hops, and it flags chains, loops and targets that do not answer with 200. Use it on every entry variant: http and https, with and without www, with and without trailing slash, and at least one deep URL with a query string.

Repeat the check after every hosting migration, every CMS update and every change to the CDN or proxy. Those are exactly the places where new hops appear without anyone adding them on purpose.

Frequently asked questions

How many redirects are acceptable?
One. Every entry URL should land on the canonical address with exactly one 301. Two hops are acceptable when the HSTS preload list requires the redirect to stay on the same host. Anything beyond that is a chain you should shorten, even though Google technically follows up to ten hops.
Do I lose link equity with a 301?
Google stated in 2016 that redirects no longer lose PageRank. In practice, a direct redirect to a topically matching page is still the only setup where rankings carry over reliably. Chains, redirects to the homepage and redirects to a 404 lose signals regardless of what the status code says.
How long do I need to keep the redirect after a domain move?
At least a year, so that Google transfers all signals and you have time to update backlinks. Permanently is better: old links in forums, directories and emails would otherwise stop working at some point, and an abandoned domain can be registered by a third party once it expires.
Check now

Free 301 redirect check: every hop with status code and response time, from http to https, from www to non-www. Detects redirect chains, loops and 302s.

Redirects change without anyone noticing: a hosting migration adds a hop, a plugin switches 301 to 302, a relaunch leaves the target pointing at nothing. DomainWarn monitors the redirects of all client domains, measures chain length and target status, and alerts you to every change in destination or status code before rankings suffer.

Monitor this domain continuously14-day free trial, no credit card.

More guides