Hi,
I’m trying to figure out if i can automate issuing SSL certificates for domains, and then have it install on my nginx server…without me doing any manual work like SSH’ing into my server.
The way I would like for it to work:
User signs up on my software and enters their domain name.
My server will automatically create an SSL certificate for that domain and install it on my Nginx server.
If there is any documentation for this or 3rd party software that handles this. I would be grateful to check it out
You also need to think about how you are going to deal with validation. Presumably at the moment a user signs up with you, their domain may not be pointing at your server yet, so you wouldn’t be able to immediately issue a certificate. Alternatively, if you control the base domain always, you can do that, but you need to deal with failures and retries.
If you’re married to using nginx, then there is probably a fair amount of work to do. I’m not aware of any out-of-the-box ACME clients that deal with this SaaS-like scenario in a great way. Since you control the DNS of the zone already, it’s a little bit simpler:
Once a client signs up, in a queue/worker, use the acme-client gem to issue a certificate for the domain using the DNS-01 challenge. Keep track of the certificate/domain/expiration, write the private key and certificate to the filesystem.
Once the issuance task succeeds, template out a new nginx SSL virtualhost for the domain (in /etc/nginx/sites-enabled/ or wherever) that proxies back to your Rails application, reload nginx.
You will need to have a background task that deals with renewing certificates in the same way as in (1) and then reloading nginx.
If you’re open to moving away from nginx, you may find that other software like Caddy and Traefik provide a strong alternative. They will terminate SSL for you instead of nginx and they will deal with the entire issuance and renewal problem for you, all you have to do is e.g. template out the Caddyfile and reload Caddy when the time comes.
Didn’t even think of googling for a gem for acme, heh. Thanks for that!
My main concern is how one would go about installing the ssl certs and changing settings on /etc/nginx/sites-enabled/ without manually ssh’ing into my server. Assuming such a thing is even possible in the first place.
EDIT: Unfortunately, we can’t move away from nginx.
OpenResty might also be a good choice, but you would probably still have to do most of the work yourself, or use one of the third-party ACME modules (which I can't vouch for).
require 'erb'
# 1. Save cert + private key /var/lib/myapp/ssl_storage/<client_domain>/ or wherever
# 2. Generate an nginx configuration file for this server
@client_domain = 'example.org' # or whatever
tpl_text = File.read('nginx.erb')
nginx_config_to_save = ERB.new(tpl_text).result(binding)
# 3. Write the contents of nginx_config_to_save to /etc/nginx/sites-enabled/<client_domain>-ssl.conf
# 4. Invoke `sudo service nginx reload` or whatever
I don't know any Ruby so ymmv.
If this seems like too much, well, I don't see any way around it really apart from trying one of the other SSL terminating webservers, or maybe OpenResty as suggested (which is based on nginx).
I don't envision Certbot as being very beneficial in your case. Even if it issues the certificate for you, it has no way of understanding your requirement about your customer domains and SaaS in an automatic way. You have to do this server templating bit no matter what, if you're using nginx.
Depending on your dnsimple plan, you can get letsencrypt ssl via their API service (which claimed to support wildcard, however I haven’t tried yet)
Maybe you can start directly from Dnsimple instead of server-side?
If you are willing to extend your nginx with a few modules or switch to the nginx based OpenResty, there is a tool which does exactly what you need:
This OpenResty plugin automatically and transparently issues SSL certificates from Let's Encrypt (a free certificate authority) as requests are received. It works like:
A SSL request for a SNI hostname is received.
If the system already has a SSL certificate for that domain, it is immediately returned (with OCSP stapling).
If the system does not yet have an SSL certificate for this domain, it issues a new SSL certificate from Let's Encrypt. Domain validation is handled for you. After receiving the new certificate (usually within a few seconds), the new certificate is saved, cached, and returned to the client (without dropping the original request).
This uses the ssl_certificate_by_lua functionality in OpenResty 1.9.7.2+.