Apollo-server: SSL on Apollo Server 2.0 + Subscriptions

Created on 12 Jul 2018  ·  9Comments  ·  Source: apollographql/apollo-server


Hi all,

What is the best way to add SSL to Apollo Server 2.0 with Subscription support? Looks like Standalone is based on Express http package.

I tried applyMiddle with https.createServer:

var app = express()

const apolloServer = new ApolloServer({typeDefs, resolvers})
apolloServer.applyMiddleware({ app })

var sslServer = https.createServer(options, app).listen({port: SSL_PORT}, function() {
    console.log(`Running on ${SSL_PORT}${apolloServer.graphqlPath}`)
})

This works for standard HTTPs requests but when I try to use a subscription over WSS, I get:

Could not connect to websocket endpoint wss://localhost:4000/graphql. Please check if the endpoint url is correct.

Everything works fine without SSL.

⛲️ feature

Most helpful comment

Turns out, it is pretty simple with apollo-server-express.

Here's the code snippet for using HTTPS in production and HTTP in development - with subscriptions:

import express from 'express'
import { ApolloServer } from 'apollo-server-express'
import typeDefs from './graphql/schema'
import resolvers from './graphql/resolvers'
import * as fs from 'fs'
import * as https from 'https'
import * as http from 'http'

const configurations = {
  // Note: You may need sudo to run on port 443
  production: { ssl: true, port: 443, hostname: 'example.com' },
  development: { ssl: false, port: 4000, hostname: 'localhost' }
}

const environment = process.env.NODE_ENV || 'production'
const config = configurations[environment]

const apollo = new ApolloServer({ typeDefs, resolvers })

const app = express()
apollo.applyMiddleware({ app })

// Create the HTTPS or HTTP server, per configuration
var server
if (config.ssl) {
  // Assumes certificates are in .ssl folder from package root. Make sure the files
  // are secured.
  server = https.createServer(
    {
      key: fs.readFileSync(`./ssl/${environment}/server.key`),
      cert: fs.readFileSync(`./ssl/${environment}/server.crt`)
    },
    app
  )
} else {
  server = http.createServer(app)
}

// Add subscription support
apollo.installSubscriptionHandlers(server)

server.listen({ port: config.port }, () =>
  console.log(
    '🚀 Server ready at',
    `http${config.ssl ? 's' : ''}://${config.hostname}:${config.port}${apollo.graphqlPath}`
  )
)

All 9 comments

Would be nice to see some official guidance on this. The question was asked on SO about a year ago and there are no answers.

Turns out, it is pretty simple with apollo-server-express.

Here's the code snippet for using HTTPS in production and HTTP in development - with subscriptions:

import express from 'express'
import { ApolloServer } from 'apollo-server-express'
import typeDefs from './graphql/schema'
import resolvers from './graphql/resolvers'
import * as fs from 'fs'
import * as https from 'https'
import * as http from 'http'

const configurations = {
  // Note: You may need sudo to run on port 443
  production: { ssl: true, port: 443, hostname: 'example.com' },
  development: { ssl: false, port: 4000, hostname: 'localhost' }
}

const environment = process.env.NODE_ENV || 'production'
const config = configurations[environment]

const apollo = new ApolloServer({ typeDefs, resolvers })

const app = express()
apollo.applyMiddleware({ app })

// Create the HTTPS or HTTP server, per configuration
var server
if (config.ssl) {
  // Assumes certificates are in .ssl folder from package root. Make sure the files
  // are secured.
  server = https.createServer(
    {
      key: fs.readFileSync(`./ssl/${environment}/server.key`),
      cert: fs.readFileSync(`./ssl/${environment}/server.crt`)
    },
    app
  )
} else {
  server = http.createServer(app)
}

// Add subscription support
apollo.installSubscriptionHandlers(server)

server.listen({ port: config.port }, () =>
  console.log(
    '🚀 Server ready at',
    `http${config.ssl ? 's' : ''}://${config.hostname}:${config.port}${apollo.graphqlPath}`
  )
)

Given the lack of official guidance, I ended up using nginx as a reverse proxy in front of apollo-server.

Nginx works. Traefik is another good option. Neither are necessary though. I'll do a pull request for documentation update on SSL.

I am using typescript for my server and your solution without nginx does not work for me. It seems like installSubscriptionHandlers doesn't expect an https.Server:

Argument of type 'Server | Server' is not assignable to parameter of type 'Server'.
  Type 'import("https").Server' is not assignable to type 'import("http").Server'.
    Property 'maxHeadersCount' is missing in type 'Server'. [2345]

Given the lack of official guidance, I ended up using nginx as a reverse proxy in front of apollo-server.

I tried this but it still didn't work. What's your nginx configuration? Maybe I'm doing something wrong

I’m sorry, I haven’t had a chance to work with TypeScript on Apollo. Can someone else in the community resolve this?

Zak

On Dec 7, 2018, at 2:59 PM, Ove von Stackelberg notifications@github.com wrote:

I am using typescript for my server and your solution without nginx does not work for me. It seems like installSubscriptionHandlers doesn't expect an https.Server:

Argument of type 'Server | Server' is not assignable to parameter of type 'Server'.
Type 'import("https").Server' is not assignable to type 'import("http").Server'.
Property 'maxHeadersCount' is missing in type 'Server'. [2345]

You are receiving this because you modified the open/close state.
Reply to this email directly, view it on GitHub, or mute the thread.

Actually, it was just two lines of code missing in my nginx config, it's all good now. Thanks a lot

Actually it's NOT all good... Though SanchezQb might be happy with his nginx workaround, the real problem is not resolved.

As @Ragyal mentioned, it seems like installSubscriptionHandlers doesn't expect an https.Server.

Could someone please reopen, as it is still a bug.

Was this page helpful?
0 / 5 - 0 ratings