2

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?

2 Answers 2

3

I found my own solution: the docker/nginx configs were right, but Apollo was expecting the websocket connection on wss://mydomain/graphql, even though the graphql server is running on https://mydomain/api

I failed to find a way to change that, so I added this to the 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; } 

And it finally worked

Sign up to request clarification or add additional context in comments.

Comments

2

I just solved this problem. The front end tried to establish a connection via wss, but the server returned a 400 error. I changed the Nginx configuration file:

before:

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

after:

# sudo nano /etc/nginx/sites-available/backend server { server_name www.api.example.host api.example.host; location / { proxy_pass http://localhost:3033/; 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; } } # sudo service nginx restart # sudo service nginx status # sudo apt install -y certbot python3-certbot-nginx # sudo certbot run -n --nginx --agree-tos -d api.example.host,www.api.example.host -m [email protected] --redirect 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.