Im trying to publish my first GraphQl project on a VPN, using docker-compose
It consists on a webapp, running on nodejs, and a GraphQl API, also running on nodejs, with Apollo Express and Prisma
The idea is to have the app and the API running on different containers and use a nginx container to proxy pass the requests to the right container (/ goes to the webapp, /api goes to the API)
I got it working, seems to be fine, but it needs to run on https. So Ive set up a letsencrypt certificate and set it on nginx and is working too, except for one thing: subscriptions
If I try to connect to the websocket using ws://mydomain/api, its refused cause the app is running on https. But if I try to connect on wss://mydomain/api, I get:
WebSocket connection to 'wss://mydomain/api' failed: Error during WebSocket handshake: Unexpected response code: 400 I read a lot of docs and tutorials and it seems to me Im doing right, but it just wont work and I dont know what to try anymore
Here is the relevant docker-compose.yml code:
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 And here is the 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"; } } And finally, the server initialization:
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`) } ); Where server is an ApolloServer
Everything works but the wss connection: the app can connect to the api using https://mydomain/api normally, and regular ws connection works too, if I run the app on http
Is just wss that I cant get to work
Any clues? What am I doing wrong here?