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
之后只是发送垃圾邮件yarn init
并使用默认设置创建项目环境。
(如果使用时没有障碍的话我yarn
更喜欢它。)npm
然后,我使用以下express
命令在本地安装到我的项目中:
yarn add express
您还可以使用:
npm install express
然后,我创建了单个源文件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}/`);
});
到目前为止,我导入了express
包,创建了它的一个实例并将其分配给app
。设置我的变量,并在我的 API 服务器中PORT
创建了一个处理路由,并调用方法启动我的服务器监听指定的端口。endpoint
app.list(PORT, callback())
回到我的终端并在我的项目目录中执行以下命令:
node index.js
它启动我的服务器并记录到控制台如下:
Server running at http://localhost:8080/
然后,我切换到浏览器并浏览http://localhost:8080/
,出现以下页面:
到目前为止一切顺利。我的应用正确地监听了我的端口。
之后,我测试了最初的尝试,并想测试是否可以处理更多端点。所以我刚刚route
在代码中添加了另一个端点。
app.get('/omergulen', (req, res) => {
res.send('Hello Omer! Welcome to dev.to!');
});
/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(...);
我的 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.
经过一些快速研究后,我意识到我需要根据来配置我的 API 服务器CORS Policy
。
首先,我已将以下内容添加mode: 'cors'
到我的获取请求中:
fetch('MY_API_URL', {
mode: 'cors'
})
.then(function (response) {
console.log(response);
return response.json();
})
.then(...);
它本身对我的问题毫无用处。然后,我cors
实际上只用了两行代码就将中间件添加到了 API 服务器。
安装软件包后cors
:
yarn add cors
我刚刚在我的代码中添加了以下几行:
// import `cors` package
const cors = require('cors');
// use middleware
app.use(cors());
按照这些配置运行后,我的问题暂时解决了。
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.
然而,我的 Web 服务器在 Firebase Hosting 上,并且以 https 的形式提供服务,发送HTTPS to HTTP
这种名为“混合内容”的请求是不允许的。
所以,我只是把它放在s
URL 的开头:))
https://my_api_url
正如您所猜测的,它也没有起作用。
GET https://my_api_url net::ERR_SSL_PROTOCOL_ERROR
然后,经过一番深入研究,我意识到我需要向证书颁发机构 (Certificate Authority) 申请证书。许多证书颁发机构都需要付费,但Let's Encrypt却不需要。
Let's Encrypt 是一个免费、自动化、开放的证书颁发机构。
如果您有服务器的 shell 访问权限,建议您使用certbot。
在certbot
网站中,我选择了:
我的 HTTP 网站正在运行,None of the above
这Ubuntu 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
3. 安装 Certbot
在机器上的命令行上运行此命令来安装 Certbot。
sudo apt-get install certbot
4. 选择您想要运行 Certbot 的方式
您同意暂时停止您的网站吗?
是的,我的网络服务器目前没有在这台机器上运行。
停止您的 Web 服务器,然后运行此命令获取证书。Certbot 将在您的计算机上临时启动 Web 服务器。
sudo certbot certonly --standalone
不,我需要保持我的网络服务器运行。
如果您有一个已经在使用端口 80 的 Web 服务器,并且不想在 Certbot 运行时停止它,请运行此命令并按照终端中的说明进行操作。
sudo certbot certonly --webroot
在此步骤中,您需要将您的域名插入终端,例如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
重要提示:
要使用 webroot 插件,您的服务器必须配置为从隐藏目录提供文件。如果/.well-known
您的 Web 服务器配置对其进行了特殊处理,您可能需要修改配置以确保/.well-known/acme-challenge
Web 服务器能够提供隐藏目录中的文件。
4. 安装签名证书到 Express API 服务器
您需要在 API 服务器的配置文件中安装新证书。
首先,您需要安装并导入一些模块:
yarn add https
// 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');
});
如果您还想在请求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');
});
最后,您的最终 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');
});
5. 证书的自动续期和测试
系统上的 Certbot 软件包附带一个 cron 作业或 systemd 计时器,它会在证书到期前自动续订。除非您更改配置,否则无需再次运行 Certbot。您可以运行以下命令来测试证书的自动续订功能:
sudo certbot renew --dry-run
更新 certbot 的命令安装在以下位置之一:
/etc/crontab/
/etc/cron.*/*
systemctl list-timers
如果您需要停止 Web 服务器来运行 Certbot,则需要编辑内置命令,添加--pre-hook
和--post-hook
标志,以自动停止和启动 Web 服务器。例如,如果您的 Web 服务器是 HAProxy,请在certbot renew
命令中添加以下内容:
--pre-hook "service haproxy stop" --post-hook "service haproxy start"
有关更新证书的更多信息,请参阅Certbot 文档。
确认 Certbot 正常工作
要确认您的网站设置正确,请访问https://yourwebsite.com/
浏览器并在 URL 栏中查找锁定图标。如果您想检查是否拥有顶级安装,可以前往https://www.ssllabs.com/ssltest/。
做得好!您已经完成了本篇冗长的教程。
完成这些步骤后,您最终可以转到您的 API 服务器 URL,并且您应该会看到Hello dev.to!
。
感谢阅读
我希望本教程能够对您有所帮助。
您可以在这里查看我的上一篇文章:
我愿意接受对未来文章的建议和请求,再见😃
新年快乐!🥳🥳🥳
文章来源:https://dev.to/omergulen/step-by-step-node-express-ssl-certificate-run-https-server-from-scratch-in-5-steps-5b87