When I use a load balancer on the default port (http/80, https/443) that routes request to an httpd instance listening on a non default port, httpd builds redirects that include the load balancer's hostname but the port of the httpd virtual host. UseCanonicalName is turned off. I've looked at the code in vhost.c that handles the Host header and the code in core.c that builds the absolute URI used for the Location header in redirects and my understanding is that when the absolute URI is computed the absence of a port in the Host header of the request is treated as if there was no Host header at all. r->parsed_uri.port_str ? r->parsed_uri.port : ... And parsed_uri.port_str is only set if there is a port in the Host header. A workaround that I've come to use in multiple installations is to set the ServerName with the default port inside the <VirtualHost> since this sets the SERVER_PORT. I've reproduced the issue with a very basic setup. Listen 4080 <VirtualHost *:4080> </VirtualHost> And an empty test/ folder in the DocumentRoot. When I call with an explicit port in the Host header everything works as expected (I can supply any hostname it is echoed back in the Location header) GET /test HTTP/1.1 Host: whatever:80 HTTP/1.1 301 Moved Permanently Date: Fri, 14 Jun 2019 20:35:07 GMT Server: Apache/2.5.1-dev (Unix) Location: http://whatever/test/ When I call without a port in the Host header the Location header in the response contains the server port but the hostname part of the Host header is echoed back GET /test HTTP/1.1 Host: whatever HTTP/1.1 301 Moved Permanently Date: Fri, 14 Jun 2019 20:35:09 GMT Server: Apache/2.5.1-dev (Unix) Location: http://whatever:4080/test/ I've reproduced the issue on httpd 2.2.8, 2.4.37 and a build from a fresh checkout from 2.5-HEAD.
Since `ServerName foo` and not the ugly `ServerName foo:80` is sufficient I'm not sure it's even worth documenting. Maybe a warning about not omitting the ServerName completely from a virtualhost under e.g. https://httpd.apache.org/docs/2.4/mod/core.html#usecanonicalphysicalport
When you specify the Listen port (or any other non standard port) in the ServerName directive you also get the same issue, requests with a port in the Host header will get valid responses since the port from the Host header will be echoed back, but requests without a port in the Host header will have the server port in the response. The workaround works fine but requires that you set the ServerName to a value that either does not contain a port or contains the default port, I just felt it at least needed to be reported since I have been using it for some time.