0

I'm encountering a path rewriting problem when using Docker Compose with Nginx reverse proxy to deploy a Hugo blog. Requests to IP/Hugo-Blog/X/Y/Z are being redirected to IP/X/Y/Z instead of maintaining the /Hugo-Blog/ prefix, resulting in 404 errors.
However, when I try to access IP/Hugo-Blog/X/Y/Z/ directly(with a trailing slash), it works correctly.
The same Hugo structure works correctly on GitHub Pages at https://ri-nai.github.io/Hugo-Blog/.

Setup Details:

  1. Infrastructure: Tencent Cloud Server (Chinese cloud platform)
  2. Stack: Docker Compose + Nginx reverse proxy + Hugo static site

Configuration Files:

  1. docker-compose.yaml:
version: '3'
services:
  homepage: # Homepage Site, works fine
    ...
  blog:
    build: ./Hugo-Blog
    container_name: blog
    expose:
      - "80"
    restart: always

reverse-proxy: image: nginx:stable-alpine container_name: reverse-proxy volumes: - ./nginx-proxy/default.conf:/etc/nginx/conf.d/default.conf:ro ports: - "80:80" depends_on: - homepage - blog restart: always

  1. Hugo-Blog/Dockerfile:
FROM hugomods/hugo:exts-0.128.0 AS builder
COPY . .
RUN hugo --minify --baseURL "https://ri-nai.github.io/Hugo-Blog/"

FROM nginx:stable-alpine COPY --from=builder /src/public /usr/share/nginx/html

  1. nginx-proxy/default.conf:
server {
    listen 80;
    server_name IP;
location /Hugo-Blog/ {
    proxy_pass http://blog:80/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

location / {
    proxy_pass http://homepage:80/;
    # ... same headers
}

}

Troubleshooting Attempted:

  • Confirmed Hugo configuration works properly on GitHub Pages

  • Verified Docker containers are running and accessible internally

Tries and Expects

  • Request to IP/Hugo-Blog/about

    1. 404 on IP/Hugo-Blog/about
    2. Followed by 404 on IP/about
  • Expected: Behavior matching GitHub Pages' 301 → 200 redirect pattern while keeping /Hugo-Blog/ prefix

Reina
  • 3

1 Answers1

1

Your mistake is the trailing slash after the proxy_pass directive's upstream name, which many nginx novice users consider unimportant. However, it is important, as it acts as a URI part of the specified upstream. If you read the proxy_pass directive documentation carefully, you'll find the following:

A request URI is passed to the server as follows:

  • If the proxy_pass directive is specified with a URI, then when a request is passed to the server, the part of a normalized request URI matching the location is replaced by a URI specified in the directive:
    location /name/ {
        proxy_pass http://127.0.0.1/remote/;
    }
    
  • ...

With your

location /Hugo-Blog/ {
    proxy_pass http://blog:80/;
    ...
}

configuration snippet, you're explicitly telling nginx to strip the /Hugo-Blog/ request URI prefix and replace it with /.

Similary, with your

location / {
    proxy_pass http://homepage:80/;
    ...
}

configuration snippet, you are stripping / from your request URI and then adding it back, which doesn't harm the proxied request but does waste some extra CPU cycles on an unnecessary operation.

Instead, don't use any URI part on your upstream definitions at all:

location /Hugo-Blog/ {
    proxy_pass http://blog:80;
    ...
}

location / { proxy_pass http://homepage:80; ... }

This way, nginx will preserve the request URI as is when forwarding it to the upstream servers, preventing any unintended modifications.

Ivan Shatsky
  • 3,545