11

System Information

Goal

Serve the web application using SSL over HTTPS on localhost

What has been done

  1. Created basic NextJS application using Create Next App
  2. Generated a certificate and key using OpenSSL and moved it into the project directory
  3. Added the Express dependency
  4. Configured the app to use express inside server.js
  5. Changed script to use the server.js inside package.json scripts.

server.js

const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const port = 3000;

const https = require('https');
const fs = require('fs');
const httpsOptions = {
  key: fs.readFileSync('./certificates/key.pem'),
  cert: fs.readFileSync('./certificates/cert.pem')
};

app
  .prepare()
  .then(() => {
    const server = express();

    server.get('*', (req, res) => {
      return handle(req, res);
    });

    server.listen(port, err => {
      if (err) throw err;
      console.log('> Ready on http://localhost: ' + port);
    });
  })
  .catch(ex => {
    console.error(ex.stack);
    process.exit(1);
  });

Extra Information

The app currently works when initialized using yarn dev. I have tried to serve the app over https using this answer but I was unable to figure out how to apply this to my current setup using NextJS.

I spent a lot of time researching the web how to apply this solution but have not yet found a way on how to make this work.

Any help is greatly appreciated.

Ben Löffel
  • 931
  • 4
  • 12
  • 29
  • Use ngrok, very easy to use tool to make local port available online via https. Method explained here: https://frontendguruji.com/blog/run-next-js-app-locally-in-https/ – Mandeep Pasbola Aug 25 '22 at 12:13

5 Answers5

16

You just need to use the createServer method of https module.

const { createServer } = require('https');
const { parse } = require('url');
const { readFileSync } = require('fs');
const next = require('next');

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

const httpsOptions = {
  key: readFileSync('./certificates/key.pem'),
  cert: readFileSync('./certificates/cert.pem')
};

app.prepare()
  .then(() => {
    createServer(httpsOptions, (req, res) => {
      const parsedUrl = parse(req.url, true);
      handle(req, res, parsedUrl);
    }).listen(port, err => {
      if (err) throw err;
      console.log(`> Ready on https://localhost:${port}`);
    })
  });
Tibi02
  • 689
  • 7
  • 17
9

Other answer seemed to just drop express... Found a solution after some difficulty with both server code and certificate so hopefully can save someone else the trouble!

First of all, solid advice for creating localhost certificate here: https://letsencrypt.org/docs/certificates-for-localhost/

Secondly, simple code that offers HTTP/HTTPS with next js and express:

const next = require('next');
const express = require('express');
const http = require('http');
const https = require('https');
const fs = require('fs');

const ports = {
  http: 3080,
  https: 3443
}
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const server = express();  

const options = { 
  key: fs.readFileSync('localhost.key'),
  cert: fs.readFileSync('localhost.crt'), 
};

app.prepare().then(() => {           
  server.all('*', (req, res) => {
    return handle(req, res)    
  });
  http.createServer(server).listen(ports.http);
  https.createServer(options, server).listen(ports.https);
});

It is worth noting that one could omit or redirect either port.

Goon Nguyen
  • 1,462
  • 11
  • 26
PJRobot
  • 1,306
  • 13
  • 14
1

Step 1: Run your dev server and get their http port.

Step 2: Run local-ssl-proxy with your desire ports, in target parameter must be the current dev server port.

npx local-ssl-proxy --source 3001 --target 3000

Step 3: Visit your brand new HTTPS service https://localhost:3001 or use your IP inside your LAN https://192.168.1.21:3001

starball
  • 20,030
  • 7
  • 43
  • 238
Daniel De León
  • 13,196
  • 5
  • 87
  • 72
0

Below work for me very well for next server with https;

Using this official documentation of node js https module Creating HTTPS Server

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

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

const httpsOptions = {
    pfx: readFileSync('./certificates/AMB.pfx'),
    passphrase: 'Testabc$'
  };

app.prepare().then(() => {
    createServer(httpsOptions, (req, res) => {    
        const parsedUrl = parse(req.url, true)
        const { pathname, query } = parsedUrl

        if (pathname === '/login') {
            app.render(req, res, '/login', query)
        } else {
            handle(req, res, parsedUrl)
        }
    }).listen(port, err => {
        if (err) throw err
        console.log(`> Ready on https://localhost:${port}`)
    })
})
emarshah
  • 328
  • 3
  • 14
0

Our straightforward, switchable implementation:

const app = require('express')();
const https = require('https');
const http = require('http');
const next = require('next');
const fs = require('fs');
const path = require('path');

const HTTPS = true;
const server = HTTPS
  ? https.createServer(
      {
        key: fs.readFileSync(path.resolve(__dirname, './server.key')),
        cert: fs.readFileSync(path.resolve(__dirname, './server.cert')),
      },
      app
    )
  : http.createServer({}, app);

const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();

nextApp.prepare().then(() => {
  app.get('/api/something', (req, res) => {
    res.json({});
  });

  // ...

  app.get('*', (req, res) => {
    return nextHandler(req, res);
  });

  server.listen(port, (err) => {
    if (err) throw err;
    console.log(`> Ready on http${HTTPS ? 's' : ''}://localhost:${port}`);
  });
});
malix
  • 3,566
  • 1
  • 31
  • 41