Claude-skill-inception nextjs-request-url-proxy-redirect
install
source · Clone the upstream repo
git clone https://github.com/strataga/claude-skill-inception
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/strataga/claude-skill-inception "$T" && mkdir -p ~/.claude/skills && cp -r "$T/nextjs-request-url-proxy-redirect" ~/.claude/skills/strataga-claude-skill-inception-nextjs-request-url-proxy-redirect && rm -rf "$T"
manifest:
nextjs-request-url-proxy-redirect/SKILL.mdsource content
Next.js request.url Returns Internal Proxy URL on Containerized Platforms
Problem
When deploying Next.js to Railway, Vercel, or similar containerized platforms,
request.url in Edge runtime or API routes can return the internal proxy URL
(e.g., http://localhost:8080) instead of the public domain (e.g., https://example.com).
This causes
NextResponse.redirect(new URL(path, request.url)) to redirect users
to the internal URL, which fails with ERR_CONNECTION_REFUSED.
Context / Trigger Conditions
- Symptom: Browser shows
toERR_CONNECTION_REFUSED
or similarlocalhost:8080 - Console errors:
followed by connection refusedFailed to fetch RSC payload - Network tab: Shows 307 redirect to
https://localhost:8080/... - Environment: Next.js deployed to Railway, Vercel, Docker, or any reverse proxy setup
- Code pattern: Using
for redirectsnew URL('/path', request.url)
Solution
Replace
request.url with an environment variable for the public URL:
// Before (broken on containerized platforms): return NextResponse.redirect( new URL(`/not-found?code=${shortCode}`, request.url) ); // After (works everywhere): const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "https://example.com"; return NextResponse.redirect( new URL(`/not-found?code=${shortCode}`, baseUrl) );
For reusable code, create a helper:
const getBaseUrl = () => process.env.NEXT_PUBLIC_APP_URL || "https://example.com";
Verification
- Deploy the fix to production
- Visit a URL that triggers the redirect
- Verify the redirect goes to the public domain, not localhost
- Check browser console for absence of
ERR_CONNECTION_REFUSED
Example
File:
app/[shortCode]/route.ts
// Add helper at module level const getBaseUrl = () => process.env.NEXT_PUBLIC_APP_URL || "https://clicktowa.com"; export async function GET(request: NextRequest, { params }) { const { shortCode } = await params; const baseUrl = getBaseUrl(); // ... lookup logic ... if (!link) { // Use baseUrl instead of request.url return NextResponse.redirect( new URL(`/not-found?code=${encodeURIComponent(shortCode)}`, baseUrl) ); } // ... rest of handler }
Notes
-
This issue occurs because containerized platforms route traffic through internal load balancers/proxies. The
reflects the internal connection, not the original public request.request.url -
Some platforms set headers like
orX-Forwarded-Host
, but these aren't automatically used byX-Original-Host
.request.url -
The
prefix makes the variable available in both client and server code, which is appropriate for the public URL.NEXT_PUBLIC_ -
Always provide a sensible fallback in case the env var isn't set.
-
This also affects
in some configurations—always prefer explicit environment variables for public URLs.request.headers.get('host')
Related Patterns
- Auth callback URLs should also use
NEXT_PUBLIC_APP_URL - OAuth redirect URIs need the public domain
- Sitemap and robots.txt generation should use the env var
- OpenGraph and canonical URLs should use the env var