71

I'm trying to get https working on my localhost environment for Vite. Chrome shows an invalid certificate error.

I've set up my vite.config.js file like this:

import { defineConfig  } from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs';

export default defineConfig({
  resolve: { alias: { '@': '/src' } },
  plugins: [vue()],
  https: {
    key: fs.readFileSync('RootCA-key.pem'),
    cert: fs.readFileSync('RootCA.pem')
  }
})

and when I run npm run dev -- --https it works as expected, I don't get any issues from Vite. However, Chrome shows an invalid certificate.

I used openssl to create the cert files, which gave me .crt, .pem, and .key files. None of them are binary, so I renamed the .key file as RootCA-key.pem. I've tried using the RootCA.pem file as the cert, as well as renaming the RootCA.crt file to RootCA-cert.pem and using that as the cert.

As a temporary work-around, I've enabled insecure localhost in Chrome (chrome://flags/#allow-insecure-localhost), which at least gets rid of the warning.

kissu
  • 40,416
  • 14
  • 65
  • 133
hyphen
  • 2,368
  • 5
  • 28
  • 59
  • 3
    Self-signed certs are invalid by default. You'll have to manually [trust the certificate](https://stackoverflow.com/a/15076602/6277151). – tony19 Oct 05 '21 at 04:14
  • Unless you create and trust your own root CA in the local Browsers. And that is exactly where one wants vite to serve ones own self signed certs so that Chrome and co do not come up with the security question. – norman Sep 17 '22 at 16:08
  • 1
    @hyphen: The example you provide has a mistake you might want to fix (at least for vite 3): the 'https' options under the keys 'server' or 'preview'. – norman Sep 17 '22 at 16:17

6 Answers6

116

Easiest way is to use the vite-plugin-mkcert package.

npm i vite-plugin-mkcert -D

vite.config.js

import { defineConfig } from 'vite'
import mkcert from 'vite-plugin-mkcert'

export default defineConfig({
  server: { https: true },
  plugins: [ mkcert() ]
})

When you run the local vite dev server you may be prompted for your password the first time. It will then install a local certificate onto your system and to a number of installed browsers.

Easy!

Daniel Elkington
  • 2,560
  • 6
  • 22
  • 35
  • I'm using this in combination with laravel sail, but my container won't start anymore due to network failures – Janessa Labeur Jul 12 '22 at 06:56
  • 1
    Thanks, solved my problem. Spent 12hrs+ trying to troubleshoot `ERR_SSL_PROTOCOL_ERROR` error before I came across this. – Moses Machua Jan 02 '23 at 01:37
  • It also blocks the hosting of the vue application to your local network.npm run dev -- --host is not making application anymore accessible. – Tun Kapgen Apr 17 '23 at 21:46
89

The Vite documentation suggest using their official package instead: @vitejs/plugin-basic-ssl

Documentation: https://vitejs.dev/config/server-options.html#server-https

You need to install it with

npm install -D @vitejs/plugin-basic-ssl

And then use it like this in your vite.config.ts:

import basicSsl from '@vitejs/plugin-basic-ssl'

export default {
  plugins: [
    basicSsl()
  ]
}

⚠️ This if for your dev environment, don't use this on production. You need your own certificate in production (using nginx and let's encrypt for example).

Zymotik
  • 6,412
  • 3
  • 39
  • 48
Herobrine
  • 1,661
  • 14
  • 12
  • Chrome says certificate is not valid when using this – Julien Reszka Aug 30 '22 at 09:59
  • 3
    @JulienReszka It's a local certificate, so yes, chrome can't verify it, and you need to manually approve it. Click on "Advanced parameters" on the error page, then "Continue toward 127.0.0.1". – Herobrine Aug 31 '22 at 10:18
  • 2
    This should be the accepted answer, as it works perfectly for a dev environment and it's actually suggested by the documentation. Production - wise, it's another story. – venir Sep 05 '22 at 10:06
  • 4
    They actually DON'T recommend doing this. They recommend using your own certificate, according to the linked page. – Tim Keating Sep 05 '22 at 22:08
  • 1
    @TimKeating I added a small warning. This solution is of course only for testing purpose in dev environment. Anyway, I'm not sure anyone uses Vite in production, since the main point of Vite is hot-reload... You don't use Vite to serve generated files AFAIK. – Herobrine Sep 06 '22 at 15:04
  • SvelteKit's current model is Vite 100% of the time... although arguably, that means Rollup in production. – Tim Keating Sep 09 '22 at 01:13
  • Using plugin-basic-ssl this approach I get a warning about SSL which I cannot skip ("You cannot visit localhost right now because the website uses HSTS.") We're better off signing our own certificate. – Fabien Snauwaert Jan 25 '23 at 17:53
  • 1
    Mac users: for Chrome you can type 'thisisunsafe' to bypass, Safari, you need to paste the URL of the Vite server into the main window then use the options Safari gives you to bypass the security warnings. Note that while **@vitejs/plugin-basic-ssl** worked, **vite-plugin-mkcert** didn't. – William Turrell Feb 23 '23 at 18:52
  • 1
    I added this so it runs only on dev: ...(process.env.NODE_ENV === "development" ? [basicSsl()] : []), – jaletechs Apr 16 '23 at 04:54
