Apache behind NAT: Returns wrong IP address

This question is not actually FreeBSD specific, but more about Apache.

I have a strange setup: A server at home, which is usually not reachable from the outside world (inbound connections are blocked, both at the DSL modem, and using pf on the server's external ethernet interface). On an internal network, it runs a variety of servers, including a web server that's reachable normally on port 80 and port 443. Say for example my server is called internal.example.com, then inside our household I can browse "https://internal.example.com", and there is a lot of good stuff (including CGI scripts that help with system administration and equipment operation). A lot of that stuff is confidential or worse, which is the reason why the server is usually unreachable. So far so good.

Turns out that occasionally I actually do need to access some web content from the outside. Not a big problem: I can configure the DSL modem to tunnel and translate a few ports: take port 443 on the outside (public network) and translate it to port 8443 inside. Then I configure apache with a separate VirtualHost section for "*:8443", which is restricted: served out of a directory with only a few (safe) files, no CGI scripts, no soft links, no directory listing, no index.html, and so on. As long as you use this to directly go to a single file, it works good: On the outside world, you can go to "https://internal.example.com/test.html" (no port number, goes directly to port 443), and see that file.

The problem is: For some reason, the apache server returns to the web client that it is serving things on port 8443. So if you try to reload the same page, or follow a link, it won't work: The web browser has updated to link to be to "https://internal.example.com:8443/test.html", and that port number doesn't work on the outside world.

The root cause of the problem is: The apache server thinks (correctly, from its viewpoint) that it is serving port 8443. The web browser outside thinks (correctly, from its viewpoint) that the pages are being served on port 443. The apache server is smart enough to append 8443, perhaps via redirects or via decorating links, but from the client's viewpoint that's incorrect.

I vaguely remember that there is a setting you can put into the apache configuration file to override the host name and port number that the server identifies itself as. But I can't find it, neither in example files, nor by a quick reading of the (huge) documentation, nor in examples on the web. Am I being blind?

Details, if it matters: FreeBSD 11.0-RELEASE with the stock apache24.
 
This question is not actually FreeBSD specific, but more about Apache.

I have a strange setup: A server at home, which is usually not reachable from the outside world (inbound connections are blocked, both at the DSL modem, and using pf on the server's external ethernet interface). On an internal network, it runs a variety of servers, including a web server that's reachable normally on port 80 and port 443. Say for example my server is called internal.example.com, then inside our household I can browse "https://internal.example.com", and there is a lot of good stuff (including CGI scripts that help with system administration and equipment operation). A lot of that stuff is confidential or worse, which is the reason why the server is usually unreachable. So far so good.

Turns out that occasionally I actually do need to access some web content from the outside. Not a big problem: I can configure the DSL modem to tunnel and translate a few ports: take port 443 on the outside (public network) and translate it to port 8443 inside. Then I configure apache with a separate VirtualHost section for "*:8443", which is restricted: served out of a directory with only a few (safe) files, no CGI scripts, no soft links, no directory listing, no index.html, and so on. As long as you use this to directly go to a single file, it works good: On the outside world, you can go to "https://internal.example.com/test.html" (no port number, goes directly to port 443), and see that file.

The problem is: For some reason, the apache server returns to the web client that it is serving things on port 8443. So if you try to reload the same page, or follow a link, it won't work: The web browser has updated to link to be to "https://internal.example.com:8443/test.html", and that port number doesn't work on the outside world.

The root cause of the problem is: The apache server thinks (correctly, from its viewpoint) that it is serving port 8443. The web browser outside thinks (correctly, from its viewpoint) that the pages are being served on port 443. The apache server is smart enough to append 8443, perhaps via redirects or via decorating links, but from the client's viewpoint that's incorrect.

I vaguely remember that there is a setting you can put into the apache configuration file to override the host name and port number that the server identifies itself as. But I can't find it, neither in example files, nor by a quick reading of the (huge) documentation, nor in examples on the web. Am I being blind?

Details, if it matters: FreeBSD 11.0-RELEASE with the stock apache24.

You can fix it with mod_rewrite I believe. I think there is a lightweight option as well but I can't remember it right now.

I use virtualhosts at home all listening on port 80 and port 443.

thus http://internal.example.com/ only replies to IP addresses from my internal network while https://external.example.com/ goes through NAT.

Internally to the server http://internal.example.com/external/ is the same set of files as https://external.example.com/ except you have to authenticate when using the example URL.
 
The problem is: For some reason, the apache server returns to the web client that it is serving things on port 8443. So if you try to reload the same page, or follow a link, it won't work: The web browser has updated to link to be to "https://internal.example.com:8443/test.html", and that port number doesn't work on the outside world.

Create a new virtual host listening on port 443 and do the NAT on your router on a different port or just use 443 again.
 
take port 443 on the outside (public network) and translate it to port 8443 inside.
Simple solution, redirect to port 443 instead of 8443 and configure authentication correctly (no authentication required when source is on the local network).
 
Why not redirect from the outside to port 443? Because port 443 is already in use for internal use. And the content served for outside is entirely different from the inside content: Different web server directories, different settings. Fundamentally, I'm pretending that I have two different web servers, one serving the internal network (using ports 80 and 443), and one the world.

But now as I'm explaining this, I'm starting to think the right answer is not to play games with strange port numbers (because NAT'ing is inherently difficult, when protocols transport port numbers, like http does). Instead, I should probably use different IP addresses for the internal and external servers; that's probably the standard technique for having multiple servers on a single machine.

I started reading the documentation for mod_rewrite, but its complete generality by rewriting everything using regular expressions caused my head to explode. I'll have a calming glass of warm chocolate milk, and try reading it again.
 
Why not redirect from the outside to port 443? Because port 443 is already in use for internal use. And the content served for outside is entirely different from the inside content: Different web server directories, different settings. Fundamentally, I'm pretending that I have two different web servers, one serving the internal network (using ports 80 and 443), and one the world.

But now as I'm explaining this, I'm starting to think the right answer is not to play games with strange port numbers (because NAT'ing is inherently difficult, when protocols transport port numbers, like http does). Instead, I should probably use different IP addresses for the internal and external servers; that's probably the standard technique for having multiple servers on a single machine.
You can have multiple sites on the same IP address and port: https://httpd.apache.org/docs/2.4/vhosts/examples.html
 
The apache server is smart enough to append 8443, perhaps via redirects or via decorating links, but from the client's viewpoint that's incorrect.

I'm sure there's something else going on here. Apache doesn't care what port it runs on and should not be modifying content and adding port numbers into links being sent back to the client.
 
The apache server is smart enough to append 8443, perhaps via redirects or via decorating links, but from the client's viewpoint that's incorrect.
I'm sure there's something else going on here. Apache doesn't care what port it runs on and should not be modifying content and adding port numbers into links being sent back to the client.

usdmatt got to the point.

Perhaps Apache is generating for some reasons one of the Location or Content-Location response headers. These would be a way to tell the browser the actual location of a requested URI. ralphbsz, did you configure rewrite rules for URI manipulation, for example, in order to remove the .php and/or other extensions from the URI which the browser displays in the address bar to the user? Like many of these more geeky Apache configurations, this might cause unwanted side effects.
 
This evening I will read the documentation that SirDice proposed, and hunt down the hints that obsigna gave. Thanks for all the help!
 
Back
Top