mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-08-06 21:28:30 +02:00
Updated a lot of stuffs
+ Added comments for whitelist + Added automatic cert pick for multi-host certs (SNI) + Renamed .crt to .pem for cert store + Added best-fit selection for wildcard matching rules + Added x-proxy-by header + Added X-real-Ip header + Added Development Mode (Cache-Control: no-store) + Updated utm timeout to 10 seconds instead of 90
This commit is contained in:
@@ -15,42 +15,19 @@
|
||||
</div>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
<h4>Default Certificates</h4>
|
||||
<p>When there are no matching certificate for the requested server name, reverse proxy router will always fallback to this one.<br>Note that you need both of them uploaded for it to fallback properly</p>
|
||||
<table class="ui very basic unstackable celled table">
|
||||
<thead>
|
||||
<tr><th class="no-sort">Key Type</th>
|
||||
<th class="no-sort">Exists</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><i class="globe icon"></i> Default Public Key</td>
|
||||
<td id="pubkeyExists"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="lock icon"></i> Default Private Key</td>
|
||||
<td id="prikeyExists"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="margin-bottom: 0.4em;"><i class="ui upload icon"></i> Upload Default Keypairs</p>
|
||||
<div class="ui buttons">
|
||||
<button class="ui basic grey button" onclick="uploadPublicKey();"><i class="globe icon"></i> Public Key</button>
|
||||
<button class="ui basic black button" onclick="uploadPrivateKey();"><i class="black lock icon"></i> Private Key</button>
|
||||
</div>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
<h4>Sub-domain Certificates</h4>
|
||||
<h3>Hosts Certificates</h3>
|
||||
<p>Provide certificates for multiple domains reverse proxy</p>
|
||||
<div class="ui fluid form">
|
||||
<div class="three fields">
|
||||
<div class="field">
|
||||
<label>Server Name (Domain)</label>
|
||||
<input type="text" id="certdomain" placeholder="example.com / blog.example.com">
|
||||
<small><i class="exclamation circle yellow icon"></i> Match the server name with your CN/DNS entry in certificate for faster resolve time</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Public Key (.pem)</label>
|
||||
<input type="file" id="pubkeySelector" onchange="handleFileSelect(event, 'pub')">
|
||||
<small>or .crt files in order systems</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Private Key (.key)</label>
|
||||
@@ -63,14 +40,33 @@
|
||||
<div id="certUploadSuccMsg" class="ui green message" style="display:none;">
|
||||
<i class="ui checkmark icon"></i> Certificate for domain <span id="certUploadingDomain"></span> uploaded.
|
||||
</div>
|
||||
<br>
|
||||
<div class="ui message">
|
||||
<h4>Tips about Server Names & SNI</h4>
|
||||
<div class="ui bulleted list">
|
||||
<div class="item">
|
||||
If you have two subdomains like <code>a.example.com</code> and <code>b.example.com</code> ,
|
||||
for faster response speed, you might want to setup them one by one (i.e. having two seperate certificate for
|
||||
<code>a.example.com</code> and <code>b.example.com</code>).
|
||||
</div>
|
||||
<div class="item">
|
||||
If you have a wildcard certificate that covers <code>*.example.com</code>,
|
||||
you can just enter <code>example.com</code> as server name to add a certificate.
|
||||
</div>
|
||||
<div class="item">
|
||||
If you have a certificate contain multiple host, you can enter the first domain in your certificate
|
||||
and Zoraxy will try to match the remaining CN/DNS for you.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Current list of loaded certificates</p>
|
||||
<div>
|
||||
<div style="width: 100%; overflow-x: auto; margin-bottom: 1em;">
|
||||
<table class="ui sortable unstackable celled table">
|
||||
<table class="ui sortable unstackable basic celled table">
|
||||
<thead>
|
||||
<tr><th>Domain</th>
|
||||
<th>Last Update</th>
|
||||
<th>Expire At</th>
|
||||
<th class="no-sort">Renew</th>
|
||||
<th class="no-sort">Remove</th>
|
||||
</tr></thead>
|
||||
<tbody id="certifiedDomainList">
|
||||
@@ -81,15 +77,34 @@
|
||||
|
||||
<button class="ui basic button" onclick="initManagedDomainCertificateList();"><i class="green refresh icon"></i> Refresh List</button>
|
||||
</div>
|
||||
<div class="ui message">
|
||||
<h4><i class="info circle icon"></i> Sub-domain Certificates</h4>
|
||||
If you have 3rd or even 4th level subdomains like <code>blog.example.com</code> or <code>en.blog.example.com</code> ,
|
||||
depending on your certificates coverage, you might need to setup them one by one (i.e. having two seperate certificate for <code>a.example.com</code> and <code>b.example.com</code>).<br>
|
||||
If you have a wildcard certificate that covers <code>*.example.com</code>, you can just enter <code>example.com</code> as server name in the form below to add a certificate.
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<h4>Certificate Authority (CA) and Auto Renew (ACME)</h4>
|
||||
<h3>Fallback Certificate</h3>
|
||||
<p>When there are no matching certificate for the requested server name, reverse proxy router will always fallback to this one.<br>Note that you need both of them uploaded for it to fallback properly</p>
|
||||
<table class="ui very basic unstackable celled table">
|
||||
<thead>
|
||||
<tr><th class="no-sort">Key Type</th>
|
||||
<th class="no-sort">Found</th>
|
||||
</tr></thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><i class="globe icon"></i> Fallback Public Key</td>
|
||||
<td id="pubkeyExists"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><i class="lock icon"></i> Fallback Private Key</td>
|
||||
<td id="prikeyExists"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p style="margin-bottom: 0.4em;"><i class="ui upload icon"></i> Upload Default Keypairs</p>
|
||||
<div class="ui buttons">
|
||||
<button class="ui basic grey button" onclick="uploadPublicKey();"><i class="globe icon"></i> Public Key</button>
|
||||
<button class="ui basic black button" onclick="uploadPrivateKey();"><i class="black lock icon"></i> Private Key</button>
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<h3>Certificate Authority (CA) and Auto Renew (ACME)</h3>
|
||||
<p>Management features regarding CA and ACME</p>
|
||||
<h4>Prefered Certificate Authority</h4>
|
||||
<p>The default CA to use when create a new subdomain proxy endpoint with TLS certificate</p>
|
||||
<div class="ui fluid form">
|
||||
<div class="field">
|
||||
@@ -112,12 +127,12 @@
|
||||
<button class="ui basic icon button" onclick="saveDefaultCA();"><i class="ui blue save icon"></i> Save Settings</button>
|
||||
</div><br>
|
||||
<h5>Certificate Renew / Generation (ACME) Settings</h5>
|
||||
<div class="ui basic segment">
|
||||
<div class="ui basic segment acmeRenewStateWrapper">
|
||||
<h4 class="ui header" id="acmeAutoRenewer">
|
||||
<i class="red circle icon"></i>
|
||||
<i class="white remove icon"></i>
|
||||
<div class="content">
|
||||
<span id="acmeAutoRenewerStatus">Disabled</span>
|
||||
<div class="sub header">Auto-Renewer Status</div>
|
||||
<div class="sub header">ACME Auto-Renewer</div>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
@@ -130,6 +145,110 @@
|
||||
|
||||
$("#defaultCA").dropdown();
|
||||
|
||||
|
||||
//Renew certificate by button press
|
||||
function renewCertificate(domain, btn=undefined){
|
||||
let defaultCA = $("#defaultCA").dropdown("get value");
|
||||
if (defaultCA.trim() == ""){
|
||||
defaultCA = "Let's Encrypt";
|
||||
}
|
||||
//Get a new cert using ACME
|
||||
msgbox("Requesting certificate via " + defaultCA +"...");
|
||||
|
||||
//Request ACME for certificate
|
||||
if (btn != undefined){
|
||||
$(btn).addClass('disabled');
|
||||
$(btn).html(`<i class="ui loading spinner icon"></i>`);
|
||||
}
|
||||
obtainCertificate(domain, defaultCA.trim(), function(succ){
|
||||
if (btn != undefined){
|
||||
$(btn).removeClass('disabled');
|
||||
if (succ){
|
||||
$(btn).html(`<i class="ui green check icon"></i>`);
|
||||
}else{
|
||||
$(btn).html(`<i class="ui red times icon"></i>`);
|
||||
}
|
||||
|
||||
setTimeout(function(){
|
||||
initManagedDomainCertificateList();
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
Obtain Certificate via ACME
|
||||
*/
|
||||
|
||||
// Obtain certificate from API, only support one domain
|
||||
function obtainCertificate(domains, usingCa = "Let's Encrypt", callback=undefined) {
|
||||
//Load the ACME email from server side
|
||||
let acmeEmail = "";
|
||||
$.get("/api/acme/autoRenew/email", function(data){
|
||||
if (data != "" && data != undefined && data != null){
|
||||
acmeEmail = data;
|
||||
}
|
||||
|
||||
let filename = "";
|
||||
let email = acmeEmail;
|
||||
if (acmeEmail == ""){
|
||||
msgbox("Unable to obtain certificate: ACME email not set", false, 8000);
|
||||
if (callback != undefined){
|
||||
callback(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (filename.trim() == "" && !domains.includes(",")){
|
||||
//Zoraxy filename are the matching name for domains.
|
||||
//Use the same as domains
|
||||
filename = domains;
|
||||
}else if (filename != "" && !domains.includes(",")){
|
||||
//Invalid settings. Force the filename to be same as domain
|
||||
//if there are only 1 domain
|
||||
filename = domains;
|
||||
}else{
|
||||
msgbox("Filename cannot be empty for certs containing multiple domains.")
|
||||
if (callback != undefined){
|
||||
callback(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: "/api/acme/obtainCert",
|
||||
method: "GET",
|
||||
data: {
|
||||
domains: domains,
|
||||
filename: filename,
|
||||
email: email,
|
||||
ca: usingCa,
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.error) {
|
||||
console.log("Error:", response.error);
|
||||
// Show error message
|
||||
msgbox(response.error, false, 12000);
|
||||
if (callback != undefined){
|
||||
callback(false);
|
||||
}
|
||||
} else {
|
||||
console.log("Certificate installed successfully");
|
||||
// Show success message
|
||||
msgbox("Certificate installed successfully");
|
||||
|
||||
if (callback != undefined){
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function(error) {
|
||||
console.log("Failed to install certificate:", error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//Delete the certificate by its domain
|
||||
function deleteCertificate(domain){
|
||||
if (confirm("Confirm delete certificate for " + domain + " ?")){
|
||||
@@ -154,6 +273,12 @@
|
||||
//Initialize the current default CA options
|
||||
$.get("/api/acme/autoRenew/email", function(data){
|
||||
$("#prefACMEEmail").val(data);
|
||||
if (data.trim() == ""){
|
||||
//acme email is not yet set
|
||||
$(".renewButton").addClass('disabled');
|
||||
}else{
|
||||
$(".renewButton").removeClass('disabled');
|
||||
}
|
||||
});
|
||||
|
||||
$.get("/api/acme/autoRenew/ca", function(data){
|
||||
@@ -167,7 +292,13 @@
|
||||
//Set the status of the acme enable icon
|
||||
function setACMEEnableStates(enabled){
|
||||
$("#acmeAutoRenewerStatus").text(enabled?"Enabled":"Disabled");
|
||||
$("#acmeAutoRenewer").find("i").attr("class", enabled?"green circle icon":"red circle icon");
|
||||
if (enabled){
|
||||
$(".acmeRenewStateWrapper").addClass("enabled");
|
||||
}else{
|
||||
$(".acmeRenewStateWrapper").removeClass("enabled");
|
||||
}
|
||||
|
||||
$("#acmeAutoRenewer").find("i").attr("class", enabled?"white circle check icon":"white circle times icon");
|
||||
}
|
||||
initAcmeStatus();
|
||||
|
||||
@@ -187,6 +318,9 @@
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false);
|
||||
}else{
|
||||
//Update the renew button states
|
||||
$(".renewButton").removeClass('disabled');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -223,13 +357,14 @@
|
||||
<td>${entry.Domain}</td>
|
||||
<td>${entry.LastModifiedDate}</td>
|
||||
<td class="${isExpired?"expired":"valid"} certdate">${entry.ExpireDate} (${!isExpired?entry.RemainingDays+" days left":"Expired"})</td>
|
||||
<td><button title="Renew Certificate" class="ui mini basic icon button renewButton" onclick="renewCertificate('${entry.Domain}', this);"><i class="ui green refresh icon"></i></button></td>
|
||||
<td><button title="Delete key-pair" class="ui mini basic red icon button" onclick="deleteCertificate('${entry.Domain}');"><i class="ui red trash icon"></i></button></td>
|
||||
</tr>`);
|
||||
});
|
||||
|
||||
if (data.length == 0){
|
||||
$("#certifiedDomainList").append(`<tr>
|
||||
<td colspan="4"><i class="ui times circle icon"></i> No valid keypairs found</td>
|
||||
<td colspan="4"><i class="ui times red circle icon"></i> No valid keypairs found</td>
|
||||
</tr>`);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user