46

Maybe it's the key and cert files that are the issue. I am using the mkcert library with the same options and it works fine for me. Moreover, no need to manually trust the certificates.

You can follow these steps:

# Step: 1
# Install mkcert tool - macOS; you can see the mkcert repo for details
brew install mkcert

# Step: 2
# Install nss (only needed if you use Firefox)
brew install nss

# Step: 3
# Setup mkcert on your machine (creates a CA)
mkcert -install

# Step: 4 (Final)
# at the project root directory run the following command
mkdir -p .cert && mkcert -key-file ./.cert/key.pem -cert-file ./.cert/cert.pem 'localhost'

And update your vite.config.js with

import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import fs from 'fs';

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    https: {
      key: fs.readFileSync('./.cert/key.pem'),
      cert: fs.readFileSync('./.cert/cert.pem'),
    },
  },
  plugins: [react()],
});

The above steps should solve the HTTPS issue while running yarn dev to start the dev server.

Additional: I use an npm script to make it easy for my team members to create the certificates.

// in package.json
"scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "serve": "vite preview",

    "cert": "rm -rf .cert && mkdir -p .cert && mkcert -key-file ./.cert/key.pem -cert-file ./.cert/cert.pem 'localhost'"

  },

Munshi
  • 691
  • 6
  • 8
  • 2
    Because I overlooked this for quite a while: Make sure you don't accidentally use vite's basicSsl() at the same time. In that case vite will never serve your own certificates and always generate an adhoc cert. After I got rid of that my openssl 3.x certs worked fine with vite. – norman Sep 17 '22 at 16:13
  • 2
    this worked for me as of June 8th 2023 :) even in brave – Rick Penabella Jun 08 '23 at 05:46
  • note that if you use a custom server this won't work. – Jamie Jun 26 '23 at 13:16
1

Daniel Elkington's answer above worked like a charm for me on macOS. However it did not work for me for a Vue/Vite inside a Docker container.

This approach below worked for me (both on macOS and inside a Docker container):

Got things working (by re-)using key and cert files I'd generated for localhost using mkcert, e.g.:

// vite.config.js
import { fileURLToPath, URL } from "node:url";

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// https://vitejs.dev/config/
export default defineConfig({
  server: {
    https: {
      key: '/path/to/some_folder/ssl/SSLforMyHosts-key.pem',
      cert: '/path/to/some_folder/ssl/SSLforMyHosts-certificate.pem',
    }
  },
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});

The key and cert files were generated for localhost (and more test domains for local development) using mkcert, with this command:

cd /Users/your_name/some_folder/ssl
mkcert \
  -cert-file SSLforMyHosts-certificate.pem -key-file SSLforMyHosts-key.pem \
  localhost 127.0.0.1 ::1 \
  some-other-local-dev-site.localhost \
  example.localhost

See also: answer about installing self-signed certificate.

Fabien Snauwaert
  • 4,995
  • 5
  • 52
  • 70
0

As an alternative solution, the answer in this post explains how to add the CA and cert to the server and to the browser: Getting Chrome to accept self-signed localhost certificate

For your vite config refer to Vite Docs - server.https, you would only need something like this:

server: {
    https: true
  }

or You could do it from the command line like this:

vite --https

or

npm run dev -- --https
0

if you have created local certificate using mkcert then you can use the following config:

vite.config.js (using vue@3)

Remember to change the certificate filename if you intend to copypase the code.

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import fs from 'fs';
// https://vitejs.dev/config/
export default defineConfig({
  server: {
    https: {
            key:  fs.readFileSync("../localhost+2-key.pem"),
            cert: fs.readFileSync("../localhost+2.pem"),
            ca: fs.readFileSync("../.local/share/mkcert/rootCA.pem")

        },
      port: 8080
},
  plugins: [vue(), vueJsx()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})