When running multiple Nginx containers in Docker with different host port mappings, you'll encounter a common issue with automatic redirects. The container correctly serves content when accessed with the proper URL structure, but fails to maintain the host port during redirects.
# Typical symptom:
# Request to: http://localhost:8080/docs
# Redirects to: http://localhost/docs/ (port is lost!)
Nginx's automatic redirect behavior for trailing slashes doesn't inherently account for port mappings in container environments. The server constructs redirect URLs based on:
- The
listen
directive port (container port 80) - Default host header interpretation
Here are three approaches to solve this:
1. Using absolute_redirect Directive
server {
listen 80;
server_name localhost;
absolute_redirect off;
root /var/www;
location /docs {
try_files $uri $uri/ =404;
}
}
2. Proper Server Name Configuration
server {
listen 80;
server_name $host; # Preserves original host header
port_in_redirect off;
location /docs {
if (-d $request_filename) {
rewrite [^/]$ $scheme://$http_host$uri/ permanent;
}
}
}
3. Custom Rewrite Rule
server {
listen 80;
location /docs {
if (-d $request_filename) {
return 301 $scheme://$http_host:$server_port$uri/;
}
}
}
For production environments, combine these techniques:
server {
listen 80;
server_name _;
absolute_redirect off;
port_in_redirect off;
location / {
root /var/www;
try_files $uri $uri/ @trailingslash;
}
location @trailingslash {
if (-d $request_filename) {
return 301 $scheme://$host:$server_port$uri/;
}
}
}
Use this curl command to verify:
curl -v http://localhost:8080/docs 2>&1 | grep Location
# Should show: Location: http://localhost:8080/docs/
When using docker-compose, ensure proper network configuration:
version: '3'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf
- ./html:/var/www
When running multiple Nginx containers in Docker with different host port mappings, you'll encounter redirect issues when Nginx automatically adds trailing slashes. The redirect loses the original host port information.
Consider this common scenario:
docker run -p 8080:80 nginx-container
When accessing http://localhost:8080/docs
, Nginx's automatic slash-appending redirect sends you to http://localhost/docs/
instead of preserving the original port 8080.
The usual Nginx directives don't solve this:
server_name_in_redirect off;
port_in_redirect off;
These only work when the server is directly accessible, not behind port-mapped containers.
Here's a configuration that properly handles port-mapped redirects:
server {
listen 80;
server_name localhost;
# Force correct host and port in redirects
absolute_redirect off;
location /docs {
if (-d $request_filename) {
rewrite [^/]$ $scheme://$http_host$uri/ permanent;
}
# Your normal config here
}
}
For more complex setups, consider these additional methods:
# Method 1: Use proxy_set_header in upstream
proxy_set_header Host $host:$server_port;
# Method 2: Environment variable injection
location / {
set $frontend_port $ENV{FRONTEND_PORT};
if (-d $request_filename) {
return 301 $scheme://$host:$frontend_port$uri/;
}
}
Use this curl command to verify redirect behavior:
curl -v http://localhost:8080/docs
Look for the Location header in the 301 response - it should include your host port.
Remember that Docker port mapping creates a networking abstraction layer. The solution needs to bridge the gap between container-internal and external networking perspectives. Always test redirects with both trailing slash and non-trailing slash URLs.