From c49f2fd1db80290f14bab50178263c384c171d4e Mon Sep 17 00:00:00 2001 From: adoolaard Date: Thu, 30 Jan 2025 21:22:19 +0100 Subject: [PATCH 1/7] Changed dockerfile to better cache --- docker/Dockerfile | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index 2099358..5c3c5cd 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,19 +1,27 @@ +# Stage 1: Build Zoraxy FROM docker.io/golang:alpine AS build-zoraxy +# Install dependencies RUN mkdir -p /opt/zoraxy/source/ &&\ mkdir -p /usr/local/bin/ -# If you build it yourself, you will need to add the src directory into the docker directory. -COPY ./src/ /opt/zoraxy/source/ - WORKDIR /opt/zoraxy/source/ -RUN go mod tidy &&\ - go build -o /usr/local/bin/zoraxy &&\ +# Copy go.mod and go.sum first to leverage Docker cache +COPY ./src/go.mod ./src/go.sum ./ +RUN go mod tidy + +# Copy the rest of the source code +COPY ./src/ . + +# Build the application +RUN go build -o /usr/local/bin/zoraxy &&\ chmod 755 /usr/local/bin/zoraxy +# Stage 2: Build ZeroTier FROM docker.io/ubuntu:latest AS build-zerotier +# Install dependencies RUN mkdir -p /opt/zerotier/source/ &&\ mkdir -p /usr/local/bin/ @@ -22,6 +30,7 @@ WORKDIR /opt/zerotier/source/ RUN apt-get update -y &&\ apt-get install -y curl jq build-essential pkg-config clang cargo libssl-dev +# Download and build ZeroTier RUN curl -Lo ZeroTierOne.tar.gz https://codeload.github.com/zerotier/ZeroTierOne/tar.gz/refs/tags/1.10.6 &&\ tar -xzvf ZeroTierOne.tar.gz &&\ cd ZeroTierOne-* &&\ @@ -29,19 +38,24 @@ RUN curl -Lo ZeroTierOne.tar.gz https://codeload.github.com/zerotier/ZeroTierOne mv ./zerotier-one /usr/local/bin/zerotier-one &&\ chmod 755 /usr/local/bin/zerotier-one +# Stage 3: Final image FROM docker.io/ubuntu:latest +# Install runtime dependencies RUN apt-get update -y &&\ apt-get install -y bash sudo netcat-openbsd libssl-dev ca-certificates +# Copy entrypoint script COPY --chmod=700 ./entrypoint.sh /opt/zoraxy/ + +# Copy built binaries from previous stages COPY --from=build-zoraxy /usr/local/bin/zoraxy /usr/local/bin/zoraxy COPY --from=build-zerotier /usr/local/bin/zerotier-one /usr/local/bin/zerotier-one WORKDIR /opt/zoraxy/config/ +# Set environment variables ENV ZEROTIER="false" - ENV AUTORENEW="86400" ENV CFGUPGRADE="true" ENV DB="auto" @@ -60,9 +74,12 @@ ENV WEBROOT="./www" ENV ZTAUTH="" ENV ZTPORT="9993" +# Define volumes VOLUME [ "/opt/zoraxy/config/" ] +# Set entrypoint ENTRYPOINT [ "/opt/zoraxy/entrypoint.sh" ] +# Healthcheck HEALTHCHECK --interval=15s --timeout=5s --start-period=10s --retries=3 CMD nc -vz 127.0.0.1 $PORT || exit 1 From 791fbfa1b45efc50e4f2f2d41cb74cf2405443f1 Mon Sep 17 00:00:00 2001 From: adoolaard Date: Thu, 30 Jan 2025 21:48:40 +0100 Subject: [PATCH 2/7] Updated gitignore --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 5e9c044..8cdd224 100644 --- a/.gitignore +++ b/.gitignore @@ -39,4 +39,9 @@ src/tmp/localhost.pem src/www/html/index.html src/sys.uuid src/zoraxy -src/log/ \ No newline at end of file +src/log/ + + +# dev-tags +/Dockerfile +/Entrypoint.sh \ No newline at end of file From a402c4f3269daf2f9baed5a2226b9716dd513db8 Mon Sep 17 00:00:00 2001 From: adoolaard Date: Thu, 30 Jan 2025 22:22:42 +0100 Subject: [PATCH 3/7] Tags are working, just not yet editable --- src/mod/dynamicproxy/typedef.go | 1 + src/reverseproxy.go | 15 +++++++++++++++ src/web/components/httprp.html | 4 ++++ src/web/components/rules.html | 7 +++++++ 4 files changed, 27 insertions(+) diff --git a/src/mod/dynamicproxy/typedef.go b/src/mod/dynamicproxy/typedef.go index c7a060d..2919a7e 100644 --- a/src/mod/dynamicproxy/typedef.go +++ b/src/mod/dynamicproxy/typedef.go @@ -194,6 +194,7 @@ type ProxyEndpoint struct { //Internal Logic Elements parent *Router `json:"-"` + Tags []string // Tags for the proxy endpoint } /* diff --git a/src/reverseproxy.go b/src/reverseproxy.go index c55b6db..ced72f5 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -287,6 +287,12 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { } } + tagsStr, _ := utils.PostPara(r, "tags") + tags := strings.Split(tagsStr, ",") + for i := range tags { + tags[i] = strings.TrimSpace(tags[i]) + } + var proxyEndpointCreated *dynamicproxy.ProxyEndpoint if eptype == "host" { rootOrMatchingDomain, err := utils.PostPara(r, "rootname") @@ -357,6 +363,8 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { // Rate Limit RequireRateLimit: requireRateLimit, RateLimit: int64(proxyRateLimit), + + Tags: tags, } preparedEndpoint, err := dynamicProxyRouter.PrepareProxyRoute(&thisProxyEndpoint) @@ -515,6 +523,12 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { return } + tagsStr, _ := utils.PostPara(r, "tags") + tags := strings.Split(tagsStr, ",") + for i := range tags { + tags[i] = strings.TrimSpace(tags[i]) + } + //Generate a new proxyEndpoint from the new config newProxyEndpoint := dynamicproxy.CopyEndpoint(targetProxyEntry) newProxyEndpoint.BypassGlobalTLS = bypassGlobalTLS @@ -539,6 +553,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { newProxyEndpoint.RateLimit = proxyRateLimit newProxyEndpoint.UseStickySession = useStickySession newProxyEndpoint.DisableUptimeMonitor = disbleUtm + newProxyEndpoint.Tags = tags //Prepare to replace the current routing rule readyRoutingRule, err := dynamicProxyRouter.PrepareProxyRoute(newProxyEndpoint) diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index 8ecd402..1464e38 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -19,6 +19,7 @@ Host Destination Virtual Directory + Tags Advanced Settings Actions @@ -124,6 +125,7 @@ ${vdList} + ${subd.Tags.join(", ")} ${subd.AuthenticationProvider.AuthMethod == 0x1?` Basic Auth`:``} ${subd.AuthenticationProvider.AuthMethod == 0x2?` Authelia`:``} @@ -457,6 +459,7 @@ let requireRateLimit = $(row).find(".RequireRateLimit")[0].checked; let rateLimit = $(row).find(".RateLimit").val(); let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked; + let tags = $("#proxyTags").val().trim(); $.cjax({ url: "/api/proxy/edit", @@ -470,6 +473,7 @@ "authprovider" :authProviderType, "rate" :requireRateLimit, "ratenum" :rateLimit, + "tags": tags, }, success: function(data){ if (data.error !== undefined){ diff --git a/src/web/components/rules.html b/src/web/components/rules.html index f6df6ce..dd37efd 100644 --- a/src/web/components/rules.html +++ b/src/web/components/rules.html @@ -63,6 +63,11 @@ +
+ + + Comma-separated list of tags for this proxy host. +
Security @@ -198,6 +203,7 @@ let skipWebSocketOriginCheck = $("#skipWebsocketOriginCheck")[0].checked; let accessRuleToUse = $("#newProxyRuleAccessFilter").val(); let useStickySessionLB = $("#useStickySessionLB")[0].checked; + let tags = $("#proxyTags").val().trim(); if (rootname.trim() == ""){ $("#rootname").parent().addClass("error"); @@ -231,6 +237,7 @@ cred: JSON.stringify(credentials), access: accessRuleToUse, stickysess: useStickySessionLB, + tags: tags, }, success: function(data){ if (data.error != undefined){ From e4ad505f2ade0230263cf76c3a2352ecfcde9e1d Mon Sep 17 00:00:00 2001 From: adoolaard Date: Thu, 30 Jan 2025 22:42:06 +0100 Subject: [PATCH 4/7] Tags editor works! --- src/web/components/httprp.html | 9 ++++ src/web/snippet/tagEditor.html | 77 ++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 src/web/snippet/tagEditor.html diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index 1464e38..cdb9873 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -417,6 +417,7 @@ + `); $(".hostAccessRuleSelector").dropdown(); @@ -613,4 +614,12 @@ tabSwitchEventBind["httprp"] = function(){ listProxyEndpoints(); } + + function editTags(uuid){ + let payload = encodeURIComponent(JSON.stringify({ + ept: "host", + ep: uuid + })); + showSideWrapper("snippet/tagEditor.html?t=" + Date.now() + "#" + payload); + } \ No newline at end of file diff --git a/src/web/snippet/tagEditor.html b/src/web/snippet/tagEditor.html new file mode 100644 index 0000000..e4c5a32 --- /dev/null +++ b/src/web/snippet/tagEditor.html @@ -0,0 +1,77 @@ + + + + + + + + + + + +
+
+
+ Edit Tags +
+
+
+
+

Enter tags for this proxy host. Use commas to separate multiple tags.

+
+
+ + +
+ + +
+
+ + + \ No newline at end of file From 8df68f1f4eec0be0795350d38505fc4abf3fa7d5 Mon Sep 17 00:00:00 2001 From: adoolaard Date: Thu, 30 Jan 2025 22:48:48 +0100 Subject: [PATCH 5/7] Zoeken en filteren werkt ook! --- src/web/components/httprp.html | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index cdb9873..0e2ce06 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -12,6 +12,19 @@ min-width: 200px; } +
+ + +
+
@@ -144,12 +157,42 @@ `); }); + populateTagFilterDropdown(data); } resolveAccessRuleNameOnHostRPlist(); }); } + // Function to populate the tag filter dropdown + function populateTagFilterDropdown(data) { + let tags = new Set(); + data.forEach(subd => { + subd.Tags.forEach(tag => tags.add(tag)); + }); + let dropdownMenu = $("#tagFilterDropdown .menu"); + dropdownMenu.html('
All
'); + tags.forEach(tag => { + dropdownMenu.append(`
${tag}
`); + }); + $('#tagFilterDropdown').dropdown(); + } + + // Function to filter the proxy list + function filterProxyList() { + let searchInput = $("#searchInput").val().toLowerCase(); + let selectedTag = $("#tagFilterDropdown").dropdown('get value'); + $("#httpProxyList tr").each(function() { + let host = $(this).find("td[data-label='']").text().toLowerCase(); + let tags = $(this).find("td[data-label='tags']").text().toLowerCase(); + if ((host.includes(searchInput) || searchInput === "") && (tags.includes(selectedTag) || selectedTag === "")) { + $(this).show(); + } else { + $(this).hide(); + } + }); + } + //Perform realtime alias update without refreshing the whole page function updateAliasListForEndpoint(endpointName, newAliasDomainList){ let targetEle = $(`.aliasDomains[eptuuid='${endpointName}']`); @@ -622,4 +665,9 @@ })); showSideWrapper("snippet/tagEditor.html?t=" + Date.now() + "#" + payload); } + + // Initialize the proxy list on page load + $(document).ready(function() { + listProxyEndpoints(); + }); \ No newline at end of file From 97a6cf016a5431805ec8197e67e729e731b7ddb6 Mon Sep 17 00:00:00 2001 From: adoolaard Date: Fri, 31 Jan 2025 00:17:10 +0100 Subject: [PATCH 6/7] Point on the I --- src/reverseproxy.go | 22 ++++++++++++++-------- src/web/components/httprp.html | 16 +++++++++++++--- src/web/components/rules.html | 1 + 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/reverseproxy.go b/src/reverseproxy.go index ced72f5..c0f3fe9 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -287,10 +287,13 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { } } - tagsStr, _ := utils.PostPara(r, "tags") - tags := strings.Split(tagsStr, ",") - for i := range tags { - tags[i] = strings.TrimSpace(tags[i]) + tagStr, _ := utils.PostPara(r, "tags") + tags := []string{} + if tagStr != "" { + tags = strings.Split(tagStr, ",") + for i := range tags { + tags[i] = strings.TrimSpace(tags[i]) + } } var proxyEndpointCreated *dynamicproxy.ProxyEndpoint @@ -523,10 +526,13 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) { return } - tagsStr, _ := utils.PostPara(r, "tags") - tags := strings.Split(tagsStr, ",") - for i := range tags { - tags[i] = strings.TrimSpace(tags[i]) + tagStr, _ := utils.PostPara(r, "tags") + tags := []string{} + if tagStr != "" { + tags = strings.Split(tagStr, ",") + for i := range tags { + tags[i] = strings.TrimSpace(tags[i]) + } } //Generate a new proxyEndpoint from the new config diff --git a/src/web/components/httprp.html b/src/web/components/httprp.html index 0e2ce06..1624fc5 100644 --- a/src/web/components/httprp.html +++ b/src/web/components/httprp.html @@ -138,7 +138,9 @@ - +
${vdList}${subd.Tags.join(", ")} + ${subd.Tags.map(tag => `${tag}`).join("")} + ${subd.AuthenticationProvider.AuthMethod == 0x1?` Basic Auth`:``} ${subd.AuthenticationProvider.AuthMethod == 0x2?` Authelia`:``} @@ -170,10 +172,11 @@ data.forEach(subd => { subd.Tags.forEach(tag => tags.add(tag)); }); + tags = Array.from(tags).sort((a, b) => a.localeCompare(b)); let dropdownMenu = $("#tagFilterDropdown .menu"); - dropdownMenu.html('
All
'); + dropdownMenu.html('
All
'); tags.forEach(tag => { - dropdownMenu.append(`
${tag}
`); + dropdownMenu.append(`
${tag}
`); }); $('#tagFilterDropdown').dropdown(); } @@ -669,5 +672,12 @@ // Initialize the proxy list on page load $(document).ready(function() { listProxyEndpoints(); + + // Event listener for clicking on tags + $(document).on('click', '.tag-select', function() { + let tag = $(this).text().trim(); + $('#tagFilterDropdown').dropdown('set selected', tag); + filterProxyList(); + }); }); \ No newline at end of file diff --git a/src/web/components/rules.html b/src/web/components/rules.html index dd37efd..642798f 100644 --- a/src/web/components/rules.html +++ b/src/web/components/rules.html @@ -246,6 +246,7 @@ //Clear old data $("#rootname").val(""); $("#proxyDomain").val(""); + $("#proxyTags").val(""); credentials = []; updateTable(); reloadUptimeList(); From f753becd6662198ff076d517c37be2c17ced8baf Mon Sep 17 00:00:00 2001 From: adoolaard Date: Mon, 3 Feb 2025 15:10:13 +0100 Subject: [PATCH 7/7] The proxy hosts broke on import, because the tags were missing. This is now fixed. --- src/config.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/config.go b/src/config.go index eacea02..62468f8 100644 --- a/src/config.go +++ b/src/config.go @@ -54,6 +54,11 @@ func LoadReverseProxyConfig(configFilepath string) error { return err } + //Make sure the tags are not nil + if thisConfigEndpoint.Tags == nil { + thisConfigEndpoint.Tags = []string{} + } + //Matching domain not set. Assume root if thisConfigEndpoint.RootOrMatchingDomain == "" { thisConfigEndpoint.RootOrMatchingDomain = "/" @@ -175,8 +180,8 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) { // Set the Content-Type header to indicate it's a zip file w.Header().Set("Content-Type", "application/zip") - // Set the Content-Disposition header to specify the file name - w.Header().Set("Content-Disposition", "attachment; filename=\"config.zip\"") + // Set the Content-Disposition header to specify the file name, add timestamp to the filename + w.Header().Set("Content-Disposition", "attachment; filename=\"zoraxy-config-"+time.Now().Format("2006-01-02-15-04-05")+".zip\"") // Create a zip writer zipWriter := zip.NewWriter(w)