简体   繁体   中英

Nginx reverse proxy and multiple React apps

So I'm trying to use NGINX as a reverse proxy for 2 react apps and 1 node js api. Each in separate docker containers.

So for example,

  • localhost -> leads to one react app

  • localhost/admin -> leads to another react app

  • localhost/api/getProducts -> leads to the /getProducts endpoint of the api

The first example and the second both work as intended. No issues. It's the 2nd example I'm having trouble configuring. It should just lead to a dashboard application built in React, but all I get is a white screen (with the same favicon as the first react app).

Here is my nginx config file

    upstream api {
        least_conn;
        server api:8080 max_fails=3 fail_timeout=30s;
    }

    upstream app {
        least_conn;
        server app:3000 max_fails=3 fail_timeout=30s;
    }

    upstream adminapp {
        least_conn;
        server adminapp:3001 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 80;

        if ($request_method = 'OPTIONS') {
            return 200;
        }

        # To allow POST on static pages
        error_page  405     =200 $uri;

        location / {
            proxy_pass http://app;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            expires 30d;
            break;
        }

        location ~ /admin/(?<url>.*) {
            proxy_pass http://adminapp;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
            expires 30d;
            break;
        }

        location ~ /api/(?<url>.*) {
            proxy_pass http://api/$url;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }

        location /health-check {
            return 200;
            access_log off;
        }
    }

}

When I specifically go to localhost:3001, I can reach the admin dashboard so I know it's running perfectly fine.

Here's my docker compose file as well

version: '3.7'

services:
  nginx:
    container_name: nginx
    image: nginx
    ports:
      - '80:80'
      - '443:443'
    links:
      - api:api
      - app:app
      - adminapp:adminapp
    volumes:
      - ./server/config/nginx:/etc/nginx
      - ./server/config/certs:/etc/ssl/private
  app:
    container_name: app
    build:
      context: ./frontend
      dockerfile: Dockerfile
    volumes:
      - './frontend:/usr/app/frontend/'
      - '/usr/app/frontend/node_modules'
    ports:
      - '3000:3000'
    environment:
      - NODE_ENV=development
  adminapp:
    container_name: adminapp
    build:
      context: ./admin
      dockerfile: Dockerfile
    volumes:
      - './admin:/usr/app/admin/'
      - '/usr/app/admin/node_modules'
    ports:
      - '3001:3001'
    environment:
      - NODE_ENV=development
      - PORT=3001
  api:
    container_name: api
    build:
      context: ./backend
      dockerfile: Dockerfile
    volumes:
      - './backend:/usr/app/backend/'
      - '/usr/app/backend/node_modules'
    ports:
      - '8080'
    environment:
      - NODE_ENV=development

So this isnt an answer really - because im having the same problem - but if you try setting an PUBLIC_URL as an env variable with "./", or "./your-path", you should see some changes. If you inspect the source of the page and click on the URLs of the static resources you should see the JS there. You may have to modify the path by adding /adminapp before it. I'm going to continue working on it so I'll update with anything else I find. Also FYI this may be relevant:

https://github.com/facebook/create-react-app/issues/8222#issuecomment-568308139

Leaving an answer here because I figured it out. Basically you have to add "homepage": "." to your package.json first. Then, make sure you check your dockerfile. This was my mistake. For it to work on a subdomain you have to explicitly build everything in the Dockerfile as it is here:

FROM node:14-alpine as build-deps
WORKDIR /usr/src/app
COPY package.json yarn.lock ./
RUN yarn
COPY . ./
RUN yarn build

FROM nginx:1.13-alpine
#WORKDIR /usr/src/app

COPY --from=build-deps /usr/src/app/build /usr/share/nginx/html
COPY ./nginx.conf /etc/nginx/nginx.conf
EXPOSE 3000

This is how I had it before, and this was incorrect:

# linux distro
FROM node:14-alpine

# workdir inside the container
WORKDIR /usr/src/app

# copy these files to WORKDIR
COPY package.json .
COPY yarn.lock .

# Install all of the npm dependencies on the Docker image. 
RUN yarn install

# Copy everything from the folder which this Dockerfile is placed
# and unto the new containers WORKDIR
COPY . .

# Open port 3000
EXPOSE 3000

# Run the script "npm start" defined in package.json
# this will start the dev server and the project will be at the containers ip+ port.
CMD ["yarn", "start"]

If you make sure that you have your Dockerfile correct and you have "homepage", the paths should be correct and your react app should work at the subdomain.

As a side note, if you are having trouble with react routing, check your basepath, that will probably fix it for you. =)

So I realized I never posted how I solved this; and to be honest I forget exactly what I did. I compared the nginx config in my original question to what I have now and realized there were some stark differences. So I'm posting what I have now. I don't think I had to change my docker config or anything. I did switch to the staticfloat/nginx-certbot image for SSL.

What it looks like I did though was set up a separate server block for the subdomain. Not sure if that is the most efficient or whatever, but it ended up working.

server {
        listen 80;
        server_name domain.com www.domain.com;

        location / {
            return 301 https://$host$request_uri;
        }
}

server {
    listen 443;
    server_name admin.domain.com;

    ssl_certificate     /etc/letsencrypt/live/admin.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/admin.domain.com/privkey.pem;

    location / {
        proxy_pass http://adminapp;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        expires 1d;
        break;
    }

    location ~* \.(eot|otf|ttf|woff|woff2)$ {
        expires 365d;
        add_header Access-Control-Allow-Origin *;
    }


    location ~ /api/(?<url>.*) {
        proxy_pass http://api/$url;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /health-check {
        return 200;
        access_log off;
    }
}

server {
    listen 443 ssl default_server;
    # listen 80 default_server;
    server_name domain.com;
    if ($request_method = 'OPTIONS') {
        return 200;
    }

    ssl_certificate     /etc/letsencrypt/live/domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/domain.com/privkey.pem;

    # To allow POST on static pages
    error_page  405     =200 $uri;


    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        expires 1d;
        break;
    }

    location ~* \.(eot|otf|ttf|woff|woff2)$ {
        expires 365d;
        add_header Access-Control-Allow-Origin *;
    }


    location ~ /api/(?<url>.*) {
        proxy_pass http://api/$url;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /health-check {
        return 200;
        access_log off;
    }
}

server {
    listen 443 ssl;
    # listen 80 default_server;
    server_name www.domain.com;
    if ($request_method = 'OPTIONS') {
        return 200;
    }

    ssl_certificate     /etc/letsencrypt/live/www.domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/www.domain.com/privkey.pem;

    # To allow POST on static pages
    error_page  405     =200 $uri;


    location / {
        proxy_pass http://app;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        expires 1d;
        break;
    }

    location ~* \.(eot|otf|ttf|woff|woff2)$ {
        expires 365d;
        add_header Access-Control-Allow-Origin *;
    }


    location ~ /api/(?<url>.*) {
        proxy_pass http://api/$url;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /health-check {
        return 200;
        access_log off;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM