Ben Löffel
Ben Löffel

Reputation: 931

HTTPS on localhost using NextJS + Express

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.

Upvotes: 11

Views: 25874

Answers (6)

Markus Amalthea Magnuson
Markus Amalthea Magnuson

Reputation: 8741

next.js 13.5.1 released today has built-in experimental support for HTTPS dev server using the --experimental-https flag: https://github.com/vercel/next.js/releases/tag/v13.5.1

Upvotes: 0

Daniel De León
Daniel De León

Reputation: 13639

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

Upvotes: 2

PJRobot
PJRobot

Reputation: 1416

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.

Upvotes: 9

malix
malix

Reputation: 3572

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}`);
  });
});

Upvotes: 0

emarshah
emarshah

Reputation: 326

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}`)
    })
})

Upvotes: 0

Tibi02
Tibi02

Reputation: 697

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}`);
    })
  });

Upvotes: 16

Related Questions