Skip to content
Sandny Blog
  • Home
  • Java
  • JavaScript
  • AWS
  • Embedded
  • About
SSL Websocket using Nginx Proxy Express.js

SSL Websocket proxy with Nginx for Graphql Subscriptions

  • May 12, 2022May 12, 2022
  • by Coder Kai

GraphQL has become the most used API framework to use in mobile and web platforms. Often we come with instances where we need to run these services behind a proxy server like Nginx to co-exist with other services. In this tutorial, you will find how to configure your SSL certs with the WebSocket server in order to

What is WebSocket and why do we need it with GraphQL

GraphQL has a comprehensive feature set called subscriptions. With subscription, a client can listen to the updates of certain entity types when they occure in the backend. For example, when you send a message using the backend graphql mutation, it will trigger a message to all the clients who are listening to a specific message as a recipient.

To achieve this there should be two way communication. Early days there was long polling, callback polling transport methods and later websocket became popular with its wide support over different platforms.

So GraphQL subcscription can use qwebsockets for this communication and for that we need a socket connection additional to the existing http connection

Setting up the client and Server

The most common client that is used for GraphQL is Apollo Client. You can use following code to create a link with websocket connection for subscription and http link for the mutations and queries

import { HttpLink } from '@apollo/client';
import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
import { createClient } from 'graphql-ws';

const httpLink = new HttpLink({ uri: "https://yourdomain/graphql" });

const wsLink = new GraphQLWsLink(createClient({
  url: 'wss://yourdomain/subscription', /// should be wss://
}));

// use wsLink for the truthy values which is subscriptions. For others use httpLink
const splitLink = split(
  ({ query }) => {
    const definition = getMainDefinition(query);
    return (
      definition.kind === 'OperationDefinition' &&
      definition.operation === 'subscription'
    );
  },
  wsLink,
  httpLink,
);

const client = new ApolloClient({
  link: splitLink,
  cache: new InMemoryCache()
});

You can refer following for more details regarding client side: https://www.apollographql.com/docs/react/data/subscriptions/#client-side

On server side you can use following to setup websocket connection

import { ApolloServer } from 'apollo-server-express';
import { createServer } from 'http';
import express from 'express';
import { ApolloServerPluginDrainHttpServer } from "apollo-server-core";
import { makeExecutableSchema } from '@graphql-tools/schema';
import { WebSocketServer } from 'ws';
import { useServer } from 'graphql-ws/lib/use/ws';
import resolvers from './resolvers';
import typeDefs from './typeDefs';

// Create the schema, which will be used separately by ApolloServer and
// the WebSocket server.
const schema = makeExecutableSchema({ typeDefs, resolvers });

// Create an Express app and HTTP server; we will attach both the WebSocket
// server and the ApolloServer to this HTTP server.
const app = express();
const httpServer = createServer(app);

// Create our WebSocket server using the HTTP server we just set up.
const wsServer = new WebSocketServer({
  server: httpServer,
  path: '/graphql',
});
// Save the returned server's info so we can shutdown this server later
const serverCleanup = useServer({ schema }, wsServer);

// Set up ApolloServer.
const server = new ApolloServer({
  schema,
  csrfPrevention: true,
  plugins: [
    // Proper shutdown for the HTTP server.
    ApolloServerPluginDrainHttpServer({ httpServer }),

    // Proper shutdown for the WebSocket server.
    {
      async serverWillStart() {
        return {
          async drainServer() {
            await serverCleanup.dispose();
          },
        };
      },
    },
  ],
});
await server.start();
server.applyMiddleware({ app });

const PORT = 4000;
// Now that our HTTP server is fully set up, we can listen to it.
httpServer.listen(PORT, () => {
  console.log(
    `Server is now running on http://localhost:${PORT}${server.graphqlPath}`,
  );
});

You can refer following link for further reference: https://www.apollographql.com/docs/apollo-server/data/subscriptions/

Configure Nginx Conf

Now your websocket connection should be running without any issues. Following is the nginx config that you need to modify for client to communicate with websocket

map $http_upgrade $connection_upgrade { // upgrade connection headers
    default upgrade;
    '' close;
}

upstream subscription {
  server localhost:4000; #  host and port of local running server instance
}

