使用 Traefik 和 Docker 在 Node.js 服务器上部署并自动配置 SSL 证书。
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
在本教程中,我们将学习如何在基于 Linux 的 VPS 上使用 Docker 部署 Node.js 服务器,并使用 Traefik 自动配置 SSL 证书。
先决条件:
- 熟悉Node.js、docker和docker-compose的基本知识。
- 您可以从任何云服务提供商处选择具有公共 IP 地址的虚拟专用服务器。
- 域名或子域名以及指向您的 VPS 公网 IP 地址的相应 DNS 记录。
介绍
Traefik 是一个开源的云原生反向代理。反向代理本质上位于服务器前端,负责处理传入的客户端请求。因此,客户端请求不会直接发送到您的 Node.js 服务器,而是先经过 Traefik,然后由 Traefik 将其转发到您的服务器。这使得我们可以实现 SSL 加密、金丝雀部署、负载均衡等功能。
现在让我们开始吧!
启动一个 Linux VPS
这可以是亚马逊 EC2 实例、Digital Ocean Droplet、Linode 虚拟机等等,甚至是拥有公网 IP 地址的本地 Linux 服务器。在本演示中,我使用的是 Digital Ocean 的 Ubuntu Droplet。
安装 Docker 和 Docker Compose。
本教程重点介绍部署阶段。您可以阅读 Docker 文档,了解如何在您的平台上安装Docker和Docker Compose 。
防火墙限制
根据您的 VPS 和配置,请确保端口 80 和端口 443 均可从外部访问。这可能意味着需要调整 AWS VPC 中安全组的入站规则,或者在 ufw 防火墙上打开相应的端口。
DNS 记录
如果您尚未创建 DNS 记录,请为您的域名或子域名创建一条 DNS 记录,并将其指向您的 VPS 的公网 IP 地址。您可以通过 ping 您的域名并查看其是否解析到 VPS 的 IP 地址来确认 DNS 解析是否生效。如果您使用的是像 Cloudflare 这样支持代理的 DNS 提供商,则在测试期间可能需要关闭代理功能。
ping mydomian.com // should resolve to your VPS IP address
Node.js 服务器
在这个例子中,我将演示如何使用一个简单的 Fastify 服务器。
//server.js file
const fastify = require("fastify")({ logger: true });
fastify.get("/", async (request, reply) => {
return { message: "Hello world! I'm using fastify" };
});
const start = async () => {
try {
await fastify.listen(3000, "0.0.0.0");
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();
Docker 化的 Node.js 服务器
我们使用下面的 Dockerfile 将 Node.js 服务器容器化。
FROM node:12-alpine
RUN mkdir home/node-traefik
WORKDIR /home/node-traefik
COPY . .
RUN npm install
EXPOSE 3000
CMD [ "node", "server.js" ]
注意:这是一个关于如何将 Node.js 应用容器化的基本示例。对于生产环境用例,您应该阅读此处的Node.js 和 Docker 最佳实践指南。
Docker Compose
现在我们创建一个 docker-compose 文件,并在其中引用我们的 Dockerfile。此时,我们可以使用docker-compose up命令启动我们的 Node.js 服务器。
services:
node-server:
build:
context: ./
dockerfile: Dockerfile
ports:
- "3000:3000"
配置 Traefik
为了将 Traefik 引入我们的流程,我们在 docker-compose 文件中为 Traefik 创建了一个新服务。
services:
reverse-proxy:
image: traefik:v2.4
container_name: "traefik"
command:
- "--api.insecure=true"
- "--api.dashboard=true"
- "--api.debug=true"
- "--providers.docker=true"
- "--log.LEVEL=DEBUG"
- "--entryPoints.web.address=:80"
- "--entryPoints.websecure.address=:443"
- "--providers.docker.exposedbydefault=false"
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"
- "--certificatesresolvers.myresolver.acme.httpchallenge.entrypoint=web"
- "--certificatesresolvers.myresolver.acme.email=hello@paularah.com"
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"
ports:
- "443:443"
- "80:80"
- "8080:8080"
volumes:
- "./letsencrypt:/letsencrypt"
- "/var/run/docker.sock:/var/run/docker.sock:ro"
Traefik 具有静态配置和动态配置的概念。静态配置是 Traefik 启动时需要的,如果对静态配置进行了更改,则必须重启 Traefik 才能使更改生效。当使用 docker-compose 部署 Traefik 时,我们将静态配置定义为 docker-compose 文件中的命令。
让我们逐一分析静态配置中的每个命令。
- "--providers.docker=true"告诉 Traefik Docker 是我们的关键基础设施组件,因此 Traefik 会查询 Docker API 以获取所需的相关信息。--api.insecure启用 Traefik 控制面板时将采用不安全模式。对于生产环境,建议在控制面板上使用基本身份验证和 TLS。-
- "--providers.docker.exposedbydefault=false"告诉 traefik 除非明确要求,否则不要暴露服务。 -
挂载的卷
- "/var/run/docker.sock:/var/run/docker.sock:ro"允许 Traefik 与 Docker 通信。 -
该
- "--entryPoints.web.address=:80"行- "--entryPoints.websecure.address=:443"声明了网络以及 Traefik 中相应的端口入口点。 -
它
"--certificatesresolvers.myresolver.acme.email=hello@paularah.com会创建一个名为 的证书解析器myresolver。证书解析器负责生成、续订和销毁证书。 -
- "--certificatesresolvers.myresolver.acme.storage=/letsencrypt/acme.json"告诉我们的证书解析器将我们的证书保存到 letsencrypt 卷中的 acme.json 文件中。 -
- "--certificatesresolvers.myresolver.acme.httpchallenge=true"告诉证书解析器使用 HTTP 质询。
在这个阶段,如果我们启动容器,就可以通过 8080 端口访问 Traefik 控制面板http://<IP>:8080。
我们的 Node.js 服务器服务尚未与 Traefik 集成。这时就需要用到动态配置的概念。与静态配置不同,动态配置可以在 Traefik 启动后进行更新。Traefik 会监听动态配置的变化并自动应用,无需重启 Traefik。当使用 Docker 部署 Traefik 时,我们通过标签添加动态配置。Traefik 会读取这些元数据并将其应用到相应的服务中。
node-server:
build:
context: .
dockerfile: Dockerfile
container_name: node-server
labels:
- "traefik.enable=true"
- "traefik.http.routers.node-server.rule=Host(`play.paularah.com`)"
- "traefik.http.routers.node-server.entrypoints=websecure"
- "traefik.http.routers.node-server.tls.certresolver=myresolver"
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"
- "traefik.http.routers.redirs.rule=hostregexp(`{host:.+}`)"
- "traefik.http.routers.redirs.entrypoints=web"
- "traefik.http.routers.redirs.middlewares=redirect-to-https"
-
由于我们已将 Traefik 配置为除非明确指示,否则不公开服务,因此该
- "traefik.enable=true"标签现在将我们的 Node.js 服务器容器公开给了 Traefik。 -
- "traefik.http.routers.node-server.rule=Host(play.paularah.com)"创建一个路由器,将来自域的网络请求路由play.paularah.com到 Node.js 服务器容器。 -
- "traefik.http.routers.node-server.tls.certresolver=myresolver"告诉路由器使用我们之前创建的证书解析器。 -
- "traefik.http.middlewares.redirect-to-https.redirectscheme.scheme=https"创建一个中间件,强制将 HTTP 网络请求重定向到 HTTPS。
接下来的三个标签创建了一个路由器,该路由器匹配对端口 80 上主机的所有请求,然后使用我们之前创建的重定向到 https 中间件。
现在重启容器,瞧!我们的 Node.js 服务器现在可以访问了play.paularah.com,它使用 SSL 并强制重定向到 HTTPS。
概括
Traefik 让使用 Docker 部署 HTTP 服务器变得非常简单。我们只需向 docker-compose 文件中添加更多服务,即可在同一主机上部署多个项目。这种设置的一个主要优势在于,所有配置都集中在一个地方,只需一条命令docker-compose up即可启动并运行所有服务。这也使得整个设置易于复现,并允许我们轻松地将项目从一个云服务提供商迁移到另一个云服务提供商。
本文的源代码可在https://github.com/paularah/node-traefik找到。
文章来源:https://dev.to/paularah/deploy-and-automatically-provision-ssl-certs-on-a-node-js-server-with-traefik-and-docker-2j0e