Docker nginx прокси websocket получая 404 - PullRequest
1 голос
/ 01 ноября 2019

Мое приложение состоит из углового внешнего интерфейса, прокси-сервера nginx, с приложением узла nestjs. Приложение узла предоставляет API-интерфейс для порта 3000 и сокетов на 3003. При запуске на моем компьютере разработчика все это работает, но в конфигурации докера веб-сокеты не работают. API звонки работает. Mongodb также работает.

Я установил docker compose с mongodb и сервером, и запускаю приложение angular в ng serve, и websockets работают, но они не работают через прокси-сервер nginx. Я не уверен, что мне не хватает.

Вот сервер Dockerfile

FROM node

ENV HOME=/usr/src/app
RUN mkdir -p $HOME
WORKDIR $HOME

RUN npm -g install @angular/cli@9.0.0-next.19

EXPOSE 3000
EXPOSE 3334
EXPOSE 3003

USER 1000

Вот конфигурация nginx

version: '3.6'
services:
  mongodb:
    image: mongo:latest
    container_name: mongodb
    restart: always
    secrets:
      - mongodb_rootusername
      - mongodb_rootuserpwd
      - mongodb_username
      - mongodb_userpwd
    environment:
      MONGO_INITDB_ROOT_USERNAME: /run/secrets/mongodb_rootusername
      MONGO_INITDB_ROOT_PASSWORD: /run/secrets/mongodb_rootuserpwd
      MONGO_INITDB_DATABASE: admin
      MONGO_USERNAME: /run/secrets/mongodb_username
      MONGO_USERPWD: /run/secrets/mongodb_userpwd
    ports:
      - 27017
    volumes:
      - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.sh:ro
  oauth2:
    container_name: oauth2
    image: 97842411e57c
    ports:
      - '4180:4180'
    command:
      - --provider=google
      - --cookie-secure=false
      - --cookie-refresh=1h
      - --cookie-expire=168h
      - --upstream=http://upstream:80
      - --http-address=0.0.0.0:4180
      - --email-domain=<mydomain>
      - --set-xauthrequest=true
      - --set-authorization-header=true
      - --request-logging=false
      - --proxy-websockets=true
    secrets:
      - OAUTH2_PROXY_CLIENT_ID
      - OAUTH2_PROXY_CLIENT_SECRET
      - OAUTH2_PROXY_COOKIE_NAME
      - OAUTH2_PROXY_COOKIE_SECRET
      - OAUTH2_PROXY_REDIRECT_URL

  server:
    container_name: server
    build:
      context: .
      dockerfile: Dockerfile.server.dev
    ports:
      - "3000:3000"
      - "3334:3334"
      - "3003:3003"
    volumes:
      - .:/usr/src/app
    command: ng serve api
    depends_on:
      - mongodb
  scripts:
    container_name: scripts
    build:
      context: .
      dockerfile: Dockerfile.scripts.dev
    ports:
      - "3333:3333"
    volumes:
      - .:/usr/src/app
    command: ng serve scripts
    depends_on:
      - mongodb
  angular:
    container_name: angular
    build:
      context: .
      dockerfile: Dockerfile.angular
    ports:
      - "4200"
    volumes:
      - .:/usr/src/app
    command: ng serve --aot --host 0.0.0.0
  web:
    container_name: web
    build: .
    volumes:
      - ./nginx.dev.conf:/etc/nginx/nginx.conf
    ports:
      - "80:80"
    depends_on:
      - angular
      - oauth2

secrets:
  mongodb_rootusername:
    file: ../../serverdata/dev/mongodb_rootusername
  mongodb_rootuserpwd:
    file: ../../serverdata/dev/mongodb_rootuserpwd
  mongodb_username:
    file: ../../serverdata/dev/mongodb_username
  mongodb_userpwd:
    file: ../../serverdata/dev/mongodb_userpwd
  OAUTH2_PROXY_CLIENT_ID:
    file: ../../serverdata/dev/oauth2_clientid
  OAUTH2_PROXY_CLIENT_SECRET:
    file: ../../serverdata/dev/oauth2_clientsecret
  OAUTH2_PROXY_COOKIE_NAME:
    file: ../../serverdata/dev/oauth2_cookiename
  OAUTH2_PROXY_COOKIE_SECRET:
    file: ../../serverdata/dev/oauth2_cookiesecret
  OAUTH2_PROXY_REDIRECT_URL:
    file: ../../serverdata/dev/oauth2_redirecturl

Вот конфигурация nginx

