使用 Apollo Express、Nginx 和 docker-compose 保护 websocket
Secure websocket with Apollo Express, Nginx and docker-compose
我正在尝试使用 docker-compose
在 VPN 上发布我的第一个 GraphQl 项目
它包含一个网络应用程序,运行ning 在 nodejs 上,还有一个 GraphQl API,也 运行ning 在 nodejs 上,带有 Apollo Express 和 Prisma
想法是让应用程序和 API 运行ning 在不同的容器上,并使用 nginx 容器代理将请求传递到正确的容器(/转到 webapp,/ api 转到 API)
我让它工作了,似乎没问题,但它需要 运行 在 https 上。所以我设置了一个 letsencrypt 证书并将其设置在 nginx 上并且也在工作,除了一件事:subscriptions
如果我尝试使用 ws://mydomain/api 连接到 websocket,它会被拒绝,因为应用程序在 https 上 运行ning。但是如果我尝试在 wss://mydomain/api 上连接,我会得到:
WebSocket connection to 'wss://mydomain/api' failed: Error during WebSocket handshake: Unexpected response code: 400
我阅读了很多文档和教程,在我看来我做得不错,但它就是行不通,我不知道该尝试什么了
这里是相关的docker-compose.yml代码:
version: "3"
services:
api:
build:
context: ./bin/api
container_name: 'node10-api'
restart: 'always'
entrypoint: ["sh", "-c"]
command: ["yarn && yarn prisma deploy && yarn prisma generate && yarn start"]
restart: always
ports:
- "8383:8383"
links:
- prisma
volumes:
- /local/api:/api
app:
build:
context: ./bin/app
container_name: 'node12-app'
restart: 'always'
entrypoint: ["sh", "-c"]
command: ["yarn && yarn build && yarn express-start"]
restart: always
ports:
- "3000:3000"
links:
- api
volumes:
- /local/app:/app
nginx:
container_name: 'nginx'
restart: always
image: nginx:1.15-alpine
ports:
- '80:80'
- '443:443'
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
- ./www:/etc/nginx/html
这里是 nginx conf:
upstream app {
ip_hash;
server app:3000;
}
upstream api {
server api:8383;
}
server {
listen 80;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name mydomain;
ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://app;
}
location /api {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
最后,服务器初始化:
const app = express();
app.use(cookieParser());
app.use(process.env.URL_BASE_PATH + '/' + process.env.UPLOAD_URL_DIR, express.static(process.env.UPLOAD_PATH));
app.use(process.env.URL_BASE_PATH + '/assets', express.static('assets'));
app.use(process.env.URL_BASE_PATH + '/etc', router);
app.use(createLocaleMiddleware());
app.use(helmet());
app.disable('x-powered-by');
console.log(process.env.URL_BASE_PATH);
if(process.env.URL_BASE_PATH === '')server.applyMiddleware({app, cors:corsOptions});
else server.applyMiddleware({app, cors:corsOptions, path:process.env.URL_BASE_PATH});
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
//STARTING
httpServer.listen({port: process.env.SERVER_PORT}, () => {
console.log(` Server ready`)
}
);
其中服务器是 ApolloServer
一切正常,但 wss 连接:应用程序可以正常使用 https://mydomain/api 连接到 api,如果我 运行 应用程序,常规 ws 连接也可以正常工作在 http
只是我无法上班
有线索吗?我在这里做错了什么?
我找到了我自己的解决方案:docker/nginx 配置是正确的,但 Apollo 期待 wss://mydomain/graphql 上的 websocket 连接,即使 graphql 服务器 运行 https:///mydomain/api
我找不到改变它的方法,所以我将它添加到 nginx conf 中:
location ^~/graphql {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://api;
}
终于成功了
我正在尝试使用 docker-compose
在 VPN 上发布我的第一个 GraphQl 项目它包含一个网络应用程序,运行ning 在 nodejs 上,还有一个 GraphQl API,也 运行ning 在 nodejs 上,带有 Apollo Express 和 Prisma
想法是让应用程序和 API 运行ning 在不同的容器上,并使用 nginx 容器代理将请求传递到正确的容器(/转到 webapp,/ api 转到 API)
我让它工作了,似乎没问题,但它需要 运行 在 https 上。所以我设置了一个 letsencrypt 证书并将其设置在 nginx 上并且也在工作,除了一件事:subscriptions
如果我尝试使用 ws://mydomain/api 连接到 websocket,它会被拒绝,因为应用程序在 https 上 运行ning。但是如果我尝试在 wss://mydomain/api 上连接,我会得到:
WebSocket connection to 'wss://mydomain/api' failed: Error during WebSocket handshake: Unexpected response code: 400
我阅读了很多文档和教程,在我看来我做得不错,但它就是行不通,我不知道该尝试什么了
这里是相关的docker-compose.yml代码:
version: "3"
services:
api:
build:
context: ./bin/api
container_name: 'node10-api'
restart: 'always'
entrypoint: ["sh", "-c"]
command: ["yarn && yarn prisma deploy && yarn prisma generate && yarn start"]
restart: always
ports:
- "8383:8383"
links:
- prisma
volumes:
- /local/api:/api
app:
build:
context: ./bin/app
container_name: 'node12-app'
restart: 'always'
entrypoint: ["sh", "-c"]
command: ["yarn && yarn build && yarn express-start"]
restart: always
ports:
- "3000:3000"
links:
- api
volumes:
- /local/app:/app
nginx:
container_name: 'nginx'
restart: always
image: nginx:1.15-alpine
ports:
- '80:80'
- '443:443'
volumes:
- ./data/nginx:/etc/nginx/conf.d
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
- ./www:/etc/nginx/html
这里是 nginx conf:
upstream app {
ip_hash;
server app:3000;
}
upstream api {
server api:8383;
}
server {
listen 80;
}
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 443 ssl;
server_name mydomain;
ssl_certificate /etc/letsencrypt/live/mydomain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mydomain/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
location / {
proxy_pass http://app;
}
location /api {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_pass http://api;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
最后,服务器初始化:
const app = express();
app.use(cookieParser());
app.use(process.env.URL_BASE_PATH + '/' + process.env.UPLOAD_URL_DIR, express.static(process.env.UPLOAD_PATH));
app.use(process.env.URL_BASE_PATH + '/assets', express.static('assets'));
app.use(process.env.URL_BASE_PATH + '/etc', router);
app.use(createLocaleMiddleware());
app.use(helmet());
app.disable('x-powered-by');
console.log(process.env.URL_BASE_PATH);
if(process.env.URL_BASE_PATH === '')server.applyMiddleware({app, cors:corsOptions});
else server.applyMiddleware({app, cors:corsOptions, path:process.env.URL_BASE_PATH});
const httpServer = http.createServer(app);
server.installSubscriptionHandlers(httpServer);
//STARTING
httpServer.listen({port: process.env.SERVER_PORT}, () => {
console.log(` Server ready`)
}
);
其中服务器是 ApolloServer
一切正常,但 wss 连接:应用程序可以正常使用 https://mydomain/api 连接到 api,如果我 运行 应用程序,常规 ws 连接也可以正常工作在 http
只是我无法上班
有线索吗?我在这里做错了什么?
我找到了我自己的解决方案:docker/nginx 配置是正确的,但 Apollo 期待 wss://mydomain/graphql 上的 websocket 连接,即使 graphql 服务器 运行 https:///mydomain/api
我找不到改变它的方法,所以我将它添加到 nginx conf 中:
location ^~/graphql {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_pass http://api;
}
终于成功了