Web server behind NAT, how to listen for public IP address

7,598

Solution 1

No, you cannot pass through the original destination IP address after you have done NAT, at least not directly.

I'll use 192.0.2.0/24 as your outside IP block and 198.51.100.0/24 as your inside one (see RFC5737).

Some things you could do include:

  • NAT the target ports on each outside IP to a different set of ports on the inside IP. For instance, NAT 192.0.2.1:80 and 192.0.2.1:443 to 198.51.100.1:80 and 198.51.100.1:443, and then NAT 192.0.2.2:80 and 192.0.2.2:443 to 198.51.100.1:81 and 198.51.100.1:444. Configure the web server to listen on the differentiated ports for the appropriate services. Be sure to choose ports not in use for anything else and check your firewall settings.
  • Allocate additional inside IPs to the web server. For example, allocate the web server 198.51.100.1 and 198.51.100.2. NAT the appropriate outside IP/port pairs to the corresponding inside IP/port pairs (eg. 192.0.2.1 to 198.51.100.1, and 192.0.2.2 to 198.51.100.2). Direct nginx to bind the appropriate services to the appropriate inside IPs.

If you go with the latter solution, your environment will be simpler and more standards-compliant because you won't be dealing with unusual port numbers and port translation, but you will need to allocate multiple inside IPs to each webserver (I gather you have just one). Also, if you use the latter solution you can use 1:1 NAT.

That said, if you don't have any reason to put the web server behind a NAT at all (NAT is not a firewall), just listen on the outside IPs (doing that would require a topology change also).

Solution 2

It sounds like you want a different public IP address for each of the sites. That means that the firewall has to present the different public IP addresses. The firewall can then forward the requests to different IP addresses to the nginx server, or can forward those requests to different ports on the same IP address. You can then have the nginx server respond accordingly.

Exactly how you configure that depends on your firewall. For example, using iptables, you could do something like this in a script:

KINCAID=192.168.1.112
EXTIPJMN=50.60.70.80
iptables -t nat -A PREROUTING -d $EXTIPJMN -p tcp -i $EXT --dport 8081 -j DNAT --to-destination $KINCAID:8080

That would route requests coming on IP address EXTIPJMN (50.60.70.80) and port 8081 to your inside server at IP address KINCAID (192.168.1.112) and port 8080

It is possible to serve different sites from the same IP address even over https, and this is supported by most modern clients, but not all.

Share:
7,598

Related videos on Youtube

Matt Mombrea
Author by

Matt Mombrea

Updated on September 18, 2022

Comments

  • Matt Mombrea
    Matt Mombrea over 1 year

    I have a debian web server (nginx) running behind a firewall using NAT. The web server is hosting several sites that require SSL and their own IP address. I'd like to have the SSL sites listen to only their specific IP address and the shared sites listen only to the shared IP.

    Right now I am listening to a wildcard * for all domains which, I assume, means it's listening to a single LAN address and serving site content based on hostname and not IP address. I'd like to correct this.

    What is the proper course of action? Is it to create a 1:1 NAT for each IP address and add the LAN IPs to the network interface to listen for, then assign the LAN IP's to specific domains? Or is there a better way? Is there any way to pass along the public IP and take action based on that? Thanks.

  • Falcon Momot
    Falcon Momot over 10 years
    It's worth mentioning that TLS SNI also requires client-side support, and results in seemingly bizzare and suspicious errors when it is not present.
  • nachbar
    nachbar over 10 years
    You are correct about TLS SNI: I corrected my answer - I said supported by most modern servers, but meant most modern clients.
  • Matt Mombrea
    Matt Mombrea over 10 years
    Thanks, I'm going to try and sort out option #2. I've been trying to go that direction all along but for some reason nginx only responds on the wildcard directive in my setup. I'll create a separate question for that.