为客户域生成 SSL 证书并与 Python Flask 集成
Generating SSL Certs for Customer Domains and integrating with Python Flask
所以,这就是我 运行 遇到的问题,我正在尝试构建一个非常小规模的 MVP 应用程序,我将很快发布它。从使用 Dokku 部署 Flask 应用程序(我稍后会升级到更好的东西),我已经能够弄清楚所有事情,并且已经能够在该应用程序上进行大部分工作,包括 S3 上传、条带集成等。这是一个我坚持的事情,我如何为客户即时生成 SSL 证书,然后 link 一切都返回到 Python 应用程序?以下是我的想法:
一旦域指向我的服务器,我可以使用一个简单的脚本并连接到 Letsencrypt API 来生成和请求证书。我 运行 遇到的问题是,一旦指向域,我怎么知道? Dokku 不会将所有传入请求连接到我的容器,因此 Flask 无法检测到它,除非我使用 dokku domains:add
命令手动连接它?
有没有更好的方法来解决这个问题?我知道 Cloudflare 的 SaaS SSL,但它似乎只适用于他们的企业客户,我需要一个像这样的强大解决方案,我不介意构建但只需要一些指示(除非已经有解决方案免费 - 无需重新发明轮子,嗯?)。另一件事,将来我确实计划让我的数据库 运行 分开,负载均衡器指向我的应用程序的多个不同实例(不会是一个主要问题,因为数据库仍然是中心,但只是担心IP 部分)。回顾一下:
客户端域 (example.io) -> dns1.example.com -> 让我们加密 SSL 证书 -> Dokku 容器 -> 我的应用程序
如果我需要重新解释什么,请告诉我,谢谢!
您的解决方案是通配符证书,或者使用应用前缀。
所以我不确定为什么您需要为每个客户提供证书,但假设您要这样做
customer1.myapp.com
-> 路由到 customer1 后端。不管什么原因。
Let's Encrypt 允许您注册 *。myapp.com 因此您可以为每个客户使用子域。
备选方案是客户前缀。
假设您的应用 URL 看起来像 www.myapp.com/api/v1/somecomand
您可以使用 www.myapp.com/api/v1/customerID/somecommand
,然后允许您的负载均衡器根据前缀进行路由,并使用重写规则将客户 ID 删除回原始 URL。
这更复杂,它依赖于负载均衡器,但第一个解决方案也是如此。
综上所述,这两种解决方案很可能都需要每个客户一个单独的应用程序实例,这是一个繁重的解决方案,但如果这是您想要的并且正在使用轻量级容器或为每个服务器部署多个实例,那很好。
无论如何,需要更多的信息才能给出可靠的解决方案。
我想更简单的方法是在 python 应用程序前面使用 Nginx 容器。因为你可以在不重启服务器的情况下重新读取 Nginx 配置。
我没有使用 Dokku,所以请尝试解释如何使用 docker 简单地创建基础设施。
- 您的路由器上有全局 IP(例如
1.1.1.1
),将 80
和 443
端口转发到内部服务器 IP(设为 192.168.1.100
)。全局 80
到本地 8080
和全局 443
到本地 8443
.
- 您有 Nginx 容器监听
192.168.1.100:8080
和 192.168.1.100:8443
并通过 HTTP 协议 代理从 8443
到 127.0.0.1:8888
的所有请求
- 您有应用程序容器监听
127.0.0.1:8888
并且只能从本地服务器访问
工作流程将是:
- 客户注册 DNS A 记录:
customer.domain.com A 1.1.1.1
并将其指向您的服务器
- 客户使用一些控制网页将域添加到您的数据库(取决于您的服务)
- 数据库中的新记录通过某些触发器启动工作容器
- Worker 容器开始使用某些
nslookup
工具检查域是否存在
- 如果域已注册,worker 开始让我们加密脚本并颁发新证书(通过将
.well-known/acme-challenge
文件添加到 Nginx html 文件夹)
- 如果证书成功颁发,worker 将新的配置文件添加到 Nginx 容器中(更好的方法是从 docker 主机挂载配置目录)和 reload Nginx 配置
- 利润
如果您需要使用自己的 DNS 服务器,您必须使用一些 API 以编程方式控制它,以便能够由工作人员添加 DNS A 记录。 (好消息!在这种情况下,您可以通过将 acme-challenge 代码添加为 DNS TXT(或者 CNAME?)记录而不是 Nginx .well-known
目录来使用 Let's Encrypt 的 DNS 挑战)
实际上,实现很大程度上取决于您拥有的基础架构。这确实是一项艰巨的任务,取决于许多细节。所以在不知道的情况下很难回答得更好。
所以,这就是我 运行 遇到的问题,我正在尝试构建一个非常小规模的 MVP 应用程序,我将很快发布它。从使用 Dokku 部署 Flask 应用程序(我稍后会升级到更好的东西),我已经能够弄清楚所有事情,并且已经能够在该应用程序上进行大部分工作,包括 S3 上传、条带集成等。这是一个我坚持的事情,我如何为客户即时生成 SSL 证书,然后 link 一切都返回到 Python 应用程序?以下是我的想法:
一旦域指向我的服务器,我可以使用一个简单的脚本并连接到 Letsencrypt API 来生成和请求证书。我 运行 遇到的问题是,一旦指向域,我怎么知道? Dokku 不会将所有传入请求连接到我的容器,因此 Flask 无法检测到它,除非我使用 dokku domains:add
命令手动连接它?
有没有更好的方法来解决这个问题?我知道 Cloudflare 的 SaaS SSL,但它似乎只适用于他们的企业客户,我需要一个像这样的强大解决方案,我不介意构建但只需要一些指示(除非已经有解决方案免费 - 无需重新发明轮子,嗯?)。另一件事,将来我确实计划让我的数据库 运行 分开,负载均衡器指向我的应用程序的多个不同实例(不会是一个主要问题,因为数据库仍然是中心,但只是担心IP 部分)。回顾一下:
客户端域 (example.io) -> dns1.example.com -> 让我们加密 SSL 证书 -> Dokku 容器 -> 我的应用程序
如果我需要重新解释什么,请告诉我,谢谢!
您的解决方案是通配符证书,或者使用应用前缀。
所以我不确定为什么您需要为每个客户提供证书,但假设您要这样做
customer1.myapp.com
-> 路由到 customer1 后端。不管什么原因。
Let's Encrypt 允许您注册 *。myapp.com 因此您可以为每个客户使用子域。
备选方案是客户前缀。
假设您的应用 URL 看起来像 www.myapp.com/api/v1/somecomand
您可以使用 www.myapp.com/api/v1/customerID/somecommand
,然后允许您的负载均衡器根据前缀进行路由,并使用重写规则将客户 ID 删除回原始 URL。
这更复杂,它依赖于负载均衡器,但第一个解决方案也是如此。
综上所述,这两种解决方案很可能都需要每个客户一个单独的应用程序实例,这是一个繁重的解决方案,但如果这是您想要的并且正在使用轻量级容器或为每个服务器部署多个实例,那很好。
无论如何,需要更多的信息才能给出可靠的解决方案。
我想更简单的方法是在 python 应用程序前面使用 Nginx 容器。因为你可以在不重启服务器的情况下重新读取 Nginx 配置。
我没有使用 Dokku,所以请尝试解释如何使用 docker 简单地创建基础设施。
- 您的路由器上有全局 IP(例如
1.1.1.1
),将80
和443
端口转发到内部服务器 IP(设为192.168.1.100
)。全局80
到本地8080
和全局443
到本地8443
. - 您有 Nginx 容器监听
192.168.1.100:8080
和192.168.1.100:8443
并通过 HTTP 协议 代理从 - 您有应用程序容器监听
127.0.0.1:8888
并且只能从本地服务器访问
8443
到 127.0.0.1:8888
的所有请求
工作流程将是:
- 客户注册 DNS A 记录:
customer.domain.com A 1.1.1.1
并将其指向您的服务器 - 客户使用一些控制网页将域添加到您的数据库(取决于您的服务)
- 数据库中的新记录通过某些触发器启动工作容器
- Worker 容器开始使用某些
nslookup
工具检查域是否存在 - 如果域已注册,worker 开始让我们加密脚本并颁发新证书(通过将
.well-known/acme-challenge
文件添加到 Nginx html 文件夹) - 如果证书成功颁发,worker 将新的配置文件添加到 Nginx 容器中(更好的方法是从 docker 主机挂载配置目录)和 reload Nginx 配置
- 利润
如果您需要使用自己的 DNS 服务器,您必须使用一些 API 以编程方式控制它,以便能够由工作人员添加 DNS A 记录。 (好消息!在这种情况下,您可以通过将 acme-challenge 代码添加为 DNS TXT(或者 CNAME?)记录而不是 Nginx .well-known
目录来使用 Let's Encrypt 的 DNS 挑战)
实际上,实现很大程度上取决于您拥有的基础架构。这确实是一项艰巨的任务,取决于许多细节。所以在不知道的情况下很难回答得更好。