server {
    client_max_body_size 250M;
    listen 443 ssl;
    ssl_certificate /etc/nginx/certs/cert.crt;
    ssl_certificate_key /etc/nginx/certs/cert.key;
    server_name yourdomain.com;

    location /graphql { # http endpoint
        proxy_pass http://localhost:4000/graphql;  # local url of the http endpoint
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $http_connection;
        proxy_set_header Host $host;
    }

    location /subscription { # websocket endpoint
      proxy_pass http://subscription/graphql; # local url of the websocket endpoint
      # the host should be the upstream here which would resolve the
      # upstream url and host
      
      proxy_redirect     default;
      proxy_http_version 1.1;

      proxy_set_header   Connection        $connection_upgrade;
      proxy_set_header   Upgrade           $http_upgrade; 

      proxy_set_header   Host              $host;
      proxy_set_header   X-Real-IP         $remote_addr;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Proto $scheme;

      client_max_body_size       10m;
      client_body_buffer_size    128k;

      proxy_connect_timeout      90;
      proxy_send_timeout         90;
      proxy_read_timeout         90;
  }
}

Here it will mention that the yourdomain.com/subscription is websocket endpoint and the yourdomain.com/graphql is the http endpoint.

Finally you can see that client recieving data using a subscription or a mutation using the secure links. Note that the websocket link should wss:// and should use https:// link for the other requests

Python is not setting correct path in mac os
How to save pandas Dataframe to a file and read back
Coder Kai
A humble developer

Related articles

Create Lambda function with Terraform
How to create Lambda function…
Multiple refs for an array of React Elements
Using multiple refs for an…
Immutable and Mutable Values in Javascript
07. Immutable and Mutable Values…
wrapper objects in javascript
06. Wrapper objects in Javascript
globals undefined and null values in javascript
05 Global, null and undefined…
Javascript Booleans and Equality
04. Javascript Guide Booleans and…
How to add Chakra UI Animations
Chakra UI Animations
Change python version correctly
Python is not setting correct…
optimize React.js load time
How to optimize React.js app…
Multiple refs for an array of React Elements
How to use IntersectionObserver to…
Multiple refs for an array of React Elements
How to dismiss dropdowns when…
Javascript guide Strings
03. Javascript Guide – Strings
How to fetch data with useEffect
How to fetch data with…
add styles to stripe elements
How to add styles to…
Typescript
How to use Typescript with…
how to optimize react-native map view
How to optimize react-native map…
debounce with react hooks
Avoid multiple clicks using debounce…
Numbers inJavascript
02. Javascript Guide – Numbers
Introduction to Javascript
01. Javascript Guide – Introduction…
Nginx Load Balancer with docker…

Categories

  • android 3
  • Apollo Client 1
  • AWS 8
    • AppSync 5
    • EC2 1
    • EKS 1
    • Route53 1
    • S3 1
  • AWS Amplify 1
  • Chakra UI 1
  • Docker 1
  • Embedded 1
  • EmberJS 1
  • FCM 1
  • Godaddy 1
  • GraphQL 3
  • ios 1
  • Jasper 1
  • Java 10
    • Java 11 1
    • Java 14 1
  • JavaEE 2
  • JavaScript 39
    • Express.js 4
    • Javascript Guide 7
    • Node.js 3
    • react-native 4
    • React.js 17
    • Typescript 1
  • Kubernetes 1
  • machine learning 1
  • Maven 2
  • OCaml 3
  • PostgreSQL 1
  • Python 2
  • react-native 4
  • ReactJS 3
  • sass 1
  • Server 6
  • spark 1
  • Terraform 2
  • Ubuntu 4
  • Uncategorized 1
  • webpack 2

Recent Comments

  • Pamela587 on Chakra UI Animations
  • Alicia1760 on Chakra UI Animations
  • vneuweluso on How to add styles to stripe elements without using CardElement

Meta

  • Log in
  • Entries feed
  • Comments feed
  • WordPress.org

Archives

  • October 2022 3
  • September 2022 7
  • May 2022 1
  • December 2021 1
  • August 2021 1
  • July 2021 6
  • June 2021 3
  • February 2021 1
  • July 2020 1
  • December 2019 5
  • November 2019 6
  • October 2019 3
  • August 2019 1
  • March 2019 1
  • February 2019 1
  • January 2019 2
  • December 2018 1
  • September 2018 2
  • August 2018 1
  • June 2018 1
  • February 2018 1
  • November 2017 2
  • October 2017 5
  • September 2017 1
  • June 2017 1
  • May 2017 10
Sandny Blog space
Theme by Colorlib Powered by WordPress