SaaS产品客户的自定义域名功能

14

我使用Angular 4构建了一个SaaS产品,并集成了Golang REST API,将构建上传到了AWS EC2实例上。我的项目是基于多租户的应用程序,它在商家名称.mystore.com子域名上加载客户仪表板,但一些客户要求提供自定义域名功能,比如他们应该能够在mydomain.com上加载应用程序。

我已经通过在apache2.conf文件中添加以下代码来完成子域名部分,因此所有子域名都从包含Angular应用程序文件的apps文件夹加载。

<VirtualHost *:80>
    ServerAlias *.mystore.com
   DocumentRoot /var/www/html/apps
    <Directory "/var/www/html/apps">
        AllowOverride All
        Require all Granted
    </Directory>
</VirtualHost>

为了实现自定义域名功能,我在管理员中有一个部分可以保存自定义域名,但不确定应该如何实现。

我考虑的可能方法有:

  1. 创建虚拟主机文件,并在每个商家注册时使用其自定义域名进行更新
  2. 使用htaccess文件和mod_rewrite来完成它

Shopify可以做到这一点,但不确定他们如何加载特定商家的商店。另一个让我忙于思考的问题是我应该要求更新哪些值:

  1. 域名注册商上的IP地址
  2. 名称服务器(不确定对于我的AWS会是什么)
  3. 根据某些文章的建议要求创建CNAME或A记录
2个回答

20

我在开发和管理多个SaaS平台上有类似的设置。这种设置肯定是可取的,正如您的客户所建议的那样。您应该计划为每个客户网站提供自己的域名,并从一开始就使用* SSL。在我看来,这是今天设计良好的SaaS服务的最佳实践。

阅读您的问题时,我认为您可能有点过于工程化了。

对于同一服务器上的自定义域名SaaS应用程序,您只需向所有流量打开80端口,无论域名如何。将所有客户域指向app.mystore.com,该CNAME是您应用程序终结点的别名。

然后,应用程序会读取HTTP请求头,并以此确定所请求的主机名。

最后,应用程序在其客户端数据库中查找主机名,并定位给定客户域的客户记录。

例如,在Nginx中,您只需要:

server {
    listen       80 default_server;
    server_name  _;
    root         /var/www/myservice/htdocs;
}

这种服务器配置为指向此端点的任何域提供了一个万能处理方式。

这就是Web服务器所需要的,以允许其响应任何客户域。应用程序必须完成其余部分。

* 当您在此域上为应用程序提供自定义域时,您应该计划为该域提供SSL终端节点,例如https://www.mycustomdomain.com。在您的架构设计中考虑到这一点。还要考虑DNS问题,尤其是如果您的应用程序故障转移到新IP。


3
如何在您的服务器上为无法控制的域安装第三方SSL证书?我已经使用CNAME使一切正常,即vanity.mycompany.com映射到app.mysaas.com。mysaas.com具有通配符证书*.mysaas.com,而vanity.mycompany.com具有自己的证书,但我无法弄清楚如何停止安全警告。 - SilenceKit

1
被接受的答案是令人满意的,但它只概述了最重要的部分,即通过为第三方域名发放证书启用HTTPS。
如果您的客户只是将CNAME指向您的域或将A记录创建到您的IP,并且您不处理这些自定义域的TLS终止,则您的应用程序将不支持HTTPS,而没有它,您的应用程序将无法在这些自定义域中的现代浏览器上运行。
您需要在Web服务器前面设置一个TLS终止反向代理。此代理可以在单独的计算机上运行,但也可以在与Web服务器相同的计算机上运行。
CNAME vs A记录
如果您的客户想要在其子域上拥有您的应用程序,例如 `app.customer.com`,他们可以创建指向您的代理的CNAME `app.customer.com`。
如果他们想要在其根域上拥有您的应用程序,例如 `customer.com`,则他们必须在指向您的代理的`customer.com`上创建A记录。确保此IP地址永远不会更改!
如何处理TLS终止?
要使TLS终止工作,您需要为这些自定义域发出TLS证书。您可以使用Let's Encrypt。您的代理将查看传入请求的“Host”标头,例如 `app.customer1.com` 或 `customer2.com` 等。然后,它将通过检查SNI决定使用哪个TLS证书。
可以设置代理自动为这些自定义域发出和更新证书。对于来自新的自定义域的第一次请求,代理将看到它没有适当的证书。它将请求Let's Encrypt发出新证书。Let's Encrypt将首先发出一个挑战以查看您是否管理该域名,并且由于客户已经创建了指向您的代理的CNAME或A记录,这告诉Let's Encrypt您确实在管理该域名,因此它将让您为其发出证书。
要自动发出和更新证书,我建议使用Caddy、greenlock.js、OpenResty(Nginx)。
在后端如何处理它
您的代理正在终止TLS并将请求代理到后端。然而,您的后端不知道请求背后的原始客户是谁。这就是为什么您需要告诉您的代理在代理请求时包含其他标头以标识客户的原因。只需添加 `X-Serve-For: app.customer.com` 或 `X-Serve-For: customer2.com` 或任何原始请求的“Host”标头。
现在,当您在后端接收代理请求时,您可以读取此自定义标头,您就知道请求背后的客户是谁。您可以根据此实现逻辑,显示属于此客户的数据等。

更多

在代理服务器集群前面放置一个负载均衡器,可以提高可用性。您还需要使用分布式存储来存储证书和Let's Encrypt挑战。如果出现故障,请使用AWS ECS或EBS进行自动恢复,否则,您可能会在半夜被强制重启机器或手动操作代理。

另外,最近出现了一些服务(例如此类服务),允许您在不自己运行基础设施的情况下将自定义域名添加到应用程序中。

如果需要更多详细信息,可以通过Twitter私信我:@dragocrnjac


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接