2014-10-10 15:49:14 +00:00
< style >
< / style >
2016-01-02 23:01:20 +00:00
< h2 > TLS (SSL) Certificates< / h2 >
2014-10-10 15:49:14 +00:00
2016-01-02 23:22:22 +00:00
< p > A TLS (formerly called SSL) certificate is a cryptographic file that proves to anyone connecting to a web address that the connection is secure between you and the owner of that address.< / p >
2016-01-02 22:53:47 +00:00
2016-01-02 23:22:22 +00:00
< p > You need a TLS certificate for this box’ s hostname ({{hostname}}) and every other domain name and subdomain that this box is hosting a website for (see the list below).< / p >
2016-01-02 22:53:47 +00:00
2016-01-04 23:22:02 +00:00
< div id = "ssl_provision" >
2018-05-13 00:02:25 +00:00
< h3 > Provision certificates< / h3 >
2014-10-10 15:49:14 +00:00
2016-01-04 23:22:02 +00:00
< div id = "ssl_provision_p" style = "display: none; margin-top: 1.5em" >
< button onclick = 'return provision_tls_cert();' class = 'btn btn-primary' style = "float: left; margin: 0 1.5em 1em 0;" > Provision< / button >
2020-06-12 08:27:08 +00:00
< p > < b > By provisioning the certificates, you’ re agreeing to the < a href = "https://acme-v01.api.letsencrypt.org/terms" > Let’ s Encrypt Subscriber Agreement< / a > .< / b > < / p >
2016-01-04 23:22:02 +00:00
< p > A TLS certificate can be automatically provisioned from < a href = "https://letsencrypt.org/" target = "_blank" > Let’ s Encrypt< / a > , a free TLS certificate provider, for:< br >
< span class = "text-primary" > < / span > < / p >
< / div >
< div class = "clearfix" > < / div >
2014-10-10 15:49:14 +00:00
2016-01-04 23:22:02 +00:00
< div id = "ssl_provision_result" > < / div >
< / div >
2016-01-02 22:53:47 +00:00
2016-08-08 11:28:10 +00:00
< h3 > Certificate status< / h3 >
2016-01-02 22:53:47 +00:00
2016-01-04 23:22:02 +00:00
< p style = "margin-top: 1.5em" > Certificates expire after a period of time. All certificates will be automatically renewed through < a href = "https://letsencrypt.org/" target = "_blank" > Let’ s Encrypt< / a > 14 days prior to expiration.< / p >
2016-01-02 22:53:47 +00:00
< table id = "ssl_domains" class = "table" style = "margin-bottom: 2em; width: auto; display: none" >
2014-10-10 15:49:14 +00:00
< thead >
< tr >
< th > Domain< / th >
< th > Certificate Status< / th >
< th > Actions< / th >
< / tr >
< / thead >
< tbody >
< / tbody >
< / table >
2014-12-05 19:25:14 +00:00
2016-08-08 11:28:10 +00:00
< h3 id = "ssl_install_header" > Install certificate< / h3 >
2014-10-10 15:49:14 +00:00
2016-09-27 13:06:50 +00:00
< p > If you don't want to use our automatic Let's Encrypt integration, you can give any other certificate provider a try. You can generate the needed CSR below.< / p >
2014-10-10 15:49:14 +00:00
2016-01-02 23:01:20 +00:00
< p > Which domain are you getting a certificate for?< / p >
2014-10-10 15:49:14 +00:00
< p > < select id = "ssldomain" onchange = "show_csr()" class = "form-control" style = "width: auto" > < / select > < / p >
2016-01-04 23:22:02 +00:00
< p > (A multi-domain or wildcard certificate will be automatically applied to any domains it is valid for besides the one you choose above.)< / p >
2016-01-02 23:01:20 +00:00
< p > What country are you in? This is required by some TLS certificate providers. You may leave this blank if you know your TLS certificate provider doesn't require it.< / p >
2015-12-26 16:48:23 +00:00
< p > < select id = "sslcc" onchange = "show_csr()" class = "form-control" style = "width: auto" >
< option value = "" > (Select)< / option >
{% for code, name in csr_country_codes %}
< option value = "{{code}}" > {{name}}< / option >
{% endfor %}
< / select > < / p >
2014-10-10 15:49:14 +00:00
< div id = "csr_info" style = "display: none" >
2016-01-02 23:01:20 +00:00
< p > You will need to provide the certificate provider this Certificate Signing Request (CSR):< / p >
2014-10-10 15:49:14 +00:00
< pre id = "ssl_csr" > < / pre >
< p > < small > The CSR is safe to share. It can only be used in combination with a secret key stored on this machine.< / small > < / p >
2016-01-02 23:01:20 +00:00
< p > The certificate provider will then provide you with a TLS/SSL certificate. They may also provide you with an intermediate chain. Paste each separately into the boxes below:< / p >
2014-10-10 15:49:14 +00:00
2016-01-02 23:01:20 +00:00
< p style = "margin-bottom: .5em" > TLS/SSL certificate:< / p >
2014-10-10 15:49:14 +00:00
< p > < textarea id = "ssl_paste_cert" class = "form-control" style = "max-width: 40em; height: 8em" placeholder = "-----BEGIN CERTIFICATE-----
stuff here
-----END CERTIFICATE-----" > < / textarea > < / p >
2016-01-02 23:01:20 +00:00
< p style = "margin-bottom: .5em" > TLS/SSL intermediate chain (if provided):< / p >
2014-10-10 15:49:14 +00:00
< p > < textarea id = "ssl_paste_chain" class = "form-control" style = "max-width: 40em; height: 8em" placeholder = "-----BEGIN CERTIFICATE-----
stuff here
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
more stuff here
-----END CERTIFICATE-----" > < / textarea > < / p >
< p > After you paste in the information, click the install button.< / p >
< button class = "btn-primary" onclick = "install_cert()" > Install< / button >
< / div >
< script >
2016-01-04 23:22:02 +00:00
function show_tls(keep_provisioning_shown) {
2014-10-10 15:49:14 +00:00
api(
2016-01-02 22:53:47 +00:00
"/ssl/status",
2014-10-10 15:49:14 +00:00
"GET",
{
},
2016-01-02 22:53:47 +00:00
function(res) {
// provisioning status
2016-01-04 23:22:02 +00:00
if (!keep_provisioning_shown)
2018-05-13 00:02:25 +00:00
$('#ssl_provision').toggle(res.can_provision.length > 0)
2016-01-04 23:22:02 +00:00
$('#ssl_provision_p').toggle(res.can_provision.length > 0);
if (res.can_provision.length > 0)
$('#ssl_provision_p span').text(res.can_provision.join(", "));
2016-09-27 13:06:50 +00:00
2016-01-02 22:53:47 +00:00
// certificate status
var domains = res.status;
2014-10-10 15:49:14 +00:00
var tb = $('#ssl_domains tbody');
tb.text('');
$('#ssldomain').html('< option value = "" > (select)< / option > ');
2016-01-02 22:53:47 +00:00
$('#ssl_domains').show();
2014-10-10 15:49:14 +00:00
for (var i = 0; i < domains.length ; i + + ) {
var row = $("< tr > < th class = 'domain' > < a href = '' > < / a > < / th > < td class = 'status' > < / td > < td class = 'actions' > < a href = '#' onclick = 'return ssl_install(this);' class = 'btn btn-xs' > Install Certificate< / a > < / td > < / tr > ");
tb.append(row);
row.attr('data-domain', domains[i].domain);
row.find('.domain a').text(domains[i].domain);
row.find('.domain a').attr('href', 'https://' + domains[i].domain);
2016-01-04 23:22:02 +00:00
if (domains[i].status == "not-applicable") {
domains[i].status = "muted"; // text-muted css class
row.find('.actions a').remove(); // no actions applicable
}
2016-01-02 22:53:47 +00:00
row.addClass("text-" + domains[i].status);
row.find('.status').text(domains[i].text);
if (domains[i].status == "success") {
2014-10-10 15:49:14 +00:00
row.find('.actions a').addClass('btn-default').text('Replace Certificate');
} else {
row.find('.actions a').addClass('btn-primary').text('Install Certificate');
}
$('#ssldomain').append($('< option > ').text(domains[i].domain));
}
});
}
function ssl_install(elem) {
var domain = $(elem).parents('tr').attr('data-domain');
$('#ssldomain').val(domain);
show_csr();
2014-10-23 17:10:21 +00:00
$('html, body').animate({ scrollTop: $('#ssl_install_header').offset().top - $('.navbar-fixed-top').height() - 20 })
2014-10-10 15:49:14 +00:00
return false;
}
function show_csr() {
2018-01-28 13:58:49 +00:00
// Can't show a CSR until both inputs are entered.
2016-01-04 23:22:02 +00:00
if ($('#ssldomain').val() == "") return;
2018-01-28 13:58:49 +00:00
if ($('#sslcc').val() == "") return;
// Scroll to it and fetch.
2016-01-04 23:22:02 +00:00
$('#csr_info').slideDown();
$('#ssl_csr').text('Loading...');
2014-10-10 15:49:14 +00:00
api(
"/ssl/csr/" + $('#ssldomain').val(),
"POST",
{
2015-12-26 16:48:23 +00:00
countrycode: $('#sslcc').val()
2014-10-10 15:49:14 +00:00
},
function(data) {
$('#ssl_csr').text(data);
});
}
function install_cert() {
api(
"/ssl/install",
"POST",
{
domain: $('#ssldomain').val(),
cert: $('#ssl_paste_cert').val(),
chain: $('#ssl_paste_chain').val()
},
function(status) {
2015-05-28 18:45:35 +00:00
if (/^OK($|\n)/.test(status)) {
console.log(status)
2016-01-02 23:01:20 +00:00
show_modal_error("TLS Certificate Installation", "Certificate has been installed. Check that you have no connection problems to the domain.", function() { show_ssl(); $('#csr_info').slideUp(); });
2014-10-10 15:49:14 +00:00
} else {
2016-01-02 23:01:20 +00:00
show_modal_error("TLS Certificate Installation", status);
2014-10-10 15:49:14 +00:00
}
});
}
2016-01-04 23:22:02 +00:00
function provision_tls_cert() {
// Automatically provision any certs.
$('#ssl_provision_p .btn').attr('disabled', '1'); // prevent double-clicks
api(
"/ssl/provision",
"POST",
2018-05-13 00:02:25 +00:00
{ },
2016-01-04 23:22:02 +00:00
function(status) {
// Clear last attempt.
$('#ssl_provision_result').text("");
may_reenable_provision_button = true;
// Nothing was done. There might also be problem domains, but we've already displayed those.
if (status.requests.length == 0) {
show_modal_error("TLS Certificate Provisioning", "There were no domain names to provision certificates for.");
// don't return - haven't re-enabled the provision button
}
// Each provisioning API call returns zero or more "requests" which represent
// a request to Let's Encrypt for a single certificate. Normally there is just
// one request (for a single multi-domain certificate).
for (var i = 0; i < status.requests.length ; i + + ) {
var r = status.requests[i];
2018-05-13 00:02:25 +00:00
if (r.result == "skipped") {
// not interested --- this domain wasn't in the table
// to begin with
continue;
}
2016-01-04 23:22:02 +00:00
// create an HTML block to display the results of this request
var n = $("< div > < h4 / > < p / > < / div > ");
$('#ssl_provision_result').append(n);
2018-05-13 00:02:25 +00:00
// plain log line
if (typeof r === "string") {
n.find("p").text(r);
continue;
}
2016-01-04 23:22:02 +00:00
// show a header only to disambiguate request blocks
if (status.requests.length > 0)
n.find("h4").text(r.domains.join(", "));
2018-05-13 00:02:25 +00:00
if (r.result == "error") {
2016-01-04 23:22:02 +00:00
n.find("p").addClass("text-danger").text(r.message);
} else if (r.result == "installed") {
n.find("p").addClass("text-success").text("The TLS certificate was provisioned and installed.");
setTimeout("show_tls(true)", 1); // update main table of certificate statuses, call with arg keep_provisioning_shown true so that we don't clear what we just outputted
2018-05-13 00:02:25 +00:00
2016-01-04 23:22:02 +00:00
}
2016-09-27 13:06:50 +00:00
2016-01-04 23:22:02 +00:00
// display the detailed log info in case of problems
var trace = $("< div class = 'small text-muted' style = 'margin-top: 1.5em' > Log:< / div > ");
n.append(trace);
for (var j = 0; j < r.log.length ; j + + )
trace.append($("< div / > ").text(r.log[j]));
}
if (may_reenable_provision_button)
$('#ssl_provision_p .btn').removeAttr("disabled");
});
}
2014-10-10 15:49:14 +00:00
< / script >