You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker化Next.js+NestJS应用获取真实客户端IP(替代Nginx容器IP)

解决Docker化Next.js 13 + NestJS的真实客户端IP传递问题

环境与问题概述

我已将Next.js 13(前端)和NestJS(API)Docker化,使用nginx-proxy做反向代理,对应的docker-compose.yml配置如下:

api:
  image: gidgud/my:api
  container_name: api
  ports:
    - '6900:6999'
  networks:
    - mynetwork
  environment:
    - VIRTUAL_HOST=api.mywebsite.com
    - VIRTUAL_PORT=6999

web:
  image: gidgud/my:web
  container_name: web
  expose:
    - '3000'
  networks:
    - mynetwork
  depends_on:
    - api
  environment:
    - VIRTUAL_HOST=www.mywebsite.com,mywebsite.com
    - VIRTUAL_PORT=3000

nginx-proxy:
  image: 'nginxproxy/nginx-proxy:latest'
  container_name: 'nginx-proxy'
  volumes:
    - 'html:/usr/share/nginx/html'
    - 'dhparam:/etc/nginx/dhparam'
    - 'vhost:/etc/nginx/vhost.d'
    - 'certs:/etc/nginx/certs'
    - 'conf:/etc/nginx/conf.d'
    - '/var/run/docker.sock:/tmp/docker.sock:ro'
    - './custom_proxy.conf:/etc/nginx/conf.d/custom_proxy.conf'
  depends_on:
    - web
    - api
  networks:
    - mynetwork
  ports:
    - '80:80'
    - '443:443'

networks:
  mynetwork:
    name: my_network
    external: true

当前前端通过VM IP+API暴露端口请求接口(尝试api.mywebsite.com时Next.js服务器超时,暂用此方式),请求先经Next.js rewrites转发。核心问题:

  • API仅能收到nginx-proxy容器IP,无法获取真实客户端IP;
  • Next.js服务器组件请求API时,API收到的是Docker网络默认网关IP;
  • Vercel部署的非Docker站点请求API时可正常获取真实IP,问题出在Docker/Next.js配置。

解决方案

1. 确保nginx-proxy正确传递客户端IP头

检查挂载的custom_proxy.conf,添加以下配置,确保转发请求时携带真实客户端IP相关头信息:

# custom_proxy.conf
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Real-IP $remote_addr;

nginx-proxy默认会自动处理VIRTUAL_HOST的反向代理配置,但自定义配置需确保不覆盖这些头信息,否则会丢失客户端IP。

2. Next.js配置:传递客户端IP到API

客户端请求(经rewrites转发)

在next.config.js中配置rewrites时,改用Docker内部容器名访问API(同网络下直接用api:6999,解决之前的超时问题),同时保留客户端请求头:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  async rewrites() {
    return [
      {
        source: '/api/:path*',
        destination: 'http://api:6999/:path*',
        headers: {
          'X-Forwarded-For': '$request.headers.x-forwarded-for',
          'X-Real-IP': '$request.headers.x-real-ip',
        },
      },
    ];
  },
};

module.exports = nextConfig;

服务器组件请求(Server Components)

在服务器组件中调用API时,手动从Next.js请求对象中提取客户端IP相关头,并传递给API请求:

// app/api/[...path]/route.ts
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
  // 获取客户端IP相关头
  const forwardedFor = request.headers.get('x-forwarded-for');
  const realIp = request.headers.get('x-real-ip');

  // 调用NestJS API时传递头信息
  const apiResponse = await fetch('http://api:6999' + request.nextUrl.pathname, {
    headers: {
      ...(forwardedFor && { 'X-Forwarded-For': forwardedFor }),
      ...(realIp && { 'X-Real-IP': realIp }),
    },
  });

  return new Response(await apiResponse.text(), {
    status: apiResponse.status,
    headers: apiResponse.headers,
  });
}

3. NestJS配置:信任反向代理并提取真实IP

在NestJS的main.ts中配置信任反向代理来源,让框架从X-Forwarded-For头中提取真实IP:

// main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ExpressAdapter } from '@nestjs/platform-express';
import * as express from 'express';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, new ExpressAdapter());
  
  // 信任Docker默认网络网段(根据实际mynetwork网段调整)
  app.set('trust proxy', '172.16.0.0/12');
  
  // 配置CORS,允许前端域名并放行IP相关头
  app.enableCors({
    origin: ['https://www.mywebsite.com', 'https://mywebsite.com'],
    credentials: true,
    allowedHeaders: ['X-Forwarded-For', 'X-Real-IP', 'Content-Type'],
  });

  await app.listen(6999);
}
bootstrap();

之后在NestJS控制器中,即可通过request.ip获取真实客户端IP:

// app.controller.ts
import { Controller, Get, Req } from '@nestjs/common';
import { Request } from 'express';

@Controller()
export class AppController {
  @Get()
  getHello(@Req() req: Request): string {
    console.log('真实客户端IP:', req.ip);
    return 'Hello World!';
  }
}

4. 优化Docker配置(可选)

改用Docker内部网络访问API后,可移除api服务的宿主机端口映射,避免不必要的外部暴露:

api:
  image: gidgud/my:api
  container_name: api
  # 移除ports映射,仅内部网络访问
  networks:
    - mynetwork
  environment:
    - VIRTUAL_HOST=api.mywebsite.com
    - VIRTUAL_PORT=6999

内容的提问来源于stack exchange,提问作者gidgud

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 00:55:22