Utilizing X-Forwarded-For in Serverside for Accurate Client IP Geolocation

Joo Hee Paige Kim
2 min readJul 31, 2024

--

2024.07.31

When working with Docker to run your frontend and backend services, you might encounter issues with geolocation based on client IPs. Specifically, if you use an API to determine the client’s country based on their IP address from the server side, such as in Next.js middleware.ts or route.ts, you may find that the client’s IP is reported as localhost in local environment and AWS Elastic IP addresses depends on your deployment setting.

To address this issue, you can use the X-Forwarded-For (XFF) header. The X-Forwarded-For header is an HTTP request header that helps identify the originating IP address of a client connecting to a web server through an HTTP proxy or load balancer.

What is X-Forwarded-For?

When a client makes a request to your web server, the request may pass through several proxies or load balancers. Each proxy or load balancer can modify the request, making it difficult for the web server to determine the client’s original IP address. The X-Forwarded-For header solves this problem by keeping track of the client’s original IP address as it passes through each intermediary.

Implementing X-Forwarded-For in Next.js

To utilize the X-Forwarded-For header in Next.js, especially when you request in server side.

// middleware.ts
async function getDefaultLocale(request: NextRequest): Promise<Locale> {
try {
const response = await serverAxiosInstance('/geoip-check/', {
headers: {
'x-forwarded-for': request.headers.get('x-forwarded-for'),
},
});
return response.data.country === 'KR' ? 'ko' : 'en';
} catch (e) {
console.error(e);
return 'en';
}
}

// axios.ts
import axios from 'axios';
import { API_BASE_URL, RELEASE_ENV, SERVER_SIDE_API_URL } from '@/utils/config';
import { cookies, headers } from 'next/headers';

const serverAxiosInstance = axios.create({
baseURL: RELEASE_ENV === 'development' ? `${SERVER_SIDE_API_URL}/api` : `${API_BASE_URL}/api`,
});

serverAxiosInstance.interceptors.request.use(
(config) => {
const forwardedFor = headers().get('x-forwarded-for');
const clientIP = forwardedFor?.split(',')[0] ?? '';
config.headers['x-forwarded-for'] = clientIP;
return config;
},
(error) => {
return Promise.reject(error);
},
);

Also need to update nginx.conf if you are using Nginx as a proxy server.

// nginx.conf
{
...
location / {
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}

location ~ ^/(admin|api) {
...
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

--

--

No responses yet