Solution to point customers domains at our SAAS app - node.js

I have a SAAS application on node express. The app creates tenant sub-domains for each sign up like mybiz.ourgreatapp.com.
We want to allow the users to point a custom domain at that account/url, ie a domain they have bought.
somedomainibought.com---->mybiz.ourgreatapp.com
We also need that domain to be HTTPS.
Uur domain, and wildcard sub domains are SSL.
So: https://mybiz.ourgreatapp.com: works.
We have tried to solve the problem using https://www.cloudflare.com which works for our sub-domain routes but we can't set it up to use customers domains and point them at those routes.
How can we achieve this?

To create certificaes for different domains
You need to solve 2 problems:
that your customers should point their domains to your IP/domain in order to use your service. Solution for it: you can create a dedicated domain like cname.ourgreatapp.com. If customer wants to use his own custom domain - he should point his domain (in 99% cases it will be customer's subdomain) to your CNAME. In 1% cases when customer would like to attach domain - better to provide also public IP for such customers. As not all DNS providers support using CNAME for 1st level domain
that you need to issue certificate for the customer. When you issue a certificate, you must prove your rights for this domain (different certificates authorities provide multiple options in order to do it). Luckily when you already have a customer who already pointed to your CNAME - you can use "HTTP validation type" (when you should provide specific text at some URL and CA verifies that secret value is there by doing GET request. For example, free LetsEncrypt certificate provider will verify specific value at the URL customersdomain.com/.well-known/acme-challenge/)
This second step I suppose is too heavy to be handled by your node-express application. Better to extract SSL-signing logic to a separate layer, even to a separate micro-service.
In order to automate this process, you can create a service which will request SSL for all your customer's domains (for example by implementing ACME protocol, requesting certificates from LetsEncrypt). And setup proxy server which will proxy requests from all customer's domains, getting data and signing the responses with proper certificates.
Also you can check third party solutions which already do this from the box. For example, Kilo SSL, Cloudflare etc. I didn't try doing it with Cloudflare yet, but just checked that it's easy to do with KiloSSL

You can set up a reverse proxy (using nginx for example). Configure a virtual host with server name somedomainibought.com that does a proxy pass to https://mybiz.ourgreatapp.com/. Configure this virtual host to use ssl and listen on port 443.
Then, the Zone file for the domain somedomainibought.com must be configured with an A record pointing to the IP address of your reverse proxy.

Related

Azure - Switch host name for ssl certificate

I have just bought an SSL Certificate for my website from azure. when setting up a certificate under "Naked domain hostname" i entered the domain name WITHOUT "www".
Currently if i were to view my website with https://xyz.ca, it works just fine and it says it is secure, but if enter www.xyz.ca i do not see anything.
To atleast view the website with www.xyz.ca, i have removed HTTPS:// only request. However now this makes website un-secure.
Question
1. what will be the best way to make www.xyz.ca secure using the same certificate that i have bought?
2. if there is any other solution available, that will be fine too.
I am attaching some screenshots to understand better:
In fact a cert CAN support MANY domains. Now, whether this is something that you can add for free with the SSL provider you have chose is a different question. Certificate Subject Alternate Name(s) are what is used for this. For example the cert for this site allows stackexchange.com AND stackoverflow.com and a number of others and sub-domains too.
A valid SSL certificate must match the access FQDN domain name.
One Standard certificate only could be used for one FQDN domain name, such as www.xyz.ca while one WildCard certificate could be used for all like *.xyz.ca FQDN domain name, so usually we use the same WildCard certificate for all different services. More information about SSL Certificate Names
As the comment point it out, instead of buying one via the Azure Portal, you can get a free one via letsencrypt.org
Update
When you purchase an app service certificate in Azure for a root domain, by default, Azure supports hostname as a root domain name and www subdomain. You do not need to purchase another certificate. In this case, you already have two hostnames assigned to the site. You just bind the certificate for each. If you don't see the domain name(s) in the Hostname dropdown, try refreshing the browser page or change another browser.

Clarifying interaction of SSL, DNS, webserver

Please forgive the wishy washy nature of this question, I'm unsure how better to phrase it.
I have a nodejs server which will be accessed (HTTP + websockets) through a variety of third party DNSs by the third parties adding a new A record in their DNS entry pointing at my IP. I can find the origination third party DNS name by looking at the request headers. Node is then acting as a proxy and ultimately modifying the request headers/adding metadata before forwarding the request back to another url at the third party.
Could anyone explain please how SSL/TLS operates when the third party certificate is a wildcard cert for the origination DNS; how is the chain of encryption carried to node -> do I need to host a copy of the third party certificate on the node server? (Obviously I'd rather not). Can I use a third party's original SSL set up to any advantage?
Many thanks in advance!
DNS and HTTPS are fairly unrelated here. The client only uses DNS to find the web server's IP address. After that, the http protocol contains the Host name it is requesting in the Host header, as you have determined.
Your server will need an HTTPS certificate for each Host name that is will handle requests for, otherwise browsers will not be able to make a trusted connection to it. The certificate says "This server is authorized to handle requests for this host name".
In practice, though DNS and HTTPS are related, because if you control dns, you can issue a certificate. Let's Encrypt has made this very easy to set up.
I would not recommend sharing certificates with third parties, as that can be a bit of a pain, and it is harder to keep private keys secure if you are emailing them back and forth or something. Just issue your own certs for the third-party domains you need to serve.
My personal favorite solution for a case like yours is running a caddy server instance in front of my app to manage https certificates automatically, and proxy requests to your node backend. It can even issue certs dynamically as it receives requests.

Does Azure offer https for "cloudapp.net"?

One great advantage of using Azure Websites is that I can get secure HTTP (HTTPS) without doing nothing: I simply type https://xyz.azurewebsites.net and it works. I don't have to worry about certificates because I use the subdomain that Azure gives me (in the example it would be xyz)
So, what I usually do is that people come by through some registered domain I have, eg. http://www.my-application-homepage.com, and there, if they want to use my application, I redirect them to the subdomain at azurewebsites.net, using HTTPS.
Now, having said that:
I'm in need of upgrading to Azure Cloud Services or Azure Virtual Machines, because these have capabilities that Azure Websites don't . These two also offer a free subdomain: xyz.cloudapp.net, but my question is: will I get HTTPS there too? and how?
I searched in google for some cloudapp examples and what I tested was the following:
1) Connect through HTTP (ie. type http://xyz.cloudapp.net). Result: worked
2) Connect through HTTPS (ie. type https://xyz.cloudapp.net). Result: didn't work (chrome gave ERR_CONNECTION_TIMED_OUT)
No. HTTPS is not offered for .cloudapp.net domain as of today. Also since you don't own .cloudapp.net domain, I don't think you can buy a SSL certificate for that. If you want you could create a self-signed certificate and use that.
I would walk through the documentation listed here:
http://azure.microsoft.com/en-us/documentation/articles/cloud-services-configure-ssl-certificate/
Since you're getting a timeout with HTTPS (rather than a certificate error), check that you have a HTTPS endpoint defined in ServiceDefinition.csdef.
Additionally, be aware that the redirect-to-subdomain approach isn't much more secure than using a self-signed certificate. The reason browsers reject self-signed certs is that they are vulnerable to spoofing attacks: a user can't detect if an attacker has, for example, hijacked the DNS to point to his IP address instead of yours, where he hosts a facade of your site that just collects passwords or whatever.
In your scenario, the cloned site could redirect to another a second clone, one that is a facade of your cloudapp.net site. It could be even be secured with the attacker's SSL certificate. Unless the user was trained to recognize the host name of the real cloudapp.net, she wouldn't know she was on the attacker's "secure" site.
** Update: This method is not valid as well, we got the certificate revoked after one week using it **
We use this approach for staging/dev servers:
If you don't want to use a self-signed certificate, one option is to purchase a cheap SSL certificate, e.g.:
https://www.ssls.com/comodo-ssl-certificates/positivessl.html
Then once you need to approve it you have to ask support to change the approver validation process: instead of sending an email to a admin#mydomain.cloudapp.net you can ask to change the validation process to placing a given file with a given file in the root of your website (you have to ask in the support / chat room about that option).
More info:
https://support.comodo.com/index.php?/Default/Knowledgebase/Article/View/791/16/alternative-methods-of-domain-control-validation-dcv

SSL cert for secure.domain.net - when I don't own www.domain.net

I am writing an application for a business who have an existing website.
I would like the application to be behind SSL, and on my server - so completely separate from the existing business's website.
So for example, they are: http://www.dogsittingservices.net - pointing to their website, on their host.
I would like to be able to have https://secure.dogsittingservices.net - pointing to the web application sitting on my server.
Is this possible at all? If so, who would have to order the SSL cert - the current business for www.dogsittingservices.net - or me? How could I order a certificate for a domain I don't own? That's my dilema.
Thank you for any guidance/advice,
Mark
UPDATE following #EJP answer
So are these the steps I would need to take:
The business that has the website would setup in their DNS:
secure.dogsittingservices.net
They would then point that DNS to the IP address of my server
I would then setup a website on my server with the name: secure.dogsittingservices.net
I would then generate a CSR for it from my server
I'd then give the CSR to the business that I'm doing the work for
The business would then have to use the CSR I generated from my server, to order the SSL
They would then send me the SSL key/code to me to apply to my server
Is that how this is normally achieved?
Thank you,
Mark
They have to obtain their own SSL certificate. That's the whole point of them, that they definitely identify the business they are issued to.
You can also have one SSL certificate with multiple site-use, as an option. Read up more on SAN certificates as it may become relevant to your solution. This would allow you to share the certificate and suit both hostnames. You can also do a wildcard certificate as well if you may have more hostnames for that domain in the future.

How to serve custom domains pointing to a subdomain in Saas App

I want to create an example SaaS app, whereby users are able to signup, create web pages, use templates and/or customize them with custom css, serve their web pages off custom domains.
I was considering saving the templates on S3/other CDNs, along with media/stylesheets/js files. While all are technically possible (practical? that could be debatable). Anyways, I was having a hard time figuring out how websites would be served off custom domains in this case? For instance, when they sign up, they could get a subdomain.domain.com address. However, how do they point customerdomain.com so that when customerdomain.com is entered, it serves same content as customerdomain.domain.com, and URL remains customerdomain.com
Additionally, if I want to have a "feature" whereby, custom domains could be a paid feature. How would I restrict it to paid users only?
Normally when, we setup websites, we specify it in virtual host config file (apache), and give it aliases, so it looks for and serves those aliases. In this case, I do not want to have a separate vhost file for each person who signs up. Is there an alternative? How can I program this? Are there any gotchas to be aware of?
One solution that I have seen is to have the server serve a wildcard domain i.e *.domain.com, and a separate vhost for each custom domain, however I would prefer to avoid if I can.
Thanks.
The custom domain is usually done through a CNAME DNS record (sort of a symlink for DNS records). You tell your customer (who is usually in control of customerdomain.com) to create a CNAME record saying that customerdomain.com is an alias for customerdomain.domain.com. Then you need to set up your own server to interpret requests to customerdomain.com the same as it would treat requests to customerdomain.domain.com.
Depending on how you serve your subdomains, this can be done in a few different ways.
If you have a vhost file for every single customer, you need to add a "ServerAlias" directive for the custom domain your client has provided.
If you are coding the entry point through your own application server (say, reading the "Host" HTTP header from PHP and then setting the customer name from that) then you need to adjust that code accordingly to interpret requests for external domains according to your own database of custom domains. You can even use straight DNS for this!
Something on the lines of:
if http "host" header does not end in domain.com:
cname = get_cname_record(http "host" header value)
if cname does not end in domain.com:
return error 404
else:
site = first part of cname
else:
site = first part of http "host" header
Then you can use DNS as your "custom domain database". Make sure you are using a DNS cache though, as those queries will be performed on every single request.
The accepted answer is good but it doesn't show the full picture.
If your customers just CNAME to your domain or create the A record to your IP and you don't handle TLS termination for these custom domains, your app will not support HTTPS, and without it, your app won't work in modern browsers on these custom domains.
You need to set up a TLS termination reverse proxy in front of your webserver. This proxy can be run on a separate machine but you can run it on the same machine as the webserver.
CNAME vs A record
If your customers want to have your app on their subdomain, e.g. app.customer.com they can create a CNAME app.customer.com pointing to your proxy.
If they want to have your app on their root domain, e.g. customer.com then they'll have to create an A record on customer.com pointing to your proxy's IP. Make sure this IP doesn't change, ever!
How to handle TLS termination?
To make TLS termination work, you'll have to issue TLS certificates for these custom domains. You can use Let's Encrypt for that. Your proxy will see the Host header of the incoming request, e.g. app.customer1.com or customer2.com etc., and then it will decide which TLS certificate to use by checking the SNI.
The proxy can be set up to automatically issue and renew certificates for these custom domains. On the first request from a new custom domain, the proxy will see it doesn't have the appropriate certificate. It will ask Let's Encrypt for a new certificate. Let's Encrypt will first issue a challenge to see if you manage the domain, and since the customer already created a CNAME or A record pointing to your proxy, that tells Let's Encrypt you indeed manage the domain, and it will let you issue a certificate for it.
To issue and renew certificates automatically, I'd recommend using Caddyserver, greenlock.js, OpenResty (Nginx).
tl;dr on what happens here;
Caddyserver listens on 443 and 80, it receives requests, issues, and renews certificates automatically, proxies traffic to your backend.
How to handle it on my backend
Your proxy is terminating TLS and proxying requests to your backend. However, your backend doesn't know who is the original customer behind the request. This is why you need to tell your proxy to include additional headers in proxied requests to identify the customer. Just add X-Serve-For: app.customer.com or X-Serve-For: customer2.com or whatever the Host header is of the original request.
Now when you receive the proxied request on the backend, you can read this custom header and you know who is the customer behind the request. You can implement your logic based on that, show data belonging to this customer, etc.
More
Put a load balancer in front of your fleet of proxies for higher availability. You'll also have to use distributed storage for certificates and Let's Encrypt challenges. Use AWS ECS or EBS for automated recovery if something fails, otherwise, you may be waking up in the middle of the night restarting machines, or your proxy manually.
Alternatively, there have been a few services like this recently that allow you to add custom domains to your app without running the infrastructure yourself.
If you need more detail you can DM me on Twitter #dragocrnjac

Resources