HTTPS on Localhost with Next.js
Tags: nextjs, javascript, webdev, beginners
Published: 2024-04-29 16:04:00

Next.js is a popular framework for building web applications with great development support and tooling. However, its local development story has a plot hole: HTTPS support. While the next dev command has a `--experimental-https` flag to [enable HTTPS locally](https://nextjs.org/docs/pages/api-reference/next-cli#https-for-local-development), it’s rather limited.

Anchor’s new [lcl.host](https://lcl.host/) service fills this hole and even works with Docker containers. This article will explain what [lcl.host](https://lcl.host/) is, how it compares to Next.js’ experimental HTTPS flag, and how to configure your Next.js application to work with [lcl.host](https://lcl.host/).

## What is lcl.host?

[lcl.host](https://lcl.host/) is an easy way to enable HTTPS in local development environments, which improves the security of the development process, ensures feature parity between development and production environments, and enables features like CORS that behave differently on localhost.

There are multiple ways to use HTTPS on a local machine. You need to get a certificate for your server, renew it when it expires, and ensure your clients trust the CA that issued that certificate. If you get a certificate from a public CA, your clients automatically trust it, but your development server must be public, too. If you set up a local CA, your server can be private, but your clients need updates to trust your CA.

[lcl.host](https://lcl.host/) takes care of all this for you by providing a CA for development, ensuring your browsers and clients trust this CA, issuing certificates for your apps, and renewing them when they expire.

## What are the Benefits of Using lcl.host over Next.js’ Experimental HTTPS Flag?

Next.js offers an experimental flag that enables HTTPS locally. While [lcl.host](https://lcl.host/) requires a bit more setup, it also brings several benefits over the flag.

### lcl.host Works With All Next.js Commands

To use the experimental HTTPS support, add the `--experimental-https` flag every time you run `next dev` command.
With [lcl.host](https://lcl.host/) you can use all `next` commands without a flag, and HTTPS works transparently with them.

### lcl.host Works With HTTP and HTTPS

While the experimental HTTPS flag only listens on HTTPS, [lcl.host](https://lcl.host/) allows using HTTP and HTTPS simultaneously, so you can switch without restarting your server.

### lcl.host Works With Docker Containers

The experimental HTTPS flag relies on [`mkcert`](https://github.com/FiloSottile/mkcert), designed for a single development system. If you run a Docker container, the flag won’t configure your local browser to trust its certificate.

[lcl.host](https://lcl.host/) configures your browser on your system to trust the certificates in all containers you run locally.

### lcl.host Works With Subdomains

Experimental HTTPS only works with `localhost`; if you have multiple applications, they all run on `localhost` with different ports. [lcl.host](https://lcl.host/) doesn’t limit you to `https://localhost:<PORT>/`; you can use any subdomain of `lcl.host`, allowing you to run multiple apps simultaneously.

### lcl.host Renews Certificates Automatically

Experimental HTTPS might not take expired certificates into account. 

[lcl.host](lcl.host) handles automatic certificate renewal for you.

### lcl.host Integrates With the Experimental HTTPS Flag

The experimental HTTPS flag works with existing certificates to import the certificates generated by [lcl.host](https://lcl.host/) with the `--experimental-https-key` and `--experimental-https-cert` flags.

## How to Use lcl.host in a Next.js Project?

Now that you understand what [lcl.host](https://lcl.host/) can do for you, the next step is to see how to integrate it with a Next.js app.

### Prerequisites

- [Git](https://git-scm.com/)

### 1. Installing the Anchor CLI

First, you must install the Anchor CLI; this will handle the [lcl.host](https://lcl.host/) setup for your project.

With Homebrew (MacOS and Linux):

`brew install anchordotdev/tap/anchor`

With Chocolatey (Windows):

`choco install anchor --version=0.0.22`

Build from source with Go:

`go install github.com/anchordotdev/cli/cmd/anchor@latest`

### 2. Using Anchor’s Next.js Starter Template

For a new project, you can [use the Next.js-lcl.host starter template](https://github.com/anchordotdev/nextjs-lclhost-starter) provided by Anchor. It comes preinstalled with dependencies for automatic certificate renewal and an update `next.config.mjs` file.

You can clone it from GitHub with this command:

`git clone https://github.com/anchordotdev/nextjs-lclhost-starter.git`

> _Using this template, you can skip to step 5._

### 3. Installing Dependencies
For the automatic certificate renewal, you need the latest [anchor-pki](https://www.npmjs.com/package/anchor-pki) package. Install it as a development dependency with the following command:

`npm i anchor-pki -D`

[lcl.host](https://lcl.host/) works without this package, but when your certificates expire you must manually renew them.

### 4. Updating the Next.js Configuration

Now, you must tell Next.js to use the anchor-pki package every time you run your app. To do so, update the content of your `next.config.mjs` file:

```Javascript
import autoCert from "anchor-pki/auto-cert/integrations/next"
const withAutoCert = autoCert({enabledEnv: "development"})
const nextConfig = {
  // Your configurations
}
export default withAutoCert(nextConfig)
```

You can configure your Next.js app as usual; just ensure the config object is wrapped in the `withAutoCert()` call before exporting it.

###5. Connecting the Project with lcl.host

To make your project available via [lcl.host](https://lcl.host/), open the project directory in a shell and run the following command:

`anchor lcl`

After the command completes, you should see a URL to a guide for the automatic renewal:

```
| Next Steps
  | Now that you have local HTTPS setup, let's automate certificate provisioning
  | so you never have to manually provision future certificates again.
  | 
  | We've generated an Anchor.dev setup guide for your application with
  | instructions for automating certificate provisioning inside your
  application.
  - Opened https://anchor.dev/<ACCOUNT>/services/<APP_NAME>/guide.
```

Open this guide in your browser, then skip to the second step, as we already performed the first two here.

Click the “Generate new tokens” button, as seen in Figure 1, and copy the tokens and other environment variables into a new `.env.local` file.

![generate-new-tokens-button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/35w6108yog9534dw9w8n.png)

The content of the env file should look similar to this:

```bash
ACME_KID=aae…zWD
ACME_HMAC_KEY=72D…dMr
ACME_DIRECTORY_URL='https://anchor.dev/<ACCOUNT>/localhost/x509/ca/acme'
ACME_CONTACT="<ACCOUNT_EMAIL>+${ACME_KID}"
ACME_ALLOW_IDENTIFIERS="<APP_NAME>.lcl.host,<APP_NAME>.localhost"
HTTPS_PORT='<RANDOM_PORT>'
```

Next.js will use the `.env.local` file to set up environment variables before starting the web server. 

### 6. Testing the Project

Finally, to test the whole setup, you can start the development server with this command:

`npm run dev`

If everything goes well, you should get an output similar to this:

```bash
[AutoCert] Starting auto-cert proxy ...
[anchor-pki] The 'sni-callback' Configuration instance is enabled
[AutoCert] Listening on https://<APP_NAME>.lcl.host:44356 -> http://127.0.0.1:3000
[AutoCert] Listening on https://<APP_NAME>.localhost:44356 -> http://127.0.0.1:3000
[anchor-pki] No Terms of Service exist so agreed : true
[anchor-pki] No Terms of Service exist so agreed : true
[anchor-pki] Certificate for <APP_NAME>.lcl.host provisioned.
[anchor-pki] Certificate for <APP_NAME>.lcl.host cached in (tmp/acme).
```

As the output tells, you can now access your app via two HTTPS-enabled URLs.
If you get this error instead, it indicates a missing or incomplete `.env.local` file:

```
[AutoCert] HTTPS_PORT is not set, assuming 4333
/path/to/your/project/node_modules/anchor-pki/src/auto-cert/configuration.js:185
```

Return to step 5 and double-check you didn’t miss any environment variables.

### Summary

Next.js has a nifty HTTPS feature, which is nice for quickly testing an app on your local machine. However, its tricky to use with Docker or multiple applications.

[lcl.host](https://lcl.host/) is a complete solution for HTTPS-enabled development environments. It handles automatic certificate renewal and works transparently with several setups, including Docker, multiple local applications, and all Next.js commands.

### Resources

- [Anchor CLI](https://github.com/anchordotdev/cli)
- [Next.js lcl.host starter template](https://github.com/anchordotdev/nextjs-lclhost-starter)