Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

req.url and req.nextUrl Show Docker Container IP/Port Instead of Real Host #65568

Open
muradsofi opened this issue May 9, 2024 · 3 comments
Open
Labels
bug Issue was opened via the bug report template. Middleware Related to Next.js Middleware. Pages Router Related to Pages Router. Runtime Related to Node.js or Edge Runtime with Next.js.

Comments

@muradsofi
Copy link

muradsofi commented May 9, 2024

Link to the code that reproduces this issue

https://github.com/muradsofi/next-13.5.5-req-issue-demo

To Reproduce

  1. Clone the demo repository.

    git clone https://github.com/muradsofi/next-13.5.5-req-issue-demo

  2. Build and run the Docker container using the provided Dockerfile.

    a) Build the Docker image

    docker build -t monorepo-demo -f apps/demo/Dockerfile .

    b) Run the Docker container:

    docker run -p 3002:3000 monorepo-demo

  3. Access the application in your browser at http://localhost:3002.

  4. Log req.url and req.nextUrl in any API route or middleware.

    export default function handler(req, res) { console.log('req.url:', req.url); console.log('req.nextUrl:', req.nextUrl); res.status(200).json({ message: 'Check logs for req.url and req.nextUrl values' }); }

  5. Observe the logs to see that req.url and req.nextUrl display the Docker container's IP address and port. (Observation: Even if you run the app on port 3002, you will get port 3000 in req.url.)

  6. In the deployed environment, the hostname is displayed as localhost with port docker port 3002.

Current vs. Expected behavior

Current Behavior: req.url and req.nextUrl display the Docker container’s IP address and port.
Expected Behavior: req.url and req.nextUrl should display the actual host URL.

Provide environment information

Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.1.0: Mon Oct  9 21:28:45 PDT 2023; root:xnu-10002.41.9~6/RELEASE_ARM64_T6020
Binaries:
  Node: 18.17.0
  npm: 9.6.7
  Yarn: 1.22.22
  pnpm: 8.14.3
Relevant Packages:
  next: 13.5.6
  eslint-config-next: 13.4.12
  react: 18.2.0
  react-dom: 18.2.0
  typescript: 5.1.6
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Middleware, Pages Router, Runtime

Which stage(s) are affected? (Select all that apply)

next start (local), Other (Deployed)

Additional context

Deployment Platform: Docker
Issue Started After: Updating to Next.js ^13.5.5

@muradsofi muradsofi added the bug Issue was opened via the bug report template. label May 9, 2024
@github-actions github-actions bot added Middleware Related to Next.js Middleware. Pages Router Related to Pages Router. Runtime Related to Node.js or Edge Runtime with Next.js. labels May 9, 2024
@gg3orgiev

This comment has been minimized.

@muradsofi
Copy link
Author

muradsofi commented Aug 28, 2024

While this approach might be useful right now, I personally prefer the default behavior in Next.js:

// TODO: This file is a temporary solution to fix URL generation issues in Dockerized environments.
// The custom CloneableURL class and getRequestUrl function are workarounds until this Next.js issue is resolved:
// https://github.com/vercel/next.js/issues/54450
// Once it's fixed, consider removing this file and using the standard Next.js URL handling methods.

import getConfig from 'next/config';
import { NextRequest } from 'next/server';

/**
 * A class that extends the native URL class to include a clone method.
 * It allows duplicating the URL instance while preserving all properties.
 */
class CloneableURL extends URL {
	/**
	 * Creates a new CloneableURL instance with the same properties as the current one.
	 * @returns {CloneableURL} A new CloneableURL instance.
	 */
	clone(): CloneableURL {
		return new CloneableURL(this.href); // Creates a clone of the URL using its href
	}
}

/**
 * Generates a full URL using the request headers and the NextRequest object.
 * This ensures the URL is accurately reconstructed in environments where headers might be modified by proxies or load balancers.
 *
 * @param {NextRequest} req - The Next.js server request object.
 * @returns {CloneableURL} - The full URL constructed from either the environment variable or the request headers.
 */
export function getRequestUrl(req: NextRequest): CloneableURL {
	const { publicRuntimeConfig } = getConfig() || {};
	// eslint-disable-next-line turbo/no-undeclared-env-vars
	const BASE_URL = process.env.BASE_URL || publicRuntimeConfig?.BASE_URL || null;

	// Get 'x-forwarded-host' header if available, or fallback to 'host' or req.nextUrl.host
	const hostHeader = req.headers.get('x-forwarded-host') || req.headers.get('host') || req.nextUrl.host;

	// Determine the protocol from 'X-Forwarded-Proto' header or use req.nextUrl.protocol by default
	const protocol = req.headers.get('x-forwarded-proto')
		? `${req.headers.get('x-forwarded-proto')}:`
		: req.nextUrl.protocol;

	// Create baseURL: use BASE_URL if available, otherwise construct it using protocol and hostHeader
	const baseURL = BASE_URL || `${protocol}//${hostHeader}`;

	// Construct the full URL using baseURL, pathname, and search parameters from req.nextUrl
	const fullUrlString = `${baseURL}${req.nextUrl.pathname}${req.nextUrl.search}`;

	// Return a new CloneableURL object
	return new CloneableURL(fullUrlString);
}

@muradsofi
Copy link
Author

Linked to this issue #54450

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Issue was opened via the bug report template. Middleware Related to Next.js Middleware. Pages Router Related to Pages Router. Runtime Related to Node.js or Edge Runtime with Next.js.
Projects
None yet
Development

No branches or pull requests

2 participants