Node、Express、SSL 证书:5 个步骤从头运行 HTTPS 服务器

2025-06-07

Node、Express、SSL 证书:5 个步骤从头运行 HTTPS 服务器

Node、Express、SSL 证书:5 个步骤从头运行 HTTPS 服务器

我在为客户编写一个 Web 应用时遇到了一些困难,因此决定写这篇教程。这是一个简单的 Web 图表,但它需要通过 Telegram 机器人收集数据。我将数据保存在 MongoDB 中,并准备了一个快速 API 来获取数据,但过程中遇到了很多问题,SSL 证书就是其中之一。

因此,在本教程中,我将介绍我的错误和问题以及解决方案,如果您想直接跳到简短版本,您可以从这里继续

在本文中我不会提及与 MongoDB 相关的代码或问题。

1. 使用 Express 创建我的基本 API 服务器

在我的项目中,我更喜欢在创建项目文件夹后创建一个npm或环境。yarn

因此,我使用以下命令完成了此操作:



mkdir my-project && cd my-project
yarn init


Enter fullscreen mode Exit fullscreen mode

Enter之后只是发送垃圾邮件yarn init并使用默认设置创建项目环境。

(如果使用时没有障碍的话yarn更喜欢它。)npm

然后,我使用以下express命令在本地安装到我的项目中:



yarn add express


Enter fullscreen mode Exit fullscreen mode

您还可以使用:



npm install express


Enter fullscreen mode Exit fullscreen mode

然后,我创建了单个源文件index.js并插入以下几行:



// import express
const express = require('express');

// create new express app and assign it to `app` constant
const app = express();

// server port configuration
const PORT = 8080;

// create a route for the app
app.get('/', (req, res) => {
  res.send('Hello dev.to!');
});

// server starts listening the `PORT`
app.listen(PORT, () => {
  console.log(`Server running at: http://localhost:${PORT}/`);
});


Enter fullscreen mode Exit fullscreen mode

到目前为止,我导入了express包,创建了它的一个实例并将其分配给app。设置我的变量,并在我的 API 服务器中PORT创建了一个处理路由,并调用方法启动我的服务器监听指定的端口。endpointapp.list(PORT, callback())

回到我的终端并在我的项目目录中执行以下命令:



node index.js


Enter fullscreen mode Exit fullscreen mode

它启动我的服务器并记录到控制台如下:



Server running at http://localhost:8080/


Enter fullscreen mode Exit fullscreen mode

然后,我切换到浏览器并浏览http://localhost:8080/,出现以下页面:

替代文本

到目前为止一切顺利。我的应用正确地监听了我的端口。
之后,我测试了最初的尝试,并想测试是否可以处理更多端点。所以我刚刚route在代码中添加了另一个端点。



app.get('/omergulen', (req, res) => {
  res.send('Hello Omer! Welcome to dev.to!');
});


Enter fullscreen mode Exit fullscreen mode

/omergulen我希望这仅当我在浏览器中输入端点时才起作用。

因此,我停止了正在运行的服务器Control+C,然后重新启动,因为我的应用程序本身不支持热重载。我切换到浏览器,访问了http://localhost:8080/omergulen,结果显示一切正常。为了确认,我又访问了http://localhost:8080/,结果也正常。

替代文本

2. 为什么以及如何在 Express 中使用中间件?

在我的第一个 API 服务器部署之后,我切换到我的 Web 应用程序项目并向我的 API 端点发送了获取请求。



fetch('MY_API_URL')
  .then(function (response) {
    console.log(response);
    return response.json();
  })
  .then(...);


Enter fullscreen mode Exit fullscreen mode

我的 DOM 中没有发生任何事情,但控制台消息令人沮丧。



Access to fetch at 'MY_API_URL' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

App.js:34 Cross-Origin Read Blocking (CORB) blocked cross-origin response MY_API_URL with MIME type application/json. See https://www.chromestatus.com/feature/5629709824032768 for more details.


Enter fullscreen mode Exit fullscreen mode

经过一些快速研究后,我意识到我需要根据来配置我的 API 服务器CORS Policy

首先,我已将以下内容添加mode: 'cors'到我的获取请求中:



fetch('MY_API_URL', {
  mode: 'cors'
})
.then(function (response) {
  console.log(response);
  return response.json();
})
.then(...);