events {}
http {
        upstream node_server {
            server server:3000;
        }

        upstream node_server_websockets {
            server server:3003;
        }

        upstream angular_cli {
            server angular:4200;
        }

        upstream oauth2 {
            server oauth2:4180;


     }
server {
        listen 80 default_server;
        listen [::]:80 default_server;

        server_name localhost;



    location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/sign_in;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header Host $host;
        proxy_pass http://angular_cli;
    }

    location /oauth2/ {
        proxy_pass       http://oauth2;
        proxy_set_header Host                    $host;
        proxy_set_header X-Real-IP               $remote_addr;
        proxy_set_header X-Scheme                $scheme;
        proxy_set_header X-Auth-Request-Redirect $request_uri;
        # or, if you are handling multiple domains:
        # proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
      }
      location = /oauth2/auth {
        proxy_pass       http://oauth2;
        proxy_set_header Host             $host;
        proxy_set_header X-Real-IP        $remote_addr;
        proxy_set_header X-Scheme         $scheme;
        # nginx auth_request includes headers but not body
        proxy_set_header Content-Length   "";
        proxy_pass_request_body           off;
      }


     location /tapi/ {
        auth_request /oauth2/auth;


    # pass information via X-User and X-Email headers to backend,
        # requires running with --set-xauthrequest flag
        auth_request_set $user   $upstream_http_x_auth_request_user;
        auth_request_set $email  $upstream_http_x_auth_request_email;
        proxy_set_header X-User  $user;
        proxy_set_header X-Email $email;

        # if you enabled --pass-access-token, this will pass the token to the backend
        auth_request_set $token  $upstream_http_x_auth_request_access_token;
        proxy_set_header X-Access-Token $token;

        # if you enabled --cookie-refresh, this is needed for it to work with auth_request
        auth_request_set $auth_cookie $upstream_http_set_cookie;
        add_header Set-Cookie $auth_cookie;

        # When using the --set-authorization-header flag, some provider's cookies can exceed the 4kb
        # limit and so the OAuth2 Proxy splits these into multiple parts.
        # Nginx normally only copies the first `Set-Cookie` header from the auth_request to the response,
        # so if your cookies are larger than 4kb, you will need to extract additional cookies manually.
        auth_request_set $auth_cookie_name_upstream_1 $upstream_cookie_auth_cookie_name_1;

        # Extract the Cookie attributes from the first Set-Cookie header and append them
        # to the second part ($upstream_cookie_* variables only contain the raw cookie content)
        if ($auth_cookie ~* "(; .*)") {
            set $auth_cookie_name_0 $auth_cookie;
            set $auth_cookie_name_1 "auth_cookie_name_1=$auth_cookie_name_upstream_1$1";
        }

        # Send both Set-Cookie headers now if there was a second part
        if ($auth_cookie_name_upstream_1) {
            add_header Set-Cookie $auth_cookie_name_0;
            add_header Set-Cookie $auth_cookie_name_1;
        }



        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;
        proxy_pass http://node_server;

    }
    location /socket.io {
        # auth_request /oauth2/auth;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        # proxy_set_header Host $host;
        proxy_pass http://server:3003/;
    }

}
}

Узелсервер nestjs контроллер веб-сокета:

@WebSocketGateway(3003, {})
export class ActionsGateway implements OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit {
    @WebSocketServer() wss;

    private logger = new Logger('AppGateway');

    handleConnection(client) {
        this.logger.log('New client connected');
        client.emit('connection', 'Successfully connected to server');
    }

    handleDisconnect(client) {
        this.logger.log('Client disconnected');
    }

    afterInit(server): any {
        this.logger.log('actions gateway initialized');
        // this.wss.
    }
}

и в угловых:

this.socket = io(environment.socket.baseUrl); 

где environment.socket:

socket: {
        baseUrl: 'ws://localhost/socket.io/',
        config: {}
    }

Ошибка из журналов nginx:

web        | 172.18.0.1 - - [31/Oct/2019:21:56:47 +0000] "GET /socket.io/?EIO=3&transport=polling&t=MuZqZ14 HTTP/1.1" 404 5 "http://localhost/" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.70 Safari/537.36"

Ответы [ 2 ]

0 голосов
/ 01 ноября 2019

Настройка nginx, отсутствует параметр 'map'?

map $http_upgrade $connection_upgrade {
default upgrade;
''      close;
}

server {
   listen       80;
   server_name  _;

   location / {
        auth_request /oauth2/auth;
        error_page 401 = /oauth2/sign_in;
        proxy_pass http://angular_cli;
        proxy_set_header Host $host;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
   }
}

, посмотрите официальные документы nginx

0 голосов
/ 01 ноября 2019

Я также столкнулся с подобной проблемой несколько дней назад. Моя проблема была с nginx. Я мог бы решить мою проблему, добавив приведенный ниже код в конфигурацию nginx.

location / {
  proxy_pass http://localhost:8080;
  proxy_http_version 1.1;
  proxy_set_header Upgrade $http_upgrade;
  proxy_set_header Connection "upgrade";
  proxy_set_header Host $host;
}

Для получения дополнительной информации см. этот выпуск GitHub и эту статью .

...