使用Apollo Express、Nginx和docker-compose保护WebSocket

9njqaruj  于 2023-11-17  发布在  Nginx
关注(0)|答案(2)|浏览(193)

我正尝试使用docker-compose在VPN上发布我的第一个GraphQl项目
它包括一个运行在nodejs上的web应用程序,以及一个同样运行在nodejs上的GraphQl API,以及Apollo Express和Prisma
这个想法是让应用程序和API运行在不同的容器上,并使用nginx容器代理将请求传递到正确的容器(/转到webapp,/API转到API)
我让它工作,似乎是好的,但它需要在https上运行。所以我设置了一个letsencrypt证书,并设置在nginx上,它也在工作,除了一件事:订阅
如果我尝试使用ws://mydomain/API连接到WebSocket,它会被拒绝,因为应用程序正在https上运行。但是如果我尝试使用wss://mydomain/API连接,我会得到:

  1. WebSocket connection to 'wss://mydomain/api' failed: Error during WebSocket handshake: Unexpected response code: 400

字符串
我读了很多文档和教程,在我看来我做得对,但它就是不起作用,我不知道该怎么尝试了
下面是相关的docker-compose.yml代码:

  1. version: "3"
  2. services:
  3. api:
  4. build:
  5. context: ./bin/api
  6. container_name: 'node10-api'
  7. restart: 'always'
  8. entrypoint: ["sh", "-c"]
  9. command: ["yarn && yarn prisma deploy && yarn prisma generate && yarn start"]
  10. restart: always
  11. ports:
  12. - "8383:8383"
  13. links:
  14. - prisma
  15. volumes:
  16. - /local/api:/api
  17. app:
  18. build:
  19. context: ./bin/app
  20. container_name: 'node12-app'
  21. restart: 'always'
  22. entrypoint: ["sh", "-c"]
  23. command: ["yarn && yarn build && yarn express-start"]
  24. restart: always
  25. ports:
  26. - "3000:3000"
  27. links:
  28. - api
  29. volumes:
  30. - /local/app:/app
  31. nginx:
  32. container_name: 'nginx'
  33. restart: always
  34. image: nginx:1.15-alpine
  35. ports:
  36. - '80:80'
  37. - '443:443'
  38. volumes:
  39. - ./data/nginx:/etc/nginx/conf.d
  40. - ./data/certbot/conf:/etc/letsencrypt
  41. - ./data/certbot/www:/var/www/certbot
  42. - ./www:/etc/nginx/html


下面是nginx的conf:

  1. upstream app {
  2. ip_hash;
  3. server app:3000;
  4. }
  5. upstream api {
  6. server api:8383;
  7. }
  8. server {
  9. listen 80;
  10. }
  11. map $http_upgrade $connection_upgrade {
  12. default upgrade;
  13. '' close;
  14. }
  15. server {
  16. listen 443 ssl;
  17. server_name mydomain;
  18. ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
  19. ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem;
  20. include /etc/letsencrypt/options-ssl-nginx.conf;
  21. ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
  22. location / {
  23. proxy_pass http://app;
  24. }
  25. location /api {
  26. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  27. proxy_set_header Host $host;
  28. proxy_pass http://api;
  29. proxy_http_version 1.1;
  30. proxy_set_header Upgrade $http_upgrade;
  31. proxy_set_header Connection "Upgrade";
  32. }
  33. }


最后,服务器初始化:

  1. const app = express();
  2. app.use(cookieParser());
  3. app.use(process.env.URL_BASE_PATH + '/' + process.env.UPLOAD_URL_DIR, express.static(process.env.UPLOAD_PATH));
  4. app.use(process.env.URL_BASE_PATH + '/assets', express.static('assets'));
  5. app.use(process.env.URL_BASE_PATH + '/etc', router);
  6. app.use(createLocaleMiddleware());
  7. app.use(helmet());
  8. app.disable('x-powered-by');
  9. console.log(process.env.URL_BASE_PATH);
  10. if(process.env.URL_BASE_PATH === '')server.applyMiddleware({app, cors:corsOptions});
  11. else server.applyMiddleware({app, cors:corsOptions, path:process.env.URL_BASE_PATH});
  12. const httpServer = http.createServer(app);
  13. server.installSubscriptionHandlers(httpServer);
  14. //STARTING
  15. httpServer.listen({port: process.env.SERVER_PORT}, () => {
  16. console.log(`🚀 Server ready`)
  17. }
  18. );


其中服务器是ApolloServer
除了wss连接,其他都可以正常工作:应用程序可以正常使用https://mydomain/API连接到API,如果我在http上运行应用程序,则常规ws连接也可以正常工作
只是因为我不能去上班
有线索吗?我做错什么了?

bq8i3lrv

bq8i3lrv1#

我找到了自己的解决办法:docker/nginx的配置是正确的,但是Apollo期望wss://mydomain/graphql上的WebSocket连接,即使graphql服务器运行在https://mydomain/api上
我没有找到一种方法来改变这一点,所以我在nginx conf中添加了以下内容:

  1. location ^~/graphql {
  2. proxy_set_header Upgrade $http_upgrade;
  3. proxy_set_header Connection "upgrade";
  4. proxy_set_header Host $http_host;
  5. proxy_set_header X-Real-IP $remote_addr;
  6. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  7. proxy_set_header X-Frame-Options SAMEORIGIN;
  8. proxy_pass http://api;
  9. }

字符串
终于成功了

dfty9e19

dfty9e192#

我刚刚解决了这个问题。前端尝试通过wss建立连接,但服务器返回400错误。我更改了Nginx配置文件:
之前:

  1. # sudo nano /etc/nginx/sites-available/backend
  2. server {
  3. server_name www.api.example.host api.example.host;
  4. location / {
  5. proxy_pass http://localhost:3033/;
  6. }
  7. }
  8. # sudo service nginx restart
  9. # sudo service nginx status
  10. # sudo apt install -y certbot python3-certbot-nginx
  11. # sudo certbot run -n --nginx --agree-tos -d api.example.host,www.api.example.host -m [email protected] --redirect

字符串
之后:

  1. # sudo nano /etc/nginx/sites-available/backend
  2. server {
  3. server_name www.api.example.host api.example.host;
  4. location / {
  5. proxy_pass http://localhost:3033/;
  6. proxy_http_version 1.1;
  7. proxy_set_header Upgrade $http_upgrade;
  8. proxy_set_header Connection 'upgrade';
  9. proxy_set_header Host $host;
  10. proxy_cache_bypass $http_upgrade;
  11. }
  12. }
  13. # sudo service nginx restart
  14. # sudo service nginx status
  15. # sudo apt install -y certbot python3-certbot-nginx
  16. # sudo certbot run -n --nginx --agree-tos -d api.example.host,www.api.example.host -m [email protected] --redirect

展开查看全部

相关问题