Serving a Next.js application over HTTPS in localhost
2 min read

Serving a Next.js application over HTTPS in localhost

I recently set up a Next.js application to be served over HTTPS in localhost using mkcert. This is how I did it in under 5 minutes.

## Why HTTPS in localhost?

For most applications, not having HTTPS in localhost is completely fine and that is the usual way. Recently, I needed a way to set cross-site cookies. Using `express-session`, it's quite simple to do this. Set `cookie.sameSite` to `none`. But to do that, I have to set `cookie.secure` to `true` and this is possible only over HTTPS connections.

I could have deployed my application to a dev server so it's served over HTTPS but that just takes way too long. So I set up HTTPS for my local server and this is how I did it.

## Enter, mkcert

[mkcert](https://mkcert.dev) is awesome. It took me only 5 minutes to have my application served over HTTPS on my local machine.

First, we have to install `mkcert` on our machine. I use Ubuntu and had [Linuxbrew](https://docs.brew.sh/Homebrew-on-Linux) installed already, so I just had to run:

```shell
brew install mkcert
```

This will also work on macOS with Homebrew. On Windows, you can use the pre-built binaries available here: [https://github.com/FiloSottile/mkcert/releases](https://github.com/FiloSottile/mkcert/releases).

Once it's installed, run:

```shell
mkcert -install
```

This will add a local certificate authority to your system and notify your browsers. You have to restart your browsers to pick up this change. Then run:

```shell
mkcert localhost
```

This will generate two `pem` (localhost.pem and localhost-key.pem) files in your `home` directory. If you've used AWS EC2 before you will already be familiar with this file type. It's a file format used to store cryptographic keys and is used for authentication and authorization.

## Creating a custom local server for Next.js

There is no way, that I know of, to change the default Next.js server, so it serves over HTTPS. So we'll create a custom server. If you're deploying to Vercel, don't worry. We're using this custom server only for local development.

Create a `server.js` file in the project root:

```js
const { createServer } = require('https');
const { parse } = require('url');
const next = require('next');
const fs = require('fs');
const port = 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();

const httpsOptions = {
  key: fs.readFileSync('./certs/localhost-key.pem'),
  cert: fs.readFileSync('./certs/localhost.pem'),
};

app.prepare().then(() => {
  createServer(httpsOptions, async (req, res) => {
     const parsedUrl = parse(req.url, true);
     await handle(req, res, parsedUrl);
  }).listen(port, (err) => {
     if (err) throw err;
     console.log('ready - started server on url: https://localhost:' + port);
  });
});
```

Here we're using the `createServer` from the Node.js `https` library and passing in our local keys in the `httpsOptions`.

Now, all we have to do is, run:

```shell
node server.js
```

Go to `https://localhost:3000` on your favorite browser. Now, our application is served over HTTPS on localhost! Yaay!

---

Setting up HTTPS for a localhost server was surprisingly easy than I thought it would be. If you need your Next.js application to be served over HTTPS in localhost, this is how to do it. With some small modifications, this will also work for Express.js servers. I hope this article was informative.

Until next time.