0

TL;DR: How can I get the client ip connecting to a remotely hosted VPS to be the IP that gets forwarded/natted, via iptables, to a game server running at my house?

I have a Rust game server that I am hosting at my house. I want that to be public, however I don't necessarily want to give out my IP address to everyone. So I am renting a small VPS that intend to use basically as a reverse proxy. I am currently using nginx to forward traffic over a clinet-server VPN, which works fine. However, on the game server every players IP is that of the tunnel address of the VPS, not the actual client IP. I tried using proxy_pass $remote_addr:28015 transparancy; proxy_responses 0 in my nginx config, no change. So i then switched to doing it via iptables.

I can get it work 99% the way I want, doing exactly this:

sysctl net.ipv4.ip_forward=1
iptables -t nat -A PREROUTING -p tcp --dport 28015 -j NAT --to-destination my_ip:28015
iptables -t nat -A PREROUTING -p udp --dport 28015 -j NAT --to-destination my_ip:28015
iptables -t nat -A PREROUTING -p tcp --dport 28016 -j NAT --to-destination my_ip:28016
iptables -t nat -A PREROUTING -p udp --dport 28016 -j NAT --to-destination my_ip:28016
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -A FORWARD -p tcp -d my_ip --dport 28015 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -p ucp -d my_ip --dport 28015 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
ufw disable
ufw enable
vps reboot \

What this does is basically the same as nginx, where it works fine, but everyone just has the public ip of the VPS(note, that the LAN and Public ip address of the VPS are the same). If I omit the masqurade, it does not work.

Some info on the setup:
VPS has a single interface: eth0
VPS is running Ubuntu 20.04
At my house, modem is in passthru mode to pfsesne. On pfsense i have port forwarding rules to pass 28015/28016 tcp/udp to gameserver.

Sidenote: I'm not sure why nginx did not work for this. It was almost as if nginx was doing nothing with the proxy_pass $remote_addr directive.

1 Answer 1

0

You cannot do this with IPTables. For bi-directional packet forwarding to work properly, the source IP address of the packets sent from your VPS must contain the VPS address. Otherwise the reply packets wouldn't be sent to the VPS, which forwards them to clients.

You need layer 7 protocol support to relay the original IP address to your application. In HTTP / HTTPS, this is done as follows:

  1. nginx reverse proxy works on your VPS.
  2. The reverse proxy adds header X-Forwarded-For: <clientip> to request it sends to origin servver.
  3. Origin server reads the header and uses it as client IP address instead of using the IP address associated with the TCP socket.

Another possibility is to use SOCKS proxy between the VPS and origin server. SOCKS proxy encapsulates the traffic from client, and adds additional metadata such as client IP address.

9
  • The game server is all UDP traffic. Does X-Forwarded-For work for UDP streams as well?
    – AAron
    Nov 18, 2021 at 15:26
  • If you have some layer 7 protocol implemented that has HTTP like semantics with headers etc., then yes. But if you implement a custom application protocol on top of UDP, then that protocol needs to support this mechanism and you also need to implement the proxying for that protocol. Since you mentioned using nginx proxy_pass, I assumed you were using HTTP like protocol. Nov 18, 2021 at 15:29
  • I mean, as far as I know it's bog standard UDP, the only thing im doing with it is redirecting it elsewhere. In my nginx.conf , after the closing bracket for the default server block, I have this: stream { server { listen 28015 udp; proxy_pass my_ip:28015; proxy_bind $remote_addr:$remote_port transparent; proxy_responses 0; } }
    – AAron
    Nov 18, 2021 at 15:36
  • OK, then that is the bytestream proxy that nginx offers. That is a layer 4 relay concept, and it doesn't have the functionality you are looking for. To me it seems your only options are to switch to work over HTTP,/HTTPS or to implement functionality in your UDP protocol that allows a custom proxy to add the client IP to the protocol messages. You also need to implement the custom proxy. However, since this is a common functionality, there are likely protocol frameworks that have this functionality. Nov 18, 2021 at 15:40
  • Does nginx have the functionality I'm looking for?
    – AAron
    Nov 18, 2021 at 15:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.