Random UTF-8 characters

Home

05 Aug 2019 in next.jsreactherokuhttps

NextJS & Heroku: HTTPS by default

I recently ran into the case where I wanted to ensure all traffic to my NextJS site was happening over HTTPS. Since my site is deployed using next start on heroku, I ended up implementing this using a custom server that checks all requests are https before handling them.

Here is the completed server.js implementation.

const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')

const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const port = process.env.PORT

app.prepare().then(() => {
  createServer((req, res) => {
    const parsedUrl = parse(req.url, true)
    if (!dev && req.headers['x-forwarded-proto'] != 'https') {
      const { host } = parse(process.env.HOSTNAME)
      res.writeHead(302, {
        Location: `https://${host}${req.url}`
      })
      res.end()
    } else {
      handle(req, res, parsedUrl)
    }
  }).listen(port, err => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}`)
  })
})

The redirect only fires in production mode and it uses a environment variable that contains the servers hostname. You'll notice that it does not check the requests URL or protocol. This is because all traffic from Heroku's router to your server happens over HTTP. You can see if the request is https by checking the value of the x-forwarded-proto header that Heroku adds.

You'll also have to update your start script to run your server and not the nextjs default.

...
"scripts": {
  "dev": "next",
  "build": "next build",
  "export": "next export",
  "start": "NODE_ENV=production node server.js"
}
...

Notes and Limitations:

  • This does not support sites hosted using next export
  • Changes to server.js are not hot reloaded.