When there is an Nginx proxy in front of your tomcat (or other app server), request.getRemoteAddr() or request.getRemoteHost() will return the IP of the Nginx server. And this is obviously not what we want.
To get this right, an extra HTTP Header will have to be added in Nginx, and our web app will have to be told to use it.
Nginx configuration
Make sure the header X-Real-IP is added in your proxy configuration:
location /webapp/ {
proxy_pass http://localhost:8080/webapp/;
proxy_set_header X-Real-IP $remote_addr;
}Like mentioned on the Nginx wiki.
Web app configuration
To make sure the web app uses this header, the ServletRequest object has to be wrapped in a custom HttpServletRequestWrapper, in which the methods getRemoteAddr and getRemoteHost are overridden. The wrapping itself is done in a Filter.
The wrapper class:
package be.lacerta.web;
import java.net.InetAddress;
import java.net.UnknownHostException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
class RealIPRequestWrapper extends HttpServletRequestWrapper {
public RealIPRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getRemoteAddr() {
String realIP = super.getHeader("X-Real-IP");
return realIP!=null?realIP:super.getRemoteAddr();
}
@Override
public String getRemoteHost() {
try {
return InetAddress.getByName(getRemoteAddr()).getHostName();
} catch (UnknownHostException e) {
return getRemoteAddr();
}
}
}
The filter class:
package be.lacerta.web;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class RealIPFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
chain.doFilter(new RealIPRequestWrapper((HttpServletRequest)request), response);
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}And add the filter in web.xml:
<filter>
<filter-name>RealIPFilter</filter-name>
<filter-class>be.lacerta.web.RealIPFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>RealIPFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
And we're good to go. Wherever request.getRemoteAddr() is used, our web app will be using the value from the X-Real-IP header, if available.


Add new comment