0

We have a multi-tenant application (dotnet core + Angular), the main website url for https://example.com, The customers URLs are (http://cust1.example.com, http://cust2.example.com,......)

If the customer need to use his own domain, he just need to redirect his to domain to our server, for example: Customer 1 has his own domain: customer1.com, so he will go to domain setting and edit the DNS setting to refer to our server IP record @ = X.X.X.X (Our server IP) record CNAME www = cust1.example.com Then he can open his app using his domain (http://customer1.com) instead of using (http://cust1.example.com)

No, we go to the next step and use HTTPS, I have created a wildcard certificate with LetsEncrypt using certbot: sudo certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.example.com --manual --preferred-challenges dns-01 certonly

Now, the application works as HTTPS if you visit it with (https://cust1.example.com) and working fine,

But the problem is, how to serve the HTTPS with different domain names, let's say that I want to visit https://customer1.com, it's obviously cant serve because there is no certificate in the server with this domain name.

We need an automatic way to create a certificates to the new domains without create a new block in the nginx config file, because maybe will be 100000 customers, so it's impossible to do it manually.

Here is my Nginx config file now

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;
    }

}

I tried to use Lua with nginx, but I didn't find the way to do that,

Anyone can suggest a solution fir this issue?

0

I hope you can find solution with below mentioned vhost file.

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;
}
5
  • This is correct for subdomain, but what if the customer has his own domain, how to solve this issue? – Mhm0ud Dec 26 '19 at 9:36
  • It sounds like this could be better solved with a configuration management tool such as Ansible. There you could just create a dictionary of customer domains, or at least all customer owned ones and have a different nginx file for it – jdog Dec 27 '19 at 3:19
  • @jdog Could you please give an example – Mhm0ud Dec 27 '19 at 6:40
  • @jdog And is there a problem if we have 1000 or more customers in the future ?? – Mhm0ud Dec 27 '19 at 6:57
  • @Mahmoud have provided an answer. Ansible simply creates config files. Handling 1000s of those is simply an Nginx configuration question. – jdog Dec 27 '19 at 7:34
0

I would recommend Ansible as a configuration tool for this task, as it allows you to use templating and variables to set up your customers SaaS system sites. It may look like a bit of overkill and repetition in your case, but it would have huge benefits once you start implementing other infrastructure tasks on the same list of sites. Commonly I would expect things like:

  • SSL/ Letsencrypt renewal
  • customer specific backup scripts
  • any other mass changes

A minimal setup with roles, not tested for syntax or anything would look like this:

groups_vars/all:

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  }

roles/nginx/tasks/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

roles/nginx/templates/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;
     }

}

webserver.yml:

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

  roles:
    - nginx

I have oversimplified this, but use this across all infrastructure management for web hosting including Saas applications.

One more benefit is that with a configuration tool, you can have very verbose (repeated) config files without the extra work and risk of errors through repetition. This allows other people to easier understand how something is configured.

1
  • Thank you very much @jdog, I think I'm going to use Ansible to edit my nginx config file not to a add a new site file. because all customers whatever his domain, they forward to same website, and the website determine what is the DB need to get the data from it, depends on the domain name (one website, multiple DBs, for each customer different DB) But I have a different question please, did you know about lua-resty-auto-ssl, I read about it but I'm not sure how it can helpful for me in my case. – Mhm0ud Dec 28 '19 at 7:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.