Enter fullscreen mode Exit fullscreen mode

它本身对我的问题毫无用处。然后,我cors实际上只用了两行代码就将中间件添加到了 API 服务器。

安装软件包后cors



yarn add cors


Enter fullscreen mode Exit fullscreen mode

我刚刚在我的代码中添加了以下几行:



// import `cors` package
const cors = require('cors');

// use middleware
app.use(cors());


Enter fullscreen mode Exit fullscreen mode

按照这些配置运行后,我的问题暂时解决了。

3.如何将 Express API Server 设置为 HTTPS 服务?

为了部署,我将项目迁移到了我的 VPS,并将my_api_url域名重定向到了这个 VPS。这样,我就为我的服务器 IP 添加了一层抽象。而且,我不需要到处输入我的 IP,而是可以使用我自己的域名以及一些像 这样的高级子域名api.omergulen.com

这一步我首先尝试在HTTP上进行无认证的部署。



[blocked] The page at 'https://my_web_app'  was loaded over HTTPS but ran insecure content from 'http://my_api_url': this content should also be loaded over HTTPS.


Enter fullscreen mode Exit fullscreen mode

然而,我的 Web 服务器在 Firebase Hosting 上,并且以 https 的形式提供服务,发送HTTPS to HTTP这种名为“混合内容”的请求是不允许的。

所以,我只是把它放在sURL 的开头:))

https://my_api_url正如您所猜测的,它也没有起作用。



GET https://my_api_url net::ERR_SSL_PROTOCOL_ERROR


Enter fullscreen mode Exit fullscreen mode

然后,经过一番深入研究,我意识到我需要向证书颁发机构 (Certificate Authority) 申请证书。许多证书颁发机构都需要付费,但Let's Encrypt却不需要。

Let's Encrypt 是一个免费、自动化、开放的证书颁发机构。

如果您有服务器的 shell 访问权限,建议您使用certbot

certbot网站中,我选择了:

我的 HTTP 网站正在运行,None of the aboveUbuntu 16.04 (xenial)适合我的情况。

在开始之前,他们希望您确保:

  • 熟悉命令行
  • 以及一个 HTTP 网站(在我的例子中是 API 服务器)
  • 也就是online
  • 并在 HTTP 端口上提供服务(80
  • 托管在server
  • 您可以通过以下方式访问SSH
  • 有能力sudo

然后只需执行以下步骤:

1. 通过 SSH 连接到服务器

以具有 sudo 权限的用户身份通过​​ SSH 进入运行 HTTP 网站的服务器。

2. 添加 Certbot PPA

您需要将 Certbot PPA 添加到您的存储库列表中。为此,请在计算机上的命令行上运行以下命令:



sudo apt-get update &&
sudo apt-get install software-properties-common &&
sudo add-apt-repository universe &&
sudo add-apt-repository ppa:certbot/certbot &&
sudo apt-get update


Enter fullscreen mode Exit fullscreen mode

3. 安装 Certbot

在机器上的命令行上运行此命令来安装 Certbot。



sudo apt-get install certbot


Enter fullscreen mode Exit fullscreen mode

4. 选择您想要运行 Certbot 的方式

您同意暂时停止您的网站吗?

是的,我的网络服务器目前没有在这台机器上运行。

停止您的 Web 服务器,然后运行此命令获取证书。Certbot 将在您的计算机上临时启动 Web 服务器。



sudo certbot certonly --standalone


Enter fullscreen mode Exit fullscreen mode

不,我需要保持我的网络服务器运行。

如果您有一个已经在使用端口 80 的 Web 服务器,并且不想在 Certbot 运行时停止它,请运行此命令并按照终端中的说明进行操作。



sudo certbot certonly --webroot


Enter fullscreen mode Exit fullscreen mode

在此步骤中,您需要将您的域名插入终端,例如dev.to。之后,它将检查您的Web服务器并查找它将要创建的特定文件,如果成功,它将打印如下内容:



Performing the following challenges:
http-01 challenge for my_api_url
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/my_api_url/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/my_api_url/privkey.pem
   Your cert will expire on 2020-04-01. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le


Enter fullscreen mode Exit fullscreen mode

重要提示:
要使用 webroot 插件,您的服务器必须配置为从隐藏目录提供文件。如果/.well-known您的 Web 服务器配置对其进行了特殊处理,您可能需要修改配置以确保/.well-known/acme-challengeWeb 服务器能够提供隐藏目录中的文件。

4. 安装签名证书到 Express API 服务器

您需要在 API 服务器的配置文件中安装新证书。

首先,您需要安装并导入一些模块:



yarn add https


Enter fullscreen mode Exit fullscreen mode


// import packages
const https = require('https');
const fs = require('fs');

// serve the API with signed certificate on 443 (SSL/HTTPS) port
const httpsServer = https.createServer({
  key: fs.readFileSync('/etc/letsencrypt/live/my_api_url/privkey.pem'),
  cert: fs.readFileSync('/etc/letsencrypt/live/my_api_url/fullchain.pem'),
}, app);

httpsServer.listen(443, () => {
    console.log('HTTPS Server running on port 443');
});


Enter fullscreen mode Exit fullscreen mode

如果您还想在请求HTTP中维护请求HTTPS,那么也可以添加以下行:



const http = require('http');

// serve the API on 80 (HTTP) port
const httpServer = http.createServer(app);

httpServer.listen(80, () => {
    console.log('HTTP Server running on port 80');
});


Enter fullscreen mode Exit fullscreen mode

最后,您的最终 API 服务器代码将类似于以下内容:



// import required packages
const express = require('express');
const cors = require('cors');

const https = require('https');
const http = require('http');

const fs = require('fs');


const app = express();
app.use(cors());

// create new express app and save it as "app"
const app = express();
app.use(cors());

// create a route for the app
app.get('/', (req, res) => {
  res.send('Hello dev.to!');
});

// another route
app.get('/omergulen', (req, res) => {
  res.send('Hello Omer! Welcome to dev.to!');
});

// Listen both http & https ports
const httpServer = http.createServer(app);
const httpsServer = https.createServer({
  key: fs.readFileSync('/etc/letsencrypt/live/my_api_url/privkey.pem'),
  cert: fs.readFileSync('/etc/letsencrypt/live/my_api_url/fullchain.pem'),
}, app);

httpServer.listen(80, () => {
    console.log('HTTP Server running on port 80');
});

httpsServer.listen(443, () => {
    console.log('HTTPS Server running on port 443');
});


Enter fullscreen mode Exit fullscreen mode

5. 证书的自动续期和测试

系统上的 Certbot 软件包附带一个 cron 作业或 systemd 计时器,它会在证书到期前自动续订。除非您更改配置,否则无需再次运行 Certbot。您可以运行以下命令来测试证书的自动续订功能:



sudo certbot renew --dry-run


Enter fullscreen mode Exit fullscreen mode

更新 certbot 的命令安装在以下位置之一:



/etc/crontab/
/etc/cron.*/*
systemctl list-timers


Enter fullscreen mode Exit fullscreen mode

如果您需要停止 Web 服务器来运行 Certbot,则需要编辑内置命令,添加--pre-hook--post-hook标志,以自动停止和启动 Web 服务器。例如,如果您的 Web 服务器是 HAProxy,请在certbot renew命令中添加以下内容:



--pre-hook "service haproxy stop" --post-hook "service haproxy start"


Enter fullscreen mode Exit fullscreen mode

有关更新证书的更多信息,请参阅Certbot 文档

确认 Certbot 正常工作

要确认您的网站设置正确,请访问https://yourwebsite.com/浏览器并在 URL 栏中查找锁定图标。如果您想检查是否拥有顶级安装,可以前往https://www.ssllabs.com/ssltest/

做得好!您已经完成了本篇冗长的教程。

完成这些步骤后,您最终可以转到您的 API 服务器 URL,并且您应该会看到Hello dev.to!

感谢阅读

我希望本教程能够对您有所帮助。

您可以在这里查看我的上一篇文章:

欢迎通过omrglen@gmail.com与我联系

我愿意接受对未来文章的建议和请求,再见😃

新年快乐!🥳🥳🥳

文章来源:https://dev.to/omergulen/step-by-step-node-express-ssl-certificate-run-https-server-from-scratch-in-5-steps-5b87
PREV
向 Google 电子表格提交表单
NEXT
玻璃态:即将到来的 UI 趋势