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 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 installed already, so I just had to run:
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.
Once it's installed, run:
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:
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:
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:
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.