使用 Nginx 为多租户应用提供 HTTPS 服务

使用 Nginx 为多租户应用提供 HTTPS 服务

我们有一个多租户应用程序(dotnet core + Angular),主网站网址为https://example.com,客户 URL 是(http://cust1.example.com,http://cust2.example.com,......)

如果客户需要使用自己的域名,他只需要将他的域名重定向到我们的服务器,例如:客户 1 有自己的域名:customer1.com,因此他将转到域名设置并编辑 DNS 设置以引用我们的服务器 IP 记录 @ = XXXX(我们的服务器 IP)记录 CNAME www = cust1.example.com 然后他可以使用他的域名打开他的应用程序(http://customer1.com),而不是使用(http://cust1.example.com

不,我们进入下一步并使用 HTTPS,我已经使用 certbot 创建了 LetsEncrypt 通配符证书:sudo certbot --serverhttps://acme-v02.api.letsencrypt.org/directory-d *.example.com --manual --preferred-challenges dns-01 certonly

现在,如果您使用以下方式访问该应用程序,则该应用程序将以 HTTPS 形式运行 (https://cust1.example.com)并且运行良好,

但问题是,如何使用不同的域名提供 HTTPS,假设我想访问https://customer1.com,显然无法提供服务,因为这个域名的服务器中没有证书。

我们需要一种自动化的方法来为新域创建证书,而无需在 nginx 配置文件中创建新的块,因为可能有 100000 个客户,因此不可能手动完成。

这是我现在的 Nginx 配置文件

server {
    listen 80 default_server;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl default_server;
    server_name example.com *.example.com;

    access_log /var/log/nginx/example.com.access.log;
    error_log /var/log/nginx/example.com.error.log;
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:5000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

我尝试过在 Nginx 中使用 Lua,但是没有找到方法。

有人能提出解决这个问题的建议吗?

答案1

我建议使用 Ansible 作为此任务的配置工具,因为它允许您使用模板和变量来设置客户的 SaaS 系统站点。在您的案例中,这可能看起来有点过度和重复,但一旦您开始在同一站点列表上实施其他基础设施任务,它将带来巨大的好处。通常我会期望以下内容:

  • SSL/Letsencrypt 续订
  • 客户特定的备份脚本
  • 任何其他大规模变化

具有角色的最小设置(未测试语法或任何内容)如下所示:

组变量/全部:

sites:
 - { name: customer1.yoursaas.com, user: www_customer1, memory_limit: "256M", max_children: 2, port: 5000 }
 - { name: yoursaas.customerdomain.com, user: www_customer2, memory_limit: "256M", max_children: 2, port: 5001  }

角色/nginx/任务/main.yml:

---

- name: copy host files
  template: src=nginx-host.j2 dest=/etc/nginx/sites-available/{{item.name}} owner=root group=root mode=0644
  with_items:
   - "{{sites}}"
  notify:
     - reload nginx
  tags:
   - nginx

角色/nginx/模板/nginx-host.j2:

server {
    listen 80 default_server;
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl default_server;
    server_name {{item.name}};

    access_log /var/log/nginx/{{item.name}}.access.log;
    error_log /var/log/nginx/{{item.name}}.error.log;
    ssl_certificate /etc/letsencrypt/live/{{item.name}}/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/{{item.name}}/privkey.pem;

    location / {
        proxy_pass http://localhost:{{item.port}};
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection keep-alive;
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
     }

}

web服务器.yml:

---
- hosts: tag_group_web_servers
  vars_files:
    - group_vars/all
    - group_vars/vault

  roles:
    - nginx

我对此进行了过度简化,但在包括 Saas 应用程序在内的所有网络托管基础设施管理中都使用它。

另一个好处是,使用配置工具,您可以拥有非常详细(重复)的配置文件,而无需额外的工作和重复导致错误的风险。这让其他人更容易理解某些东西是如何配置的。

答案2

我希望您可以使用下面提到的 vhost 文件找到解决方案。

server {
    server_name *.myapp.io;
}

server {
    server_name ~^(?<account>.+)\.myapp\.io$;

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
        fastcgi_param ACCOUNT $account; # $_SERVER['ACCOUNT']
    }
}

server {
    server_name ~^(?<account>.+)\.myapp\.io$;

    root /var/www/$account;

    access_log /var/log/nginx/$account-access.log;
    error_log  /var/log/nginx/$account-error.log;
}

相关内容