npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

devcert-node20

v1.2.4

Published

Generate trusted local SSL/TLS certificates for local SSL development (Node.js 20+ compatible)

Downloads

142

Readme

devcert - 让本地开发 HTTPS 更简单

English | 简体中文

本地跑 HTTPS 服务通常很麻烦。常见方案各有取舍,而最常见的自签名证书方案,往往意味着每个项目都要面对浏览器里吓人的不安全提示。

devcert 让这个流程更简单。需要给你的服务生成私钥和证书?直接这样用:

let ssl = await devcert.certificateFor('my-app.test');
https.createServer(ssl, app).listen(3000);

然后打开 https://my-app.test:3000,你会发现页面可以直接正常访问,不再出现烦人的证书警告。

证书会按域名缓存,因此对 certificateFor('foo') 的两次调用会返回同一份 key 和 cert。

项目说明

本项目基于原始 devcert 实现,并在此基础上进行了对 Node.js 20+ 的兼容性适配。

选项

devcert 在首次安装或升级时,会创建一个自签名根证书颁发机构(CA),并用它来签发后续的域名证书。它会尝试将该 CA 注册到 macOS、Linux、Windows 的系统信任存储中。

但需要注意,一些 HTTP 客户端(例如 Firefox、Node.js 本身)会使用自己的信任列表,而不是系统信任存储。为此,getCaPathgetCaBuffer 可以把 CA 信息附带在 certificateFor() 的返回结果中,供这些程序自行决定是否信任。

getCaPath

设置为 true 后,返回对象会包含 caPath 字段,值是 CA 文件路径。你可以把这个路径用于支持路径参数的本地信任配置,比如 Node.js 内置环境变量 NODE_EXTRA_CA_CERTS

getCaBuffer

设置为 true 后,返回对象会包含 ca 字段,值是 CA 文件的 UTF-8 文本内容。适合那些不依赖操作系统信任存储、但支持直接传入证书内容的场景。

skipHostsFile

如果你申请的是自定义域名(即非 localhost),devcert 会尝试修改系统配置,把该域名解析到本机(而不是公网真实域名),默认通过修改 /etc/hosts 实现。

如果传入 skipHostsFile,则会跳过这一步。这意味着当你申请 my-app.test 这类证书时,如果没有其他 DNS 重定向手段,你将无法通过 https://my-app.test 访问本地服务。

请注意,SSL 证书是按域名签发的。如果你申请的是 my-app.test 的证书,那么访问 localhost 并不会生效,即使你的应用其实跑在本机上。

skipCertutil

这个选项会告诉 devcert 不要自动安装 certutil 工具。

certutil 是用于在某些场景自动安装 SSL 证书的工具,尤其是:

  • Firefox(所有操作系统)
  • Chrome(仅 Linux)

默认情况下,如果系统缺少 certutil,devcert 会尝试自动安装。若你不希望自动安装,可传入 skipCertutil: true

传入后会影响以下场景:

  • Firefox(全平台):Firefox 支持手动导入并信任证书。若设置了 skipCertutil: true,devcert 会改为自动打开 Firefox 并启动导入向导。按照提示完成即可。每台机器通常只需做一次
  • Linux 上的 Chrome:目前 Linux Chrome 基本只能通过 certutil 信任证书,没有等价的手动流程。因此如果你在 Linux 上使用 Chrome,请不要设置 skipCertutil: true,否则证书不会被 Chrome 信任。

certutil 的安装方式:

  • Mac: brew install nss
  • Linux: apt install libnss3-tools
  • Windows: 不适用(Windows 上没有简单的无交互安装方式,因此 Firefox 会回退到向导流程)

多域名(SAN)

如果你在做多租户应用,或者本地有多个应用域名,可以通过传入域名数组来生成带 Subject Alternative Name 扩展的证书。

let ssl = await devcert.certificateFor([
  'localhost',
  'local.api.example.com',
  'local.example.com',
  'local.auth.example.com'
]);
https.createServer(ssl, app).listen(3000);

Docker 与本地开发

如果你使用 Docker 开发,可以把 devcert 安装在用户目录下的独立工具目录中,为多个本地 Docker 项目统一生成证书。可参考 这个 issue 的讨论与注意事项。

虽然不是最优雅的方法,但通常只有在新增本地域名时才需要重新生成证书,频率一般不高。

示例脚本:

// 示例:在家目录创建如 ~/devcert-util 的目录
// ~/devcert-util/generate.js
const fs = require('fs');
const devcert = require('devcert');

// 如果只有一个域名,也可以用 devcert.certificateFor('local.example.com')
devcert.certificateFor([
  'localhost',
  'local.api.example.com',
  'local.example.com',
  'local.auth.example.com'
])
  .then(({key, cert}) => {
    fs.writeFileSync('./certs/tls.key', key);
    fs.writeFileSync('./certs/tls.cert', cert);
  })
  .catch(console.error);

一个简单用法是把生成后的 ~/devcert-util/certs 目录复制到各个 Docker 项目里:

# local-docker-project-root/
🗀 certs/
  🗎 tls.key
  🗎 tls.cert

并在 .gitignore 里加入:

certs/

这样这两个文件就可以被任意项目复用,不限于 Node.js。

在 Docker 中的 Node 服务里,直接读取证书并启动 HTTPS:

const fs = require('fs');
const Express = require('express');
const app = new Express();
https
  .createServer({
    key: fs.readFileSync('./certs/tls.key'),
    cert: fs.readFileSync('./certs/tls.cert')
  }, app)
  .listen(3000);

同样也适用于 webpack dev server 等工具:

// webpack.config.js
const fs = require('fs');

module.exports = {
  //...
  devServer: {
    contentBase: join(__dirname, 'dist'),
    host: '0.0.0.0',
    public: 'local.api.example.com',
    port: 3000,
    publicPath: '/',
    https: {
      key: fs.readFileSync('./certs/tls.key'),
      cert: fs.readFileSync('./certs/tls.cert')
    }
  }
};

工作原理

当你请求开发证书时,devcert 会先检查这台机器是否已完成初始化。如果没有,它会创建根 CA,并将其加入系统和各浏览器的信任存储。你很可能会看到系统弹出的授权密码提示。

由于机器已经信任这个根 CA,因此后续由它签发的证书也会被信任。于是当你申请新域名证书时,devcert 会用根 CA 凭据签发该域名证书并返回给你。

如果某个域名之前已经签发过证书,devcert 会直接返回缓存结果。

因此浏览器不会再把这些证书标记为不受信任。

安全注意事项

当 devcert 安装根证书时,系统要求输入管理员密码是有原因的:一旦把根 CA 加入信任链,浏览器会信任它签发的任何证书。

这会带来潜在风险:如果他人能够访问 devcert 的 CA 凭据,并同时可以劫持或篡改你的网络流量,理论上就有可能伪装网站且不触发浏览器警告。

为降低此风险,devcert 会尽量确保他人无法在你不知情的情况下使用 CA 凭据。具体方式因平台而异:

  • macOS 与 Linux:CA 凭据文件只允许 root 用户读取(例如 chown 0 ca-cert.crtchmod 600 ca-cert.crt)。devcert 自身需要读写时会通过 sudo 完成。
  • Windows:由于文件权限细节复杂,devcert 采用让用户输入密码并用 AES256 加密凭据的方式。该密码不会写入磁盘。

此外,凭据落盘时会使用临时文件,并在不再需要时立即删除。

根 CA 也是每台机器首次初始化时本地即时生成,因此不存在跨机器共享的中心密钥。

为什么要安装根 CA?

安装一个根 CA 能更容易管理多个本地域名的 SSL。另一种方案是为每个域名单独生成并信任自签名证书。

但问题在于:虽然 devcert 能帮助添加证书到信任存储,删除证书的工具链却并不总是完整覆盖所有场景。若你将来要彻底取消信任,可能需要手动逐个移除。

使用单一根 CA 后,禁用某个域名 SSL 会更简单:删除对应域名证书文件即可。因为这些域名证书本身不会被单独安装到信任存储,文件删掉就彻底失效。

集成

devcert 从设计上就是一个底层库,便于其他工具进行集成调用。目标是让不同框架、不同库都能更轻松地支持 HTTPS 本地开发。

如果你希望在自己的库、框架或 CLI 中集成 devcert,可以使用 ui 选项来自定义所有需要用户交互的节点(替换默认提示与界面),实现品牌化、国际化或融入已有工作流。

ui 选项是一个对象,可包含以下方法:

{
  async getWindowsEncryptionPassword(): Promise<string> {
    // Windows 下用于加密根 CA 凭据的密码。
    // 如果用户输入错误,可能会被多次调用。
  },
  async warnChromeOnLinuxWithoutCertutil(): Promise<string> {
    // Linux 下检测到 Chrome 且 skipCertutil=true 时触发。
    // 用于提示用户 Chrome 将不会信任该证书。
  },
  async closeFirefoxBeforeContinuing() {
    // 当需要写入 Firefox 信任存储且 Firefox 正在运行时触发。
    // 由于 Firefox 退出时可能覆盖信任存储变更,需要先关闭 Firefox。
  },
  async startFirefoxWizard(certificateHost: string) {
    // 检测到 Firefox 且指定 skipCertutil=true 时触发。
    // devcert 即将启动 Firefox 的证书导入向导,可以在这里提前提示用户。
    // certificateHost 是临时服务地址,用于触发证书下载流程并唤起向导。
  },
  async firefoxWizardPromptPage(certificateURL: string): Promise<string> {
    // 启动 Firefox 导入向导时,Firefox 会先打开一个 HTML 页面。
    // 该方法返回这个页面的模板内容,certificateURL 是实际证书地址。
    // 默认实现是简单重定向;你也可以提供自定义页面。
  }
  async waitForFirefoxWizard() {
    // 在启动导入向导后调用。
    // 该方法应在用户确认向导完成后再 resolve。
  }
}

你可以只实现其中部分方法,未实现的方法会回退到默认实现。

测试

像 devcert 这种工具测试起来并不轻松。跨平台 GUI 自动化测试(尤其是浏览器证书相关流程与 Firefox 导入向导)很难完整覆盖。

为了方便测试,项目提供了一组虚拟机快照。每个镜像都处于“即将开始测试”的状态,启动后按 Enter 即可。

你也可以利用快照能力把虚拟机回滚到干净状态,开始下一轮测试。

注意:macOS 许可条款禁止在非 Apple 硬件上运行,因此测试 macOS 平台需要拥有 Mac。如果你没有 Mac,也没关系,在 PR 中注明无法测试 macOS 即可,维护者可以协助验证。

虚拟机快照

许可证

MIT © Dave Wasmer