Testing Redirects with Curl

How to find and fix redirect issues at the source.

Tracing the source of a redirect can be difficult, especially for a redirect loop, but the curl command can make it much easier.

One of the most frustrating things to encounter is a redirect loop that you can’t trace back to it’s original, but if you plan your approaches well it can be very simple to maintain and fix.

Redirects Can Be Anywhere

Redirects can be set in many different ways, at almost every level of the load cycle for a website or page.

Needless to say it can be difficult to track down which one is the source of a redirect. But there are a few approach and tools you can use to make the process much easier.

Tracing Redirects

The first step to reverse tracing an HTTP redirect is to check the HTTP headers on the URL you’re having trouble with. To quickly see what status code and headers a URL returns you can use the -I option with the curl command.

curl -I https://kevinleary.net

This example redirects to www.kevinleary.net, so the response provided back in my Terminal looks like this:

HTTP/2 301 
date: Fri, 31 Oct 2025 15:08:05 GMT
content-type: text/html
location: https://www.kevinleary.net/
report-to: {"group":"cf-nel","max_age":604800,"endpoints":[{"url":"https://a.nel.cloudflare.com/report/v4?s=Grz7MNeBpICNsvGqhibhPJ3z96JkrzsXpHcoaR7YHwhyC7LG1WAzCGEHsvAwELq1MRr%2BiEZQRV2VBi0hTDCnVUJrpB%2FzkY82UflR"}]}
nel: {"report_to":"cf-nel","success_fraction":0.0,"max_age":604800}
cf-ray: 997410d679fc906b-BOS
cf-cache-status: MISS
server: cloudflare
x-xss-protection: 1; mode=block
strict-transport-security: max-age=15552000; includeSubDomains; preload
vary: Accept-Encoding
cf-apo-via: origin,resnok
expect-ct: max-age=86400, enforce
referrer-policy: strict-origin-when-cross-origin
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
speculation-rules: "/cdn-cgi/speculation"
set-cookie: __cf_bm=j6FdKrn.ZT08WKU9qzAhiotIXa2mf3jCyKec9iU7Xjs-1761923285-1.0.1.1-9uRQ62OqOR6ElydfVBar27SivfUU7f_GHp.sUpIuR6D7ouSQajEwDZ6Ms8D8lD6WWedfT4NO8djrQJ6fuvXzGYQ8LD5iXwgHruGLjnV6FZE; HttpOnly; SameSite=None; Secure; Path=/; Domain=kevinleary.net; Expires=Fri, 31 Oct 2025 15:38:05 GMT

In this response the most important lines are:

One missing line though is the X-Redirect-By, which is usually only available for PHP/server redirects. When it’s there it’s very useful because it’s basically a note/reminder/hint of where the redirect originated from.

For WordPress websites it will identify built-in WordPress redirects like those added with rel_canonical as:

Follow Redirects & Show Each Step

Follow redirects automatically and display each response along the way.

curl -IL https://example.com

Limit Redirects (Prevent Infinite Loops)

Stop following redirects after a specific number to detect loops.

curl -IL --max-redirs 5 https://example.com

Show Response Time for Each Redirect

Measure how long each redirect takes to complete.

curl -ILw "%{time_total}s - %{url_effective}\n" https://example.com

Verbose Redirect Tracing

See both the request and response headers for full transparency.

curl -ILv https://example.com

Basic Redirect Chain Analysis

Display the entire redirect path from start to finish.

curl -IL https://example.com/old-page

Complete Request/Response Flow

Save the detailed trace of all redirects and responses to a log file.

curl -ILv --trace-ascii trace.log https://example.com

Custom Headers to Identify Requests

Add a custom header (like a fake user agent) to help identify your test requests.

curl -IL -H "User-Agent: Redirect-Tracer" https://example.com

Check Specific HTTP Methods

Simulate different types of requests like POST or GET to see how they’re redirected.

curl -IL -X POST https://example.com

WordPress Redirects

Detect if WordPress is redirecting a post or page due to permalink or canonical changes.

curl -IL https://yoursite.com/sample-page

Server-Level Redirects (Nginx/Apache)

Identify redirects caused by web server configuration, not the app.

curl -IL https://example.com

Infinite Redirect Loop

Catch redirect loops where a site keeps bouncing between URLs.

curl -IL --max-redirs 10 https://problematic-site.com

Mixed Content Issues

Find redirects that accidentally downgrade from HTTPS to HTTP.

curl -IL https://example.com

Automated Redirect Chain Analyzer

Run a quick script to print each redirect and the status code.

#!/bin/bash
analyze_redirects() {
    local url=$1
    echo "=== Redirect Chain for $url ==="
    curl -ILs -w "%{http_code} - %{url_effective}\n" "$url" | \
    grep -E "HTTP|Location" | \
    sed 's/HTTP\/[0-9.]* //'
}
analyze_redirects "https://example.com"

Detailed Header Analysis Script

Log all key headers to see where and how each redirect happens.

#!/bin/bash
detailed_trace() {
    local url=$1
    echo "=== Detailed Trace for $url ==="
    curl -ILv "$url" 2>&1 | \
    grep -E "^(<|>) (HTTP|GET|Host|Location|Server|X-)"
}

Combine Tools for Deep Diagnosis

Use DNS + redirect + timing tests to isolate where issues start.

dig example.com
curl -IL https://example.com
curl -w "Total time: %{time_total}s\n" -o /dev/null -s https://example.com

Test Multiple URLs at Once

Loop through several URLs to check their redirect behavior quickly.

urls=("https://site1.com" "https://site2.com" "https://site3.com")
for url in "${urls[@]}"; do
    echo "Checking $url"
    curl -ILs --max-redirs 3 "$url" | head -5
    echo "---"
done

Monitor Redirect Changes Over Time

Compare redirects between runs to catch unexpected changes.

curl -IL https://example.com > redirect_snapshot.txt
curl -IL https://example.com | diff redirect_snapshot.txt -

Key Takeaways

Conclusion

Redirects are an unavoidable part of website management—whether for SEO, site migrations, or protocol enforcement. However, because they can originate from anywhere in the stack—from a Cloudflare worker rule down to a line of JavaScript—they often turn into invisible performance killers or infinite loops.

The key to solving these issues is visibility. By moving away from the browser, which often masks the underlying mechanics with caching and auto-loading, and moving toward terminal tools like curl, you gain granular control over the diagnosis.

Remember that a redirect loop is rarely a single error; it is usually a conflict between two layers of your stack (e.g., your Nginx server forcing HTTPS while your WordPress database requests HTTP). By systematically using flags like -I to isolate headers and -L to trace chains, you can pinpoint exactly which layer is mishandling the request.

Citations