How to route Vitepress app to sub-route of main app with Docker?

265 views Asked by At

I'm trying to set up a documentation for our app on the same domain, using Vitepress. Locally, I can run our app on port 5173 and the Vitepress documentation on port 9000. We're using following Docker containers to run our app (frontend only):

1. nginx
2. vite
3. vitepress (documentation)

How can I set up docker to route the 9000 port to sub-route /docs/ of our domain? Locally the docs should be available at: https://localhost:5173/docs/.

I've tried lots of things but always end up running into an 502 error. Following setup is before described routing is attempted.

Docker containers:

/docker/nginx/conf.d/local.conf:

...

location /docs/ {
  proxy_pass http://vitepress:9000/;
}

...

/docker/vite/Dockerfile:

FROM node:16

EXPOSE 5173

WORKDIR /var/www/html

ADD docker/vite/cmd/startnode startnode

RUN install -m 0755 startnode /usr/local/bin

CMD startnode

/docker/vite/cmd/startnode:

yarn
yarn dev

/docker/vitepress/Dockerfile:

FROM node:16

EXPOSE 9000

WORKDIR /var/www/html

ADD docker/vitepress/cmd/startnode startnode

RUN install -m 0755 startnode /usr/local/bin

CMD startnode

/docker/vitepress/cmd/startnode:

yarn
yarn vp

/docker/docker-compose.yml:

version: '3'

services:
  nginx:
    build:
      context: ../.
      dockerfile: ./docker/nginx/Dockerfile
    ports:
      # 5173 is the port exposed to the Docker Host
      # 443 is the port other bridged Docker Container can access the Service
      - '5173:443'
    volumes:
      - '..:/var/www/html:delegated'
      - 'trinity-ui-vite-mnt:/var/run'
    networks:
      trinity-ui-vite-bridge:
        aliases:
          - trinity-ui-vite.local
  vite:
    build:
      context: ../.
      dockerfile: ./docker/vite/Dockerfile
    volumes:
      - '..:/var/www/html:delegated'
      - 'trinity-ui-vite-mnt:/var/run'
    networks:
      trinity-ui-vite-bridge:
        aliases:
          - trinity-ui-vite.local
  vitepress:
    build:
      context: ../.
      dockerfile: ./docker/vitepress/Dockerfile
    ports:
        - '9000:9000'
    volumes:
      - '..:/var/www/html:delegated'
      - 'trinity-ui-vite-mnt:/var/run'
    networks:
      trinity-ui-vite-bridge:
        aliases:
          - trinity-ui-vite.local

networks:
  trinity-ui-vite-bridge: null
volumes:
  trinity-ui-vite-mnt: null

/docker/start.sh:

#!/bin/bash

if [[ "${1}" == "--rebuild" ]]
then
    docker-compose -p tuiv up --build -d
else
    result=$( docker images -q tuiv-vite )

    if [[ -n "$result" ]]; then
        docker-compose -p tuiv start
    else
        docker-compose -p tuiv up --build -d
        docker network connect tuiv_trinity-ui-vite-bridge ft-nginx-1
    fi
fi

/docs/.vitepress/vitepress.config.js:

module.exports = {
  base: '/docs/',
};

these are the relevant scripts in package.json:

"docs:dev": "vitepress dev docs --port=9000 --base=/docs/ --host",
"docs:build": "vitepress build docs",
"docs:serve": "vitepress serve docs",
"docgen": "vue-docgen -c docgen.config.mjs",
"docs": "vue-docgen -w -c docgen.config.mjs",
"vp": "yarn run docs:dev"

With this setup, docker starts vitepress on http://localhost:9000/docs/ and our main app on https://localhost:5173. How would one make the docs available on https://localhost:5173/docs/?

I've tried using different configurations (nginx/conf.d/local.conf):

location /docs/ {
  proxy_pass http://vitepress:5173/;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection 'upgrade';
  proxy_set_header Host $host;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Host $host;
  proxy_set_header X-Forwarded-Proto $scheme;
  proxy_buffering off;
}

but then I run into the 502. The nginx container log shows:

2023-11-30 15:17:53 2023/11/30 15:17:53 [error] 29#29: *3 connect() failed (111: Connection refused) while connecting to upstream, client: 192.168.65.1, server: _, request: "GET /docs/ HTTP/2.0", upstream: "http://172.19.0.2:9000/", host: "localhost:5173"
1

There are 1 answers

6
VonC On BEST ANSWER

Your Vitepress app is running on port 9000 within its container, but the NGINX proxy setup is trying to route to port 5173?!

Make sure the base URL in your Vitepress configuration (/docs/.vitepress/vitepress.config.js) is correctly set to /docs/. That would make Vitepress aware that it is being served from a subpath.

module.exports = {
  base: '/docs/',
  // ... other configurations
};

Make sure there is no redirect (rewrite or return directives) in your NGINX configuration causing a loop. And use the proxy_pass directive without a trailing slash if you are including the /docs/ path in the proxy_pass URL.
A proxy_redirect off; does not seem to be needed.

location /docs/ {
    proxy_pass http://vitepress:9000;  # No trailing slash
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_buffering off;
}

Clear your browser's cache or try incognito mode. Redirect loops can sometimes be caused by caching issues.
Then check the NGINX container logs for any errors or clues about why the redirects are happening.
And use browser developer tools to inspect network traffic: look at the response headers for the requests to https://localhost:5173/docs/ to see where the redirects are coming from.

+---------+      +--------+      +-----------+
|         |      |        |      |           |
|  NGINX  +----->+  VITE  |      | VITEPRESS |
|         |      |        |      |           |
+----+----+      +--------+      +-----+-----+
     |                                |
     |       Proxy /docs/ to port 9000|
     +------------------------------->+