30 Commits
2.6.7 ... v2

Author SHA1 Message Date
36e461795a Added zoraxy start paramters for reference 2024-01-30 15:22:59 +08:00
d6e7641364 Merge pull request #88 from PassiveLemon/EnglishCorrection
English correction
2024-01-01 21:38:42 +08:00
15cebd6e06 Update README.md 2023-12-04 21:03:45 -05:00
e9a074d4d1 Merge branch 'EnglishCorrection' of https://github.com/PassiveLemon/zoraxy-dev into EnglishCorrection 2023-12-04 21:01:28 -05:00
4b7fd39e57 Update web root 2023-12-04 20:59:50 -05:00
fa005f1327 Update README.md 2023-12-04 20:59:25 -05:00
c7a9f40baa Update README.md 2023-12-04 20:44:42 -05:00
d5b9726158 Update index.html 2023-12-04 20:44:41 -05:00
f659e66cf7 Update CHANGELOG.md 2023-12-04 20:44:39 -05:00
801bdbf298 Fix: main.yml
Some things somehow passed by me and needed fixing.
Updated the actions in the process.
2023-11-28 23:16:51 -05:00
09da93cfb3 Merge pull request #70 from PassiveLemon/Ghcr
Update container (2.6.8)
2023-11-28 18:46:42 +08:00
70ace02e80 Revert port update 2023-11-27 20:18:24 -05:00
1f758e953d Fix: OpenSSL CVE 2023-11-26 16:16:31 -05:00
ffad2cab81 Comment out GHCR 2023-11-25 12:20:52 -05:00
dbb10644de Update to new port 2023-11-25 12:14:26 -05:00
4848392185 Merge branch 'tobychui:main' into Ghcr 2023-11-25 12:09:43 -05:00
956f4ac30f Merge pull request #85 from Morethanevil/patch-7
Update CHANGELOG.md
2023-11-25 23:07:14 +08:00
c09ff28fd5 Update CHANGELOG.md 2023-11-25 16:00:54 +01:00
20cf290d37 Merge pull request #84 from tobychui/2.6.8
Update v2.6.8
2023-11-25 22:25:22 +08:00
4ca0fcc6d1 Update main.go
Swap to use embedded web fs
2023-11-25 16:38:15 +08:00
ce4ce72820 Added optional TLS bypass mechanism
+ Added opt-out for subdomains for global TLS settings #44
+ Optimized subdomain / vdir editing interface
2023-11-25 15:54:28 +08:00
e363d55899 Fixed #77 and added systemwide logger
+ Added system wide logger (wip)
+ Fixed issue #77 uptime monitor bug
+ Added backend options for bypass global TLS (or allow per rule TLS settings, wip)
+
2023-11-25 12:50:30 +08:00
172479e4fb Added default HTTP/2 Mode
+ Added automatic HTTP/2 switch to TLS mode (Related to #40)
2023-10-20 13:44:47 +08:00
156fa5dace Bug fix
+ Added potential fix for #67
+ Update version number
+ Changed default static web port to 5487 so it is even more unlikely to be used
+
2023-10-20 11:01:28 +08:00
4d40e0aa38 Publish to GHCR 2023-10-03 16:36:53 -04:00
045e66b631 Revert "Publish to GitHub Container Registry"
This reverts commit 23bdaa1517.
2023-10-03 16:35:10 -04:00
62e60d78de Merge branch 'tobychui:main' into main 2023-10-03 16:34:43 -04:00
23bdaa1517 Publish to GitHub Container Registry 2023-10-03 16:34:23 -04:00
50f222cced Merge pull request #68 from Morethanevil/patch-6
Update CHANGELOG.md
2023-09-26 21:30:23 +08:00
640e1adf96 Update CHANGELOG.md
Updated to latest version
2023-09-26 09:28:57 +02:00
30 changed files with 744 additions and 181 deletions

View File

@ -9,18 +9,20 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v2 uses: actions/checkout@v4
with: with:
ref: ${{ github.event.release.tag_name }} ref: ${{ github.event.release.tag_name }}
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2 uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2 uses: docker/setup-buildx-action@v3
- name: Login to Dockerhub - name: Login to Docker & GHCR
run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin run: |
echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin
#echo "${{ secrets.GHCR_PASSWORD }}" | docker login ghcr.io -u "${{ secrets.GHCR_USERNAME }}" --password-stdin
- name: Setup building file structure - name: Setup building file structure
run: | run: |
@ -36,11 +38,8 @@ jobs:
--provenance=false \ --provenance=false \
--platform linux/amd64,linux/arm64 \ --platform linux/amd64,linux/arm64 \
--tag zoraxydocker/zoraxy:${{ github.event.release.tag_name }} \ --tag zoraxydocker/zoraxy:${{ github.event.release.tag_name }} \
.
docker buildx build --push \
--build-arg VERSION=${{ github.event.release.tag_name }} \
--provenance=false \
--platform linux/amd64,linux/arm64 \
--tag zoraxydocker/zoraxy:latest \ --tag zoraxydocker/zoraxy:latest \
# Since this is still undetermined, I will leave it commented
#--tag ghcr.io/zoraxydocker/zoraxy:${{ steps.get_latest_release_tag.outputs.latest_tag }} \
#--tag ghcr.io/zoraxydocker/zoraxy:latest \
. .

View File

@ -1,3 +1,22 @@
# v2.6.8 Nov 25 2023
+ Added opt-out for subdomains for global TLS settings: See [release notes](https://github.com/tobychui/zoraxy/releases/tag/2.6.8)
+ Optimized subdomain / vdir editing interface
+ Added system-wide logger (Work in progress)
+ Fixed issue for uptime monitor bug [#77](https://github.com/tobychui/zoraxy/issues/77)
+ Changed default static web port to 5487 (prevent already in use)
+ Added automatic HTTP/2 to TLS mode
+ Bug fix for webserver autostart [67](https://github.com/tobychui/zoraxy/issues/67)
# v2.6.7 Sep 26 2023
+ Added Static Web Server function [#56](https://github.com/tobychui/zoraxy/issues/56)
+ Web Directory Manager (see static webserver tab)
+ Added static web server and black / whitelist template [#38](https://github.com/tobychui/zoraxy/issues/38)
+ Added default / preferred CA features for ACME [#47](https://github.com/tobychui/zoraxy/issues/47)
+ Optimized TLS/SSL page and added dedicated section for ACME related features
+ Bugfixes [#61](https://github.com/tobychui/zoraxy/issues/61) [#58](https://github.com/tobychui/zoraxy/issues/58)
# v2.6.6 Aug 30 2023 # v2.6.6 Aug 30 2023
+ Added basic auth editor custom exception rules + Added basic auth editor custom exception rules
@ -5,20 +24,20 @@
+ Optimized memory usage (from 1.2GB to 61MB for low speed geoip lookup) [#52](https://github.com/tobychui/zoraxy/issues/52) + Optimized memory usage (from 1.2GB to 61MB for low speed geoip lookup) [#52](https://github.com/tobychui/zoraxy/issues/52)
+ Added unset subdomain custom redirection feature [#46](https://github.com/tobychui/zoraxy/issues/46) + Added unset subdomain custom redirection feature [#46](https://github.com/tobychui/zoraxy/issues/46)
+ Fixed potential security issue in satori/go.uuid [#55](https://github.com/tobychui/zoraxy/issues/55) + Fixed potential security issue in satori/go.uuid [#55](https://github.com/tobychui/zoraxy/issues/55)
+ Added custom acme feature in back-end, thx [@daluntw](https://github.com/daluntw) + Added custom ACME feature in backend, thx [@daluntw](https://github.com/daluntw)
+ Added bypass TLS check for custom acme server, thx [@daluntw](https://github.com/daluntw) + Added bypass TLS check for custom acme server, thx [@daluntw](https://github.com/daluntw)
+ Introduce new startparameter `-fastgeoip=true`, see [Releases](https://github.com/tobychui/zoraxy/releases/tag/2.6.6) + Introduce new start parameter `-fastgeoip=true`: see [release notes](https://github.com/tobychui/zoraxy/releases/tag/2.6.6)
# v2.6.5.1 Jul 26 2023 # v2.6.5.1 Jul 26 2023
+ Patch on memory leaking for Windows netstat module (do not effect any of the previous non Windows builds) + Patch on memory leaking for Windows netstat module (do not effect any of the previous non Windows builds)
+ Fixed potential memory leak in acme handler logic + Fixed potential memory leak in ACME handler logic
+ Added "Do you want to get a TLS certificate for this subdomain?" dialog when a new subdomain proxy rule is created + Added "Do you want to get a TLS certificate for this subdomain?" dialogue when a new subdomain proxy rule is created
# v2.6.5 Jul 19 2023 # v2.6.5 Jul 19 2023
+ Added Import / Export-Feature + Added Import / Export-Feature
+ Moved configurationfiles to a separate folder [#26](https://github.com/tobychui/zoraxy/issues/26) + Moved configuration files to a separate folder [#26](https://github.com/tobychui/zoraxy/issues/26)
+ Added auto-renew with ACME [#6](https://github.com/tobychui/zoraxy/issues/6) + Added auto-renew with ACME [#6](https://github.com/tobychui/zoraxy/issues/6)
+ Fixed Whitelistbug [#18](https://github.com/tobychui/zoraxy/issues/18) + Fixed Whitelistbug [#18](https://github.com/tobychui/zoraxy/issues/18)
+ Added Whois + Added Whois
@ -28,7 +47,7 @@
+ Added force TLS v1.2 above toggle + Added force TLS v1.2 above toggle
+ Added trace route + Added trace route
+ Added ICMP ping + Added ICMP ping
+ Added special routing rules module for up-coming acme integration + Added special routing rules module for up-coming ACME integration
+ Fixed IPv6 check bug in black/whitelist + Fixed IPv6 check bug in black/whitelist
+ Optimized UI for TCP Proxy + Optimized UI for TCP Proxy
@ -38,7 +57,7 @@
+ Split blacklist and whitelist from geodb script file + Split blacklist and whitelist from geodb script file
+ Optimized compile binary size + Optimized compile binary size
+ Added access control to TCP proxy + Added access control to TCP proxy
+ Added "invalid config detect" in up time monitor for isse [#7](https://github.com/tobychui/zoraxy/issues/7) + Added "invalid config detect" in up time monitor for issue [#7](https://github.com/tobychui/zoraxy/issues/7)
+ Fixed minor bugs in advance stats panel + Fixed minor bugs in advance stats panel
+ Reduced file size of embedded materials + Reduced file size of embedded materials
@ -65,6 +84,6 @@
+ Basic auth + Basic auth
+ Support TLS verification skip (for self signed certs) + Support TLS verification skip (for self signed certs)
+ Added trend analysis + Added trend analysis
+ Added referer and file type analysis + Added referrer and file type analysis
+ Added cert expire day display + Added cert expire day display
+ Moved subdomain proxy logic to dpcore + Moved subdomain proxy logic to dpcore

View File

@ -8,9 +8,7 @@ General purpose request (reverse) proxy and forwarding tool for low power device
- Simple to use interface with detail in-system instructions - Simple to use interface with detail in-system instructions
- Reverse Proxy - Reverse Proxy
- Subdomain Reverse Proxy - Subdomain Reverse Proxy
- Virtual Directory Reverse Proxy - Virtual Directory Reverse Proxy
- Redirection Rules - Redirection Rules
- TLS / SSL setup and deploy - TLS / SSL setup and deploy
@ -19,7 +17,6 @@ General purpose request (reverse) proxy and forwarding tool for low power device
- Integrated Up-time Monitor - Integrated Up-time Monitor
- Web-SSH Terminal - Web-SSH Terminal
- Utilities - Utilities
- CIDR IP converters - CIDR IP converters
- mDNS Scanner - mDNS Scanner
- IP Scanner - IP Scanner
@ -29,9 +26,9 @@ General purpose request (reverse) proxy and forwarding tool for low power device
- SMTP config for password reset - SMTP config for password reset
## Build from Source ## Build from Source
Require Go 1.20 or above Requires Go 1.20 or higher
``` ```bash
git clone https://github.com/tobychui/zoraxy git clone https://github.com/tobychui/zoraxy
cd ./zoraxy/src/ cd ./zoraxy/src/
go mod tidy go mod tidy
@ -42,11 +39,11 @@ sudo ./zoraxy -port=:8000
## Usage ## Usage
Zoraxy provide basic authentication system for standalone mode. To use it in standalone mode, follow the instruction below for your desired deployment platform. Zoraxy provides basic authentication system for standalone mode. To use it in standalone mode, follow the instructionss below for your desired deployment platform.
### Standalone Mode ### Standalone Mode
Standalone mode is the default mode for Zoraxy. This allow single account to manage your reverse proxy server just like a home router. This mode is suitable for new owners for homelab or makers start growing their web services into multiple servers. Standalone mode is the default mode for Zoraxy. This allows a single account to manage your reverse proxy server, just like a home router. This mode is suitable for new owners to homelabs or makers starting growing their web services into multiple servers.
#### Linux #### Linux
@ -60,18 +57,51 @@ Download the binary executable and double click the binary file to start it.
#### Raspberry Pi #### Raspberry Pi
The installation method is same as Linux. If you are using Raspberry Pi 4 or newer models, pick the arm64 release. For older version of Pis, use the arm (armv6) version instead. The installation method is same as Linux. If you are using a Raspberry Pi 4 or newer models, pick the arm64 release. For older version of Pis, use the arm (armv6) version instead.
#### Other ARM SBCs or Android phone with Termux #### Other ARM SBCs or Android phone with Termux
The installation method is same as Linux. For other ARM SBCs, please refer to your SBC's CPU architecture and pick the one that is suitable for your device. The installation method is same as Linux. For other ARM SBCs, please refer to your SBC's CPU architecture and pick the one that is suitable for your device.
#### Docker #### Docker
See the [/docker](https://github.com/tobychui/zoraxy/tree/main/docker) folder for more details See the [/docker](https://github.com/tobychui/zoraxy/tree/main/docker) folder for more details.
### Start Paramters
```
Usage of zoraxy:
-autorenew int
ACME auto TLS/SSL certificate renew check interval (seconds) (default 86400)
-fastgeoip
Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)
-info
Show information about this program in JSON
-log
Log terminal output to file (default true)
-mdns
Enable mDNS scanner and transponder (default true)
-noauth
Disable authentication for management interface
-port string
Management web interface listening port (default ":8000")
-rpt string
Reserved
-sshlb
Allow loopback web ssh connection (DANGER)
-version
Show version of this server
-webfm
Enable web file manager for static web server root folder (default true)
-webroot string
Static web server root folder. Only allow chnage in start paramters (default "./www")
-ztauth string
ZeroTier authtoken for the local node
-ztport int
ZeroTier controller API port (default 9993)
```
### External Permission Management Mode ### External Permission Management Mode
If you already have a up-stream reverse proxy server in place with permission management, you can use Zoraxy in noauth mode. To enable noauth mode, start Zoraxy with the following flag If you already have an upstream reverse proxy server in place with permission management, you can use Zoraxy in noauth mode. To enable noauth mode, start Zoraxy with the following flag:
```bash ```bash
./zoraxy -noauth=true ./zoraxy -noauth=true
@ -81,32 +111,32 @@ If you already have a up-stream reverse proxy server in place with permission ma
#### Use with ArozOS #### Use with ArozOS
[ArozOS ](https://arozos.com)subservice is a build in permission managed reverse proxy server. To use zoraxy with arozos, connect to your arozos host via ssh and use the following command to install zoraxy The [ArozOS](https://arozos.com) subservice is a built-in, permission-managed, reverse proxy server. To use Zoraxy with ArozOS, connect to your ArozOS host via SSH and use the following command to install Zoraxy:
```bash ```bash
# cd into your arozos subservice folder. Sometime it is under ~/arozos/src/subservice # cd into your ArozOS subservice folder. Sometimes it is under ~/arozos/src/subservice.
cd ~/arozos/subservices cd ~/arozos/subservices
mkdir zoraxy mkdir zoraxy
cd ./zoraxy cd ./zoraxy
# Download the release binary from Github release # Download the release binary from Github release.
wget {binary executable link from release page} wget {binary executable link from release page}
# Set permission. Change this if required # Set permission. Change this if required.
sudo chmod 775 -R ./ sudo chmod 775 -R ./
# Start zoraxy to see if the downloaded arch is correct. # Start zoraxy to see if the downloaded arch is correct.
./zoraxy ./zoraxy
# After the unzip done, press Ctrl + C to kill it # After unzipping, press Ctrl + C to kill it.
# Rename it to valid arozos subservice binary format # Rename it to validate the ArozOS subservice binary format.
mv ./zoraxy zoraxy_linux_amd64 mv ./zoraxy zoraxy_linux_amd64
# If you are using SBCs with different CPU arch, use the following names # If you are using SBCs with a different CPU arch, use the following names:
# mv ./zoraxy zoraxy_linux_arm # mv ./zoraxy zoraxy_linux_arm
# mv ./zoraxy zoraxy_linux_arm64 # mv ./zoraxy zoraxy_linux_arm64
# Restart arozos # Restart ArozOS
sudo systemctl restart arozos sudo systemctl restart arozos
``` ```
@ -128,22 +158,21 @@ There is a wikipage with [Frequently-Asked-Questions](https://github.com/tobychu
This project also compatible with [ZeroTier](https://www.zerotier.com/). However, due to licensing issues, ZeroTier is not included in the binary. This project also compatible with [ZeroTier](https://www.zerotier.com/). However, due to licensing issues, ZeroTier is not included in the binary.
Assuming you already have a valid license, to use Zoraxy with ZeroTier, install ZeroTier on your host and then run Zoraxy in sudo mode (or Run As Administrator if you are on Windows). The program will automatically grab the authtoken at correct location in your host. To use Zoraxy with ZeroTier, assuming you already have a valid license, install ZeroTier on your host and then run Zoraxy in sudo mode (or Run As Administrator if you are on Windows). The program will automatically grab the authtoken in the correct location on your host.
If you prefer not to run Zoraxy in sudo mode or you have some weird installation profile, you can also pass in the ZeroTier auth token using the following flags If you prefer not to run Zoraxy in sudo mode or you have some weird installation profile, you can also pass in the ZeroTier auth token using the following flags::
``` ```bash
./zoraxy -ztauth="your_zerotier_authtoken" -ztport=9993 ./zoraxy -ztauth="your_zerotier_authtoken" -ztport=9993
``` ```
The ZeroTier auth token can usually be found at ```/var/lib/zerotier-one/authtoken.secret``` or ```C:\ProgramData\ZeroTier\One\authtoken.secret```. The ZeroTier auth token can usually be found at ```/var/lib/zerotier-one/authtoken.secret``` or ```C:\ProgramData\ZeroTier\One\authtoken.secret```.
This allows you to have infinite number of network members in your Global Area Network controller. For more technical details, see [here](https://docs.zerotier.com/self-hosting/network-controllers/). This allows you to have an infinite number of network members in your Global Area Network controller. For more technical details, see [here](https://docs.zerotier.com/self-hosting/network-controllers/).
## Web.SSH ## Web SSH
Web SSH currently only support Linux based OS. The following platforms are supported
Web SSH currently only supports Linux based OSes. The following platforms are supported:
- linux/amd64 - linux/amd64
- linux/arm64 - linux/arm64
- linux/armv6 (experimental) - linux/armv6 (experimental)
@ -151,9 +180,9 @@ Web SSH currently only support Linux based OS. The following platforms are suppo
### Loopback Connection ### Loopback Connection
Loopback web ssh connection, by default, is disabled. This means that if you are trying to connect to address like 127.0.0.1 or localhost, the system will reject your connection due to security issues. To enable loopback for testing or development purpose, use the following flags to override the loopback checking. Loopback web SSH connection, by default, is disabled. This means that if you are trying to connect to an address like 127.0.0.1 or localhost, the system will reject your connection for security reasons. To enable loopback for testing or development purpose, use the following flags to override the loopback checking:
``` ```bash
./zoraxy -sshlb=true ./zoraxy -sshlb=true
``` ```
@ -165,5 +194,5 @@ If you like the project and want to support us, please consider a donation. You
## License ## License
This project is open source under AGPL. I open source this project so everyone can check for security issues and benefit all users. **If your plans to use this project in commercial environment which violate the AGPL terms, please contact toby@imuslab.com for an alternative commercial license.** This project is open-sourced under AGPL. I open-sourced this project so everyone can check for security issues and benefit all users. **If you plan to use this project in a commercial environment (which violate the AGPL terms), please contact toby@imuslab.com for an alternative commercial license.**

View File

@ -3,6 +3,8 @@ FROM docker.io/golang:alpine
ARG VERSION ARG VERSION
RUN apk add --no-cache bash netcat-openbsd sudo RUN apk add --no-cache bash netcat-openbsd sudo
# Alternatives for security
RUN apk add --no-cache openssl=3.1.4-r1
RUN mkdir -p /opt/zoraxy/source/ &&\ RUN mkdir -p /opt/zoraxy/source/ &&\
mkdir -p /opt/zoraxy/config/ &&\ mkdir -p /opt/zoraxy/config/ &&\

View File

@ -39,7 +39,7 @@ services:
| `-p (ports)` | Yes | Depending on how your network is setup, you may need to portforward 80, 443, and the management port. | | `-p (ports)` | Yes | Depending on how your network is setup, you may need to portforward 80, 443, and the management port. |
| `-v (path to storage directory):/opt/zoraxy/config/` | Recommend | Sets the folder that holds your files. This should be the place you just chose. By default, it will create a Docker volume for the files for persistency but they will not be accessible. | | `-v (path to storage directory):/opt/zoraxy/config/` | Recommend | Sets the folder that holds your files. This should be the place you just chose. By default, it will create a Docker volume for the files for persistency but they will not be accessible. |
| `-e ARGS='(your arguments)'` | No | Sets the arguments to run Zoraxy with. Enter them as you would normally. By default, it is ran with `-noauth=false` but <b>you cannot change the management port.</b> This is required for the healthcheck to work. | | `-e ARGS='(your arguments)'` | No | Sets the arguments to run Zoraxy with. Enter them as you would normally. By default, it is ran with `-noauth=false` but <b>you cannot change the management port.</b> This is required for the healthcheck to work. |
| `zoraxydocker/zoraxy:latest` | Yes | The repository on Docker hub. By default, it is the latest version that I have published. | | `zoraxydocker/zoraxy:latest` | Yes | The repository on Docker hub. By default, it is the latest version that is published. |
## Examples: </br> ## Examples: </br>
### Docker Run </br> ### Docker Run </br>

View File

@ -148,7 +148,7 @@
Reverse Proxy Reverse Proxy
</div> </div>
</h3> </h3>
<p>Simple to use, noobs friendly reverse proxy server that can be easily set-up using a web form and a few toggle switches.</p> <p>Simple to use noob-friendly reverse proxy server that can be easily set up using a web form and a few toggle switches.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -158,7 +158,7 @@
Redirection Redirection
</div> </div>
</h3> </h3>
<p>Direct and intuitive redirection rules with basic rewrite options. Suitable for most of the simple use cases.</p> <p>Direct and intuitive redirection rules with basic rewrite options. Suitable for most simple use cases.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -168,7 +168,7 @@
Geo-IP & Blacklist Geo-IP & Blacklist
</div> </div>
</h3> </h3>
<p>Blacklist with GeoIP support. Allow easy setup for regional services.</p> <p>Blacklist with GeoIP support. Allows easy setup for regional services.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -189,7 +189,7 @@
Web SSH Web SSH
</div> </div>
</h3> </h3>
<p>Integrated with Gotty Web SSH terminal, allow one-stop management of your nodes inside private LAN via gateway nodes.</p> <p>Integration with Gotty Web SSH terminal allows one-stop management of your nodes inside private LAN via gateway nodes.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -199,7 +199,7 @@
Real Time Statistics Real Time Statistics
</div> </div>
</h3> </h3>
<p>Traffic data collection and real time analytic tools, provide you the best insights of visitors data without cookies.</p> <p>Traffic data collection and real-time analytic tools provide you the best insight of visitors data without cookies.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -209,7 +209,7 @@
Scanner & Utilities Scanner & Utilities
</div> </div>
</h3> </h3>
<p>Build in IP scanner and mDNS discovering service, enable automatic service discovery within LAN.</p> <p>Build in IP scanner and mDNS discovery service to enable automatic service discovery within LAN.</p>
</div> </div>
<div class="four wide column featureItem"> <div class="four wide column featureItem">
@ -219,7 +219,7 @@
Open Source Open Source
</div> </div>
</h3> </h3>
<p>Project is open source under AGPL on Github. Feel free to contribute on missing functions you need! </p> <p>Project is open-source under AGPL on Github. Feel free to contribute on missing functions you need! </p>
</div> </div>
</div> </div>
</div> </div>

View File

@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"math/rand" "math/rand"
"net/http" "net/http"
"regexp" "regexp"
@ -29,7 +28,7 @@ func getRandomPort(minPort int) int {
// init the new ACME instance // init the new ACME instance
func initACME() *acme.ACMEHandler { func initACME() *acme.ACMEHandler {
log.Println("Starting ACME handler") SystemWideLogger.Println("Starting ACME handler")
rand.Seed(time.Now().UnixNano()) rand.Seed(time.Now().UnixNano())
// Generate a random port above 30000 // Generate a random port above 30000
port := getRandomPort(30000) port := getRandomPort(30000)
@ -44,7 +43,7 @@ func initACME() *acme.ACMEHandler {
// create the special routing rule for ACME // create the special routing rule for ACME
func acmeRegisterSpecialRoutingRule() { func acmeRegisterSpecialRoutingRule() {
log.Println("Assigned temporary port:" + acmeHandler.Getport()) SystemWideLogger.Println("Assigned temporary port:" + acmeHandler.Getport())
err := dynamicProxyRouter.AddRoutingRules(&dynamicproxy.RoutingRule{ err := dynamicProxyRouter.AddRoutingRules(&dynamicproxy.RoutingRule{
ID: "acme-autorenew", ID: "acme-autorenew",
@ -79,7 +78,7 @@ func acmeRegisterSpecialRoutingRule() {
}) })
if err != nil { if err != nil {
log.Println("[Err] " + err.Error()) SystemWideLogger.PrintAndLog("ACME", "Unable register temp port for DNS resolver", err)
} }
} }
@ -89,7 +88,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
if dynamicProxyRouter.Option.Port == 443 { if dynamicProxyRouter.Option.Port == 443 {
//Enable port 80 to 443 redirect //Enable port 80 to 443 redirect
if !dynamicProxyRouter.Option.ForceHttpsRedirect { if !dynamicProxyRouter.Option.ForceHttpsRedirect {
log.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests") SystemWideLogger.Println("Temporary enabling HTTP to HTTPS redirect for ACME certificate renew requests")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
} else { } else {
//Set this to true, so after renew, do not turn it off //Set this to true, so after renew, do not turn it off
@ -110,7 +109,7 @@ func AcmeCheckAndHandleRenewCertificate(w http.ResponseWriter, r *http.Request)
if dynamicProxyRouter.Option.Port == 443 { if dynamicProxyRouter.Option.Port == 443 {
if !isForceHttpsRedirectEnabledOriginally { if !isForceHttpsRedirectEnabledOriginally {
//Default is off. Turn the redirection off //Default is off. Turn the redirection off
log.Println("Restoring HTTP to HTTPS redirect settings") SystemWideLogger.PrintAndLog("ACME", "Restoring HTTP to HTTPS redirect settings", nil)
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
} }
} }
@ -130,7 +129,7 @@ func HandleACMEPreferredCA(w http.ResponseWriter, r *http.Request) {
acme.IsSupportedCA(ca) acme.IsSupportedCA(ca)
//Set the new config //Set the new config
sysdb.Write("acmepref", "prefca", ca) sysdb.Write("acmepref", "prefca", ca)
log.Println("Updating prefered ACME CA to " + ca) SystemWideLogger.Println("Updating prefered ACME CA to " + ca)
utils.SendOK(w) utils.SendOK(w)
} }

View File

@ -54,6 +54,7 @@ func initAPIs() {
authRouter.HandleFunc("/api/proxy/tlscheck", HandleCheckSiteSupportTLS) authRouter.HandleFunc("/api/proxy/tlscheck", HandleCheckSiteSupportTLS)
authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet) authRouter.HandleFunc("/api/proxy/setIncoming", HandleIncomingPortSet)
authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect) authRouter.HandleFunc("/api/proxy/useHttpsRedirect", HandleUpdateHttpsRedirect)
authRouter.HandleFunc("/api/proxy/listenPort80", HandleUpdatePort80Listener)
authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck) authRouter.HandleFunc("/api/proxy/requestIsProxied", HandleManagementProxyCheck)
//Reverse proxy root related APIs //Reverse proxy root related APIs
authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList) authRouter.HandleFunc("/api/proxy/root/listOptions", HandleRootRouteOptionList)

View File

@ -6,7 +6,6 @@ import (
"encoding/pem" "encoding/pem"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -128,7 +127,7 @@ func handleListDomains(w http.ResponseWriter, r *http.Request) {
certBtyes, err := os.ReadFile(certFilepath) certBtyes, err := os.ReadFile(certFilepath)
if err != nil { if err != nil {
// Unable to load this file // Unable to load this file
log.Println("Unable to load certificate: " + certFilepath) SystemWideLogger.PrintAndLog("TLS", "Unable to load certificate: "+certFilepath, err)
continue continue
} else { } else {
// Cert loaded. Check its expiry time // Cert loaded. Check its expiry time
@ -182,11 +181,11 @@ func handleToggleTLSProxy(w http.ResponseWriter, r *http.Request) {
} else { } else {
if newState == "true" { if newState == "true" {
sysdb.Write("settings", "usetls", true) sysdb.Write("settings", "usetls", true)
log.Println("Enabling TLS mode on reverse proxy") SystemWideLogger.Println("Enabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(true) dynamicProxyRouter.UpdateTLSSetting(true)
} else if newState == "false" { } else if newState == "false" {
sysdb.Write("settings", "usetls", false) sysdb.Write("settings", "usetls", false)
log.Println("Disabling TLS mode on reverse proxy") SystemWideLogger.Println("Disabling TLS mode on reverse proxy")
dynamicProxyRouter.UpdateTLSSetting(false) dynamicProxyRouter.UpdateTLSSetting(false)
} else { } else {
utils.SendErrorResponse(w, "invalid state given. Only support true or false") utils.SendErrorResponse(w, "invalid state given. Only support true or false")
@ -213,11 +212,11 @@ func handleSetTlsRequireLatest(w http.ResponseWriter, r *http.Request) {
} else { } else {
if newState == "true" { if newState == "true" {
sysdb.Write("settings", "forceLatestTLS", true) sysdb.Write("settings", "forceLatestTLS", true)
log.Println("Updating minimum TLS version to v1.2 or above") SystemWideLogger.Println("Updating minimum TLS version to v1.2 or above")
dynamicProxyRouter.UpdateTLSVersion(true) dynamicProxyRouter.UpdateTLSVersion(true)
} else if newState == "false" { } else if newState == "false" {
sysdb.Write("settings", "forceLatestTLS", false) sysdb.Write("settings", "forceLatestTLS", false)
log.Println("Updating minimum TLS version to v1.0 or above") SystemWideLogger.Println("Updating minimum TLS version to v1.0 or above")
dynamicProxyRouter.UpdateTLSVersion(false) dynamicProxyRouter.UpdateTLSVersion(false)
} else { } else {
utils.SendErrorResponse(w, "invalid state given") utils.SendErrorResponse(w, "invalid state given")

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
@ -29,6 +28,7 @@ type Record struct {
Rootname string Rootname string
ProxyTarget string ProxyTarget string
UseTLS bool UseTLS bool
BypassGlobalTLS bool
SkipTlsValidation bool SkipTlsValidation bool
RequireBasicAuth bool RequireBasicAuth bool
BasicAuthCredentials []*dynamicproxy.BasicAuthCredentials BasicAuthCredentials []*dynamicproxy.BasicAuthCredentials
@ -61,11 +61,11 @@ func SaveReverseProxyEndpointToFile(proxyEndpoint *dynamicproxy.ProxyEndpoint) e
func RemoveReverseProxyConfigFile(rootname string) error { func RemoveReverseProxyConfigFile(rootname string) error {
filename := getFilenameFromRootName(rootname) filename := getFilenameFromRootName(rootname)
removePendingFile := strings.ReplaceAll(filepath.Join("./conf/proxy/", filename), "\\", "/") removePendingFile := strings.ReplaceAll(filepath.Join("./conf/proxy/", filename), "\\", "/")
log.Println("Config Removed: ", removePendingFile) SystemWideLogger.Println("Config Removed: ", removePendingFile)
if utils.FileExists(removePendingFile) { if utils.FileExists(removePendingFile) {
err := os.Remove(removePendingFile) err := os.Remove(removePendingFile)
if err != nil { if err != nil {
log.Println(err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Unabel to remove config file", err)
return err return err
} }
} }
@ -81,6 +81,7 @@ func LoadReverseProxyConfig(filename string) (*Record, error) {
Rootname: "", Rootname: "",
ProxyTarget: "", ProxyTarget: "",
UseTLS: false, UseTLS: false,
BypassGlobalTLS: false,
SkipTlsValidation: false, SkipTlsValidation: false,
RequireBasicAuth: false, RequireBasicAuth: false,
BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{}, BasicAuthCredentials: []*dynamicproxy.BasicAuthCredentials{},
@ -109,6 +110,7 @@ func ConvertProxyEndpointToRecord(targetProxyEndpoint *dynamicproxy.ProxyEndpoin
Rootname: targetProxyEndpoint.RootOrMatchingDomain, Rootname: targetProxyEndpoint.RootOrMatchingDomain,
ProxyTarget: targetProxyEndpoint.Domain, ProxyTarget: targetProxyEndpoint.Domain,
UseTLS: targetProxyEndpoint.RequireTLS, UseTLS: targetProxyEndpoint.RequireTLS,
BypassGlobalTLS: targetProxyEndpoint.BypassGlobalTLS,
SkipTlsValidation: targetProxyEndpoint.SkipCertValidations, SkipTlsValidation: targetProxyEndpoint.SkipCertValidations,
RequireBasicAuth: targetProxyEndpoint.RequireBasicAuth, RequireBasicAuth: targetProxyEndpoint.RequireBasicAuth,
BasicAuthCredentials: targetProxyEndpoint.BasicAuthCredentials, BasicAuthCredentials: targetProxyEndpoint.BasicAuthCredentials,
@ -191,14 +193,14 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
//Also zip in the sysdb //Also zip in the sysdb
zipFile, err := zipWriter.Create("sys.db") zipFile, err := zipWriter.Create("sys.db")
if err != nil { if err != nil {
log.Println("[Backup] Unable to zip sysdb: " + err.Error()) SystemWideLogger.PrintAndLog("Backup", "Unable to zip sysdb", err)
return return
} }
// Open the file on disk // Open the file on disk
file, err := os.Open("sys.db") file, err := os.Open("sys.db")
if err != nil { if err != nil {
log.Println("[Backup] Unable to open sysdb: " + err.Error()) SystemWideLogger.PrintAndLog("Backup", "Unable to open sysdb", err)
return return
} }
defer file.Close() defer file.Close()
@ -206,7 +208,7 @@ func ExportConfigAsZip(w http.ResponseWriter, r *http.Request) {
// Copy the file contents to the zip file // Copy the file contents to the zip file
_, err = io.Copy(zipFile, file) _, err = io.Copy(zipFile, file)
if err != nil { if err != nil {
log.Println(err) SystemWideLogger.Println(err)
return return
} }
@ -311,12 +313,12 @@ func ImportConfigFromZip(w http.ResponseWriter, r *http.Request) {
// Send a success response // Send a success response
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
log.Println("Configuration restored") SystemWideLogger.Println("Configuration restored")
fmt.Fprintln(w, "Configuration restored") fmt.Fprintln(w, "Configuration restored")
if restoreDatabase { if restoreDatabase {
go func() { go func() {
log.Println("Database altered. Restarting in 3 seconds...") SystemWideLogger.Println("Database altered. Restarting in 3 seconds...")
time.Sleep(3 * time.Second) time.Sleep(3 * time.Second)
os.Exit(0) os.Exit(0)
}() }()

View File

@ -20,6 +20,7 @@ import (
"imuslab.com/zoraxy/mod/email" "imuslab.com/zoraxy/mod/email"
"imuslab.com/zoraxy/mod/ganserv" "imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb" "imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
"imuslab.com/zoraxy/mod/mdns" "imuslab.com/zoraxy/mod/mdns"
"imuslab.com/zoraxy/mod/netstat" "imuslab.com/zoraxy/mod/netstat"
"imuslab.com/zoraxy/mod/pathrule" "imuslab.com/zoraxy/mod/pathrule"
@ -44,10 +45,11 @@ var acmeAutoRenewInterval = flag.Int("autorenew", 86400, "ACME auto TLS/SSL cert
var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)") var enableHighSpeedGeoIPLookup = flag.Bool("fastgeoip", false, "Enable high speed geoip lookup, require 1GB extra memory (Not recommend for low end devices)")
var staticWebServerRoot = flag.String("webroot", "./www", "Static web server root folder. Only allow chnage in start paramters") var staticWebServerRoot = flag.String("webroot", "./www", "Static web server root folder. Only allow chnage in start paramters")
var allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder") var allowWebFileManager = flag.Bool("webfm", true, "Enable web file manager for static web server root folder")
var logOutputToFile = flag.Bool("log", true, "Log terminal output to file")
var ( var (
name = "Zoraxy" name = "Zoraxy"
version = "2.6.7" version = "2.6.8"
nodeUUID = "generic" nodeUUID = "generic"
development = false //Set this to false to use embedded web fs development = false //Set this to false to use embedded web fs
bootTime = time.Now().Unix() bootTime = time.Now().Unix()
@ -80,8 +82,9 @@ var (
staticWebServer *webserv.WebServer //Static web server for hosting simple stuffs staticWebServer *webserv.WebServer //Static web server for hosting simple stuffs
//Helper modules //Helper modules
EmailSender *email.Sender //Email sender that handle email sending EmailSender *email.Sender //Email sender that handle email sending
AnalyticLoader *analytic.DataLoader //Data loader for Zoraxy Analytic AnalyticLoader *analytic.DataLoader //Data loader for Zoraxy Analytic
SystemWideLogger *logger.Logger //Logger for Zoraxy
) )
// Kill signal handler. Do something before the system the core terminate. // Kill signal handler. Do something before the system the core terminate.
@ -116,6 +119,9 @@ func ShutdownSeq() {
fmt.Println("- Cleaning up tmp files") fmt.Println("- Cleaning up tmp files")
os.RemoveAll("./tmp") os.RemoveAll("./tmp")
fmt.Println("- Closing system wide logger")
SystemWideLogger.Close()
//Close database, final //Close database, final
fmt.Println("- Stopping system database") fmt.Println("- Stopping system database")
sysdb.Close() sysdb.Close()
@ -151,7 +157,7 @@ func main() {
} }
uuidBytes, err := os.ReadFile(uuidRecord) uuidBytes, err := os.ReadFile(uuidRecord)
if err != nil { if err != nil {
log.Println("Unable to read system uuid from file system") SystemWideLogger.PrintAndLog("ZeroTier", "Unable to read system uuid from file system", nil)
panic(err) panic(err)
} }
nodeUUID = string(uuidBytes) nodeUUID = string(uuidBytes)
@ -173,7 +179,7 @@ func main() {
//Start the finalize sequences //Start the finalize sequences
finalSequence() finalSequence()
log.Println("Zoraxy started. Visit control panel at http://localhost" + handler.Port) SystemWideLogger.Println("Zoraxy started. Visit control panel at http://localhost" + handler.Port)
err = http.ListenAndServe(handler.Port, nil) err = http.ListenAndServe(handler.Port, nil)
if err != nil { if err != nil {

View File

@ -60,6 +60,12 @@ func (router *Router) UpdateTLSVersion(requireLatest bool) {
router.Restart() router.Restart()
} }
// Update port 80 listener state
func (router *Router) UpdatePort80ListenerState(useRedirect bool) {
router.Option.ListenOnPort80 = useRedirect
router.Restart()
}
// Update https redirect, which will require updates // Update https redirect, which will require updates
func (router *Router) UpdateHttpToHttpsRedirectSetting(useRedirect bool) { func (router *Router) UpdateHttpToHttpsRedirectSetting(useRedirect bool) {
router.Option.ForceHttpsRedirect = useRedirect router.Option.ForceHttpsRedirect = useRedirect
@ -95,27 +101,73 @@ func (router *Router) StartProxyService() error {
} }
if router.Option.UseTls { if router.Option.UseTls {
//Serve with TLS mode /*
ln, err := tls.Listen("tcp", ":"+strconv.Itoa(router.Option.Port), config) //Serve with TLS mode
if err != nil { ln, err := tls.Listen("tcp", ":"+strconv.Itoa(router.Option.Port), config)
log.Println(err) if err != nil {
router.Running = false log.Println(err)
return err router.Running = false
return err
}
router.tlsListener = ln
*/
router.server = &http.Server{
Addr: ":" + strconv.Itoa(router.Option.Port),
Handler: router.mux,
TLSConfig: config,
} }
router.tlsListener = ln
router.server = &http.Server{Addr: ":" + strconv.Itoa(router.Option.Port), Handler: router.mux}
router.Running = true router.Running = true
if router.Option.Port != 80 && router.Option.ForceHttpsRedirect { if router.Option.Port != 80 && router.Option.ListenOnPort80 {
//Add a 80 to 443 redirector //Add a 80 to 443 redirector
httpServer := &http.Server{ httpServer := &http.Server{
Addr: ":80", Addr: ":80",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
protocol := "https://" //Check if the domain requesting allow non TLS mode
if router.Option.Port == 443 { domainOnly := r.Host
http.Redirect(w, r, protocol+r.Host+r.RequestURI, http.StatusTemporaryRedirect) if strings.Contains(r.Host, ":") {
hostPath := strings.Split(r.Host, ":")
domainOnly = hostPath[0]
}
sep := router.getSubdomainProxyEndpointFromHostname(domainOnly)
if sep != nil && sep.BypassGlobalTLS {
//Allow routing via non-TLS handler
originalHostHeader := r.Host
if r.URL != nil {
r.Host = r.URL.Host
} else {
//Fallback when the upstream proxy screw something up in the header
r.URL, _ = url.Parse(originalHostHeader)
}
sep.Proxy.ServeHTTP(w, r, &dpcore.ResponseRewriteRuleSet{
ProxyDomain: sep.Domain,
OriginalHost: originalHostHeader,
UseTLS: sep.RequireTLS,
PathPrefix: "",
})
return
}
if router.Option.ForceHttpsRedirect {
//Redirect to https is enabled
protocol := "https://"
if router.Option.Port == 443 {
http.Redirect(w, r, protocol+r.Host+r.RequestURI, http.StatusTemporaryRedirect)
} else {
http.Redirect(w, r, protocol+r.Host+":"+strconv.Itoa(router.Option.Port)+r.RequestURI, http.StatusTemporaryRedirect)
}
} else { } else {
http.Redirect(w, r, protocol+r.Host+":"+strconv.Itoa(router.Option.Port)+r.RequestURI, http.StatusTemporaryRedirect) //Do not do redirection
if sep != nil {
//Sub-domain exists but not allow non-TLS access
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("400 - Bad Request"))
} else {
//No defined sub-domain
http.NotFound(w, r)
}
} }
}), }),
@ -143,7 +195,7 @@ func (router *Router) StartProxyService() error {
if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed { if err := httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
//Unable to startup port 80 listener. Handle shutdown process gracefully //Unable to startup port 80 listener. Handle shutdown process gracefully
stopChan <- true stopChan <- true
log.Fatalf("Could not start server: %v\n", err) log.Fatalf("Could not start redirection server: %v\n", err)
} }
}() }()
router.tlsRedirectStop = stopChan router.tlsRedirectStop = stopChan
@ -152,8 +204,8 @@ func (router *Router) StartProxyService() error {
//Start the TLS server //Start the TLS server
log.Println("Reverse proxy service started in the background (TLS mode)") log.Println("Reverse proxy service started in the background (TLS mode)")
go func() { go func() {
if err := router.server.Serve(ln); err != nil && err != http.ErrServerClosed { if err := router.server.ListenAndServeTLS("", ""); err != nil && err != http.ErrServerClosed {
log.Fatalf("Could not start server: %v\n", err) log.Fatalf("Could not start proxy server: %v\n", err)
} }
}() }()
} else { } else {

View File

@ -38,6 +38,7 @@ func (router *Router) AddSubdomainRoutingService(options *SubdOptions) error {
Domain: domain, Domain: domain,
RequireTLS: options.RequireTLS, RequireTLS: options.RequireTLS,
Proxy: proxy, Proxy: proxy,
BypassGlobalTLS: options.BypassGlobalTLS,
SkipCertValidations: options.SkipCertValidations, SkipCertValidations: options.SkipCertValidations,
RequireBasicAuth: options.RequireBasicAuth, RequireBasicAuth: options.RequireBasicAuth,
BasicAuthCredentials: options.BasicAuthCredentials, BasicAuthCredentials: options.BasicAuthCredentials,

View File

@ -27,6 +27,7 @@ type RouterOption struct {
Port int //Incoming port Port int //Incoming port
UseTls bool //Use TLS to serve incoming requsts UseTls bool //Use TLS to serve incoming requsts
ForceTLSLatest bool //Force TLS1.2 or above ForceTLSLatest bool //Force TLS1.2 or above
ListenOnPort80 bool //Enable port 80 http listener
ForceHttpsRedirect bool //Force redirection of http to https endpoint ForceHttpsRedirect bool //Force redirection of http to https endpoint
TlsManager *tlscert.Manager TlsManager *tlscert.Manager
RedirectRuleTable *redirection.RuleTable RedirectRuleTable *redirection.RuleTable

View File

@ -0,0 +1,103 @@
package logger
import (
"fmt"
"log"
"os"
"path/filepath"
"strconv"
"time"
)
/*
Zoraxy Logger
This script is designed to make a managed log for the Zoraxy
and replace the ton of log.Println in the system core
*/
type Logger struct {
LogToFile bool //Set enable write to file
Prefix string //Prefix for log files
LogFolder string //Folder to store the log file
CurrentLogFile string //Current writing filename
file *os.File
}
func NewLogger(logFilePrefix string, logFolder string, logToFile bool) (*Logger, error) {
err := os.MkdirAll(logFolder, 0775)
if err != nil {
return nil, err
}
thisLogger := Logger{
LogToFile: logToFile,
Prefix: logFilePrefix,
LogFolder: logFolder,
}
logFilePath := thisLogger.getLogFilepath()
f, err := os.OpenFile(logFilePath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
return nil, err
}
thisLogger.CurrentLogFile = logFilePath
thisLogger.file = f
return &thisLogger, nil
}
func (l *Logger) getLogFilepath() string {
year, month, _ := time.Now().Date()
return filepath.Join(l.LogFolder, l.Prefix+"_"+strconv.Itoa(year)+"-"+strconv.Itoa(int(month))+".log")
}
// PrintAndLog will log the message to file and print the log to STDOUT
func (l *Logger) PrintAndLog(title string, message string, originalError error) {
go func() {
l.Log(title, message, originalError)
}()
log.Println("[" + title + "] " + message)
}
// Println is a fast snap-in replacement for log.Println
func (l *Logger) Println(v ...interface{}) {
//Convert the array of interfaces into string
message := fmt.Sprint(v...)
go func() {
l.Log("info", string(message), nil)
}()
log.Println("[INFO] " + string(message))
}
func (l *Logger) Log(title string, errorMessage string, originalError error) {
l.ValidateAndUpdateLogFilepath()
if l.LogToFile {
if originalError == nil {
l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [INFO]" + errorMessage + "\n")
} else {
l.file.WriteString(time.Now().Format("2006-01-02 15:04:05.000000") + "|" + fmt.Sprintf("%-16s", title) + " [ERROR]" + errorMessage + " " + originalError.Error() + "\n")
}
}
}
// Validate if the logging target is still valid (detect any months change)
func (l *Logger) ValidateAndUpdateLogFilepath() {
expectedCurrentLogFilepath := l.getLogFilepath()
if l.CurrentLogFile != expectedCurrentLogFilepath {
//Change of month. Update to a new log file
l.file.Close()
f, err := os.OpenFile(expectedCurrentLogFilepath, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0755)
if err != nil {
log.Println("[Logger] Unable to create new log. Logging to file disabled.")
l.LogToFile = false
return
}
l.CurrentLogFile = expectedCurrentLogFilepath
l.file = f
}
}
func (l *Logger) Close() {
l.file.Close()
}

View File

@ -0,0 +1,122 @@
package logviewer
import (
"encoding/json"
"errors"
"io/fs"
"net/http"
"os"
"path/filepath"
"strings"
"imuslab.com/zoraxy/mod/utils"
)
type ViewerOption struct {
RootFolder string //The root folder to scan for log
Extension string //The extension the root files use, include the . in your ext (e.g. .log)
}
type Viewer struct {
option *ViewerOption
}
type LogFile struct {
Title string
Filename string
Fullpath string
Filesize int64
}
func NewLogViewer(option *ViewerOption) *Viewer {
return &Viewer{option: option}
}
/*
Log Request Handlers
*/
//List all the log files in the log folder. Return in map[string]LogFile format
func (v *Viewer) HandleListLog(w http.ResponseWriter, r *http.Request) {
logFiles := v.ListLogFiles(false)
js, _ := json.Marshal(logFiles)
utils.SendJSONResponse(w, string(js))
}
// Read log of a given catergory and filename
// Require GET varaible: file and catergory
func (v *Viewer) HandleReadLog(w http.ResponseWriter, r *http.Request) {
filename, err := utils.GetPara(r, "file")
if err != nil {
utils.SendErrorResponse(w, "invalid filename given")
return
}
catergory, err := utils.GetPara(r, "catergory")
if err != nil {
utils.SendErrorResponse(w, "invalid catergory given")
return
}
content, err := v.LoadLogFile(strings.TrimSpace(filepath.Base(catergory)), strings.TrimSpace(filepath.Base(filename)))
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
utils.SendTextResponse(w, content)
}
/*
Log Access Functions
*/
func (v *Viewer) ListLogFiles(showFullpath bool) map[string][]*LogFile {
result := map[string][]*LogFile{}
filepath.WalkDir(v.option.RootFolder, func(path string, di fs.DirEntry, err error) error {
if filepath.Ext(path) == v.option.Extension {
catergory := filepath.Base(filepath.Dir(path))
logList, ok := result[catergory]
if !ok {
//this catergory hasn't been scanned before.
logList = []*LogFile{}
}
fullpath := filepath.ToSlash(path)
if !showFullpath {
fullpath = ""
}
st, err := os.Stat(path)
if err != nil {
return nil
}
logList = append(logList, &LogFile{
Title: strings.TrimSuffix(filepath.Base(path), filepath.Ext(path)),
Filename: filepath.Base(path),
Fullpath: fullpath,
Filesize: st.Size(),
})
result[catergory] = logList
}
return nil
})
return result
}
func (v *Viewer) LoadLogFile(catergory string, filename string) (string, error) {
logFilepath := filepath.Join(v.option.RootFolder, catergory, filename)
if utils.FileExists(logFilepath) {
//Load it
content, err := os.ReadFile(logFilepath)
if err != nil {
return "", err
}
return string(content), nil
} else {
return "", errors.New("log file not found")
}
}

View File

@ -2,7 +2,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"log"
"net/http" "net/http"
"path/filepath" "path/filepath"
"sort" "sort"
@ -25,33 +24,43 @@ func ReverseProxtInit() {
inboundPort := 80 inboundPort := 80
if sysdb.KeyExists("settings", "inbound") { if sysdb.KeyExists("settings", "inbound") {
sysdb.Read("settings", "inbound", &inboundPort) sysdb.Read("settings", "inbound", &inboundPort)
log.Println("Serving inbound port ", inboundPort) SystemWideLogger.Println("Serving inbound port ", inboundPort)
} else { } else {
log.Println("Inbound port not set. Using default (80)") SystemWideLogger.Println("Inbound port not set. Using default (80)")
} }
useTls := false useTls := false
sysdb.Read("settings", "usetls", &useTls) sysdb.Read("settings", "usetls", &useTls)
if useTls { if useTls {
log.Println("TLS mode enabled. Serving proxxy request with TLS") SystemWideLogger.Println("TLS mode enabled. Serving proxxy request with TLS")
} else { } else {
log.Println("TLS mode disabled. Serving proxy request with plain http") SystemWideLogger.Println("TLS mode disabled. Serving proxy request with plain http")
} }
forceLatestTLSVersion := false forceLatestTLSVersion := false
sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion) sysdb.Read("settings", "forceLatestTLS", &forceLatestTLSVersion)
if forceLatestTLSVersion { if forceLatestTLSVersion {
log.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2") SystemWideLogger.Println("Force latest TLS mode enabled. Minimum TLS LS version is set to v1.2")
} else { } else {
log.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0") SystemWideLogger.Println("Force latest TLS mode disabled. Minimum TLS version is set to v1.0")
}
listenOnPort80 := false
sysdb.Read("settings", "listenP80", &listenOnPort80)
if listenOnPort80 {
SystemWideLogger.Println("Port 80 listener enabled")
} else {
SystemWideLogger.Println("Port 80 listener disabled")
} }
forceHttpsRedirect := false forceHttpsRedirect := false
sysdb.Read("settings", "redirect", &forceHttpsRedirect) sysdb.Read("settings", "redirect", &forceHttpsRedirect)
if forceHttpsRedirect { if forceHttpsRedirect {
log.Println("Force HTTPS mode enabled") SystemWideLogger.Println("Force HTTPS mode enabled")
//Port 80 listener must be enabled to perform http -> https redirect
listenOnPort80 = true
} else { } else {
log.Println("Force HTTPS mode disabled") SystemWideLogger.Println("Force HTTPS mode disabled")
} }
dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{ dprouter, err := dynamicproxy.NewDynamicProxy(dynamicproxy.RouterOption{
@ -59,6 +68,7 @@ func ReverseProxtInit() {
Port: inboundPort, Port: inboundPort,
UseTls: useTls, UseTls: useTls,
ForceTLSLatest: forceLatestTLSVersion, ForceTLSLatest: forceLatestTLSVersion,
ListenOnPort80: listenOnPort80,
ForceHttpsRedirect: forceHttpsRedirect, ForceHttpsRedirect: forceHttpsRedirect,
TlsManager: tlsCertManager, TlsManager: tlsCertManager,
RedirectRuleTable: redirectTable, RedirectRuleTable: redirectTable,
@ -67,7 +77,7 @@ func ReverseProxtInit() {
WebDirectory: *staticWebServerRoot, WebDirectory: *staticWebServerRoot,
}) })
if err != nil { if err != nil {
log.Println(err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Unable to create dynamic proxy router", err)
return return
} }
@ -78,7 +88,7 @@ func ReverseProxtInit() {
for _, conf := range confs { for _, conf := range confs {
record, err := LoadReverseProxyConfig(conf) record, err := LoadReverseProxyConfig(conf)
if err != nil { if err != nil {
log.Println("Failed to load "+filepath.Base(conf), err.Error()) SystemWideLogger.PrintAndLog("Proxy", "Failed to load config file: "+filepath.Base(conf), err)
return return
} }
@ -92,6 +102,7 @@ func ReverseProxtInit() {
MatchingDomain: record.Rootname, MatchingDomain: record.Rootname,
Domain: record.ProxyTarget, Domain: record.ProxyTarget,
RequireTLS: record.UseTLS, RequireTLS: record.UseTLS,
BypassGlobalTLS: record.BypassGlobalTLS,
SkipCertValidations: record.SkipTlsValidation, SkipCertValidations: record.SkipTlsValidation,
RequireBasicAuth: record.RequireBasicAuth, RequireBasicAuth: record.RequireBasicAuth,
BasicAuthCredentials: record.BasicAuthCredentials, BasicAuthCredentials: record.BasicAuthCredentials,
@ -102,13 +113,14 @@ func ReverseProxtInit() {
RootName: record.Rootname, RootName: record.Rootname,
Domain: record.ProxyTarget, Domain: record.ProxyTarget,
RequireTLS: record.UseTLS, RequireTLS: record.UseTLS,
BypassGlobalTLS: record.BypassGlobalTLS,
SkipCertValidations: record.SkipTlsValidation, SkipCertValidations: record.SkipTlsValidation,
RequireBasicAuth: record.RequireBasicAuth, RequireBasicAuth: record.RequireBasicAuth,
BasicAuthCredentials: record.BasicAuthCredentials, BasicAuthCredentials: record.BasicAuthCredentials,
BasicAuthExceptionRules: record.BasicAuthExceptionRules, BasicAuthExceptionRules: record.BasicAuthExceptionRules,
}) })
} else { } else {
log.Println("Unsupported endpoint type: " + record.ProxyType + ". Skipping " + filepath.Base(conf)) SystemWideLogger.PrintAndLog("Proxy", "Unsupported endpoint type: "+record.ProxyType+". Skipping "+filepath.Base(conf), nil)
} }
} }
@ -117,7 +129,7 @@ func ReverseProxtInit() {
//reverse proxy server in front of this service //reverse proxy server in front of this service
time.Sleep(300 * time.Millisecond) time.Sleep(300 * time.Millisecond)
dynamicProxyRouter.StartProxyService() dynamicProxyRouter.StartProxyService()
log.Println("Dynamic Reverse Proxy service started") SystemWideLogger.Println("Dynamic Reverse Proxy service started")
//Add all proxy services to uptime monitor //Add all proxy services to uptime monitor
//Create a uptime monitor service //Create a uptime monitor service
@ -128,7 +140,7 @@ func ReverseProxtInit() {
Interval: 300, //5 minutes Interval: 300, //5 minutes
MaxRecordsStore: 288, //1 day MaxRecordsStore: 288, //1 day
}) })
log.Println("Uptime Monitor background service started") SystemWideLogger.Println("Uptime Monitor background service started")
}() }()
} }
@ -180,6 +192,13 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
useTLS := (tls == "true") useTLS := (tls == "true")
bypassGlobalTLS, _ := utils.PostPara(r, "bypassGlobalTLS")
if bypassGlobalTLS == "" {
bypassGlobalTLS = "false"
}
useBypassGlobalTLS := bypassGlobalTLS == "true"
stv, _ := utils.PostPara(r, "tlsval") stv, _ := utils.PostPara(r, "tlsval")
if stv == "" { if stv == "" {
stv = "false" stv = "false"
@ -240,6 +259,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
RootName: vdir, RootName: vdir,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -257,6 +277,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
MatchingDomain: subdomain, MatchingDomain: subdomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -281,6 +302,7 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) {
Rootname: rootname, Rootname: rootname,
ProxyTarget: endpoint, ProxyTarget: endpoint,
UseTLS: useTLS, UseTLS: useTLS,
BypassGlobalTLS: useBypassGlobalTLS,
SkipTlsValidation: skipTlsValidation, SkipTlsValidation: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: basicAuthCredentials, BasicAuthCredentials: basicAuthCredentials,
@ -332,9 +354,15 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
if stv == "" { if stv == "" {
stv = "false" stv = "false"
} }
skipTlsValidation := (stv == "true") skipTlsValidation := (stv == "true")
//Load bypass TLS option
bpgtls, _ := utils.PostPara(r, "bpgtls")
if bpgtls == "" {
bpgtls = "false"
}
bypassGlobalTLS := (bpgtls == "true")
rba, _ := utils.PostPara(r, "bauth") rba, _ := utils.PostPara(r, "bauth")
if rba == "" { if rba == "" {
rba = "false" rba = "false"
@ -354,6 +382,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
RootName: targetProxyEntry.RootOrMatchingDomain, RootName: targetProxyEntry.RootOrMatchingDomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: false,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
@ -366,6 +395,7 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
MatchingDomain: targetProxyEntry.RootOrMatchingDomain, MatchingDomain: targetProxyEntry.RootOrMatchingDomain,
Domain: endpoint, Domain: endpoint,
RequireTLS: useTLS, RequireTLS: useTLS,
BypassGlobalTLS: bypassGlobalTLS,
SkipCertValidations: skipTlsValidation, SkipCertValidations: skipTlsValidation,
RequireBasicAuth: requireBasicAuth, RequireBasicAuth: requireBasicAuth,
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
@ -385,6 +415,10 @@ func ReverseProxyHandleEditEndpoint(w http.ResponseWriter, r *http.Request) {
BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials, BasicAuthCredentials: targetProxyEntry.BasicAuthCredentials,
} }
SaveReverseProxyConfigToFile(&thisProxyConfigRecord) SaveReverseProxyConfigToFile(&thisProxyConfigRecord)
//Update uptime monitor
UpdateUptimeMonitorTargets()
utils.SendOK(w) utils.SendOK(w)
} }
@ -417,6 +451,9 @@ func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) {
uptimeMonitor.CleanRecords() uptimeMonitor.CleanRecords()
} }
//Update uptime monitor
UpdateUptimeMonitorTargets()
utils.SendOK(w) utils.SendOK(w)
} }
@ -731,6 +768,35 @@ func ReverseProxyList(w http.ResponseWriter, r *http.Request) {
} }
} }
// Handle port 80 incoming traffics
func HandleUpdatePort80Listener(w http.ResponseWriter, r *http.Request) {
enabled, err := utils.GetPara(r, "enable")
if err != nil {
//Load the current status
currentEnabled := false
err = sysdb.Read("settings", "listenP80", &currentEnabled)
if err != nil {
utils.SendErrorResponse(w, err.Error())
return
}
js, _ := json.Marshal(currentEnabled)
utils.SendJSONResponse(w, string(js))
} else {
if enabled == "true" {
sysdb.Write("settings", "listenP80", true)
SystemWideLogger.Println("Enabling port 80 listener")
dynamicProxyRouter.UpdatePort80ListenerState(true)
} else if enabled == "false" {
sysdb.Write("settings", "listenP80", false)
SystemWideLogger.Println("Disabling port 80 listener")
dynamicProxyRouter.UpdatePort80ListenerState(true)
} else {
utils.SendErrorResponse(w, "invalid mode given: "+enabled)
}
utils.SendOK(w)
}
}
// Handle https redirect // Handle https redirect
func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) { func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
useRedirect, err := utils.GetPara(r, "set") useRedirect, err := utils.GetPara(r, "set")
@ -751,11 +817,11 @@ func HandleUpdateHttpsRedirect(w http.ResponseWriter, r *http.Request) {
} }
if useRedirect == "true" { if useRedirect == "true" {
sysdb.Write("settings", "redirect", true) sysdb.Write("settings", "redirect", true)
log.Println("Updating force HTTPS redirection to true") SystemWideLogger.Println("Updating force HTTPS redirection to true")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(true)
} else if useRedirect == "false" { } else if useRedirect == "false" {
sysdb.Write("settings", "redirect", false) sysdb.Write("settings", "redirect", false)
log.Println("Updating force HTTPS redirection to false") SystemWideLogger.Println("Updating force HTTPS redirection to false")
dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false) dynamicProxyRouter.UpdateHttpToHttpsRedirectSetting(false)
} }

View File

@ -14,6 +14,7 @@ import (
"imuslab.com/zoraxy/mod/dynamicproxy/redirection" "imuslab.com/zoraxy/mod/dynamicproxy/redirection"
"imuslab.com/zoraxy/mod/ganserv" "imuslab.com/zoraxy/mod/ganserv"
"imuslab.com/zoraxy/mod/geodb" "imuslab.com/zoraxy/mod/geodb"
"imuslab.com/zoraxy/mod/info/logger"
"imuslab.com/zoraxy/mod/mdns" "imuslab.com/zoraxy/mod/mdns"
"imuslab.com/zoraxy/mod/netstat" "imuslab.com/zoraxy/mod/netstat"
"imuslab.com/zoraxy/mod/pathrule" "imuslab.com/zoraxy/mod/pathrule"
@ -93,10 +94,17 @@ func startupSequence() {
panic(err) panic(err)
} }
//Create a system wide logger
l, err := logger.NewLogger("zr", "./log", *logOutputToFile)
if err == nil {
SystemWideLogger = l
} else {
panic(err)
}
//Create a netstat buffer //Create a netstat buffer
netstatBuffers, err = netstat.NewNetStatBuffer(300) netstatBuffers, err = netstat.NewNetStatBuffer(300)
if err != nil { if err != nil {
log.Println("Failed to load network statistic info") SystemWideLogger.PrintAndLog("Network", "Failed to load network statistic info", err)
panic(err) panic(err)
} }
@ -134,13 +142,13 @@ func startupSequence() {
BuildVersion: version, BuildVersion: version,
}, "") }, "")
if err != nil { if err != nil {
log.Println("Unable to startup mDNS service. Disabling mDNS services") SystemWideLogger.Println("Unable to startup mDNS service. Disabling mDNS services")
} else { } else {
//Start initial scanning //Start initial scanning
go func() { go func() {
hosts := mdnsScanner.Scan(30, "") hosts := mdnsScanner.Scan(30, "")
previousmdnsScanResults = hosts previousmdnsScanResults = hosts
log.Println("mDNS Startup scan completed") SystemWideLogger.Println("mDNS Startup scan completed")
}() }()
//Create a ticker to update mDNS results every 5 minutes //Create a ticker to update mDNS results every 5 minutes
@ -154,7 +162,7 @@ func startupSequence() {
case <-ticker.C: case <-ticker.C:
hosts := mdnsScanner.Scan(30, "") hosts := mdnsScanner.Scan(30, "")
previousmdnsScanResults = hosts previousmdnsScanResults = hosts
log.Println("mDNS scan result updated") SystemWideLogger.Println("mDNS scan result updated")
} }
} }
}() }()
@ -171,7 +179,7 @@ func startupSequence() {
if usingZtAuthToken == "" { if usingZtAuthToken == "" {
usingZtAuthToken, err = ganserv.TryLoadorAskUserForAuthkey() usingZtAuthToken, err = ganserv.TryLoadorAskUserForAuthkey()
if err != nil { if err != nil {
log.Println("Failed to load ZeroTier controller API authtoken") SystemWideLogger.Println("Failed to load ZeroTier controller API authtoken")
} }
} }
ganManager = ganserv.NewNetworkManager(&ganserv.NetworkManagerOptions{ ganManager = ganserv.NewNetworkManager(&ganserv.NetworkManagerOptions{
@ -220,7 +228,7 @@ func startupSequence() {
staticWebServer = webserv.NewWebServer(&webserv.WebServerOptions{ staticWebServer = webserv.NewWebServer(&webserv.WebServerOptions{
Sysdb: sysdb, Sysdb: sysdb,
Port: "8081", //Default Port Port: "5487", //Default Port
WebRoot: *staticWebServerRoot, WebRoot: *staticWebServerRoot,
EnableDirectoryListing: true, EnableDirectoryListing: true,
EnableWebDirManager: *allowWebFileManager, EnableWebDirManager: *allowWebFileManager,

View File

@ -75,13 +75,13 @@
$("#rootReqTLS").parent().addClass("disabled"); $("#rootReqTLS").parent().addClass("disabled");
//Check if web server is enabled. If not, ask if the user want to enable it //Check if web server is enabled. If not, ask if the user want to enable it
if (!$("#webserv_enable").parent().checkbox("is checked")){ /*if (!$("#webserv_enable").parent().checkbox("is checked")){
confirmBox("Enable static web server now?", function(choice){ confirmBox("Enable static web server now?", function(choice){
if (choice == true){ if (choice == true){
$("#webserv_enable").parent().checkbox("set checked"); $("#webserv_enable").parent().checkbox("set checked");
} }
}); });
} }*/
}else{ }else{
$("#rootReqTLS").parent().removeClass("disabled"); $("#rootReqTLS").parent().removeClass("disabled");
$("#proxyRoot").parent().removeClass("disabled"); $("#proxyRoot").parent().removeClass("disabled");
@ -89,7 +89,7 @@
} }
} }
function initRootInfo(){ function initRootInfo(callback=undefined){
$.get("/api/proxy/list?type=root", function(data){ $.get("/api/proxy/list?type=root", function(data){
if (data == null){ if (data == null){
@ -97,10 +97,39 @@
$("#proxyRoot").val(data.Domain); $("#proxyRoot").val(data.Domain);
checkRootRequireTLS(data.Domain); checkRootRequireTLS(data.Domain);
} }
if (callback != undefined){
callback();
}
});
}
initRootInfo(function(){
updateWebServerLinkSettings();
});
//Update the current web server port settings
function updateWebServerLinkSettings(){
isUsingStaticWebServerAsRoot(function(isUsingWebServ){
if (isUsingWebServ){
$(".webservRootDisabled").addClass("disabled");
$("#useStaticWebServer").parent().checkbox("set checked");
}else{
$(".webservRootDisabled").removeClass("disabled");
$("#useStaticWebServer").parent().checkbox("set unchecked");
}
})
}
function isUsingStaticWebServerAsRoot(callback){
let currentProxyRoot = $("#proxyRoot").val().trim();
$.get("/api/webserv/status", function(webservStatus){
if (currentProxyRoot == "127.0.0.1:" + webservStatus.ListeningPort || currentProxyRoot == "localhost:" + webservStatus.ListeningPort){
return callback(true);
}
return callback(false);
}); });
} }
initRootInfo();
function updateRootSettingStates(){ function updateRootSettingStates(){
$.get("/api/cert/tls", function(data){ $.get("/api/cert/tls", function(data){
@ -111,6 +140,7 @@
} }
}); });
} }
//Bind event to tab switch //Bind event to tab switch
tabSwitchEventBind["setroot"] = function(){ tabSwitchEventBind["setroot"] = function(){
//On switch over to this page, update root info //On switch over to this page, update root info
@ -137,11 +167,12 @@
let useRedirect = $("#unsetRedirect")[0].checked; let useRedirect = $("#unsetRedirect")[0].checked;
updateRedirectionDomainSettingInputBox(useRedirect); updateRedirectionDomainSettingInputBox(useRedirect);
}); });
}) });
} }
checkCustomRedirectForUnsetSubd(); checkCustomRedirectForUnsetSubd();
//Check if the given domain will redirect to https
function checkRootRequireTLS(targetDomain){ function checkRootRequireTLS(targetDomain){
//Trim off the http or https from the origin //Trim off the http or https from the origin
if (targetDomain.startsWith("http://")){ if (targetDomain.startsWith("http://")){
@ -168,7 +199,7 @@
}) })
} }
//Set the new proxy root option
function setProxyRoot(){ function setProxyRoot(){
var newpr = $("#proxyRoot").val(); var newpr = $("#proxyRoot").val();
if (newpr.trim() == ""){ if (newpr.trim() == ""){
@ -189,8 +220,24 @@
msgbox(data.error, false, 5000); msgbox(data.error, false, 5000);
}else{ }else{
//OK //OK
initRootInfo(); initRootInfo(function(){
msgbox("Proxy Root Updated") //Check if WebServ is enabled
isUsingStaticWebServerAsRoot(function(isUsingWebServ){
if (isUsingWebServ){
//Force enable static web server
//See webserv.html for details
setWebServerRunningState(true);
}
setTimeout(function(){
//Update the checkbox
updateWebServerLinkSettings();
msgbox("Proxy Root Updated");
}, 1000);
})
});
} }
} }
}); });

View File

@ -8,7 +8,7 @@
<div class="field"> <div class="field">
<label>Proxy Type</label> <label>Proxy Type</label>
<div class="ui selection dropdown"> <div class="ui selection dropdown">
<input type="hidden" id="ptype" value="subd"> <input type="hidden" id="ptype" value="subd" onchange="handleProxyTypeOptionChange(this.value)">
<i class="dropdown icon"></i> <i class="dropdown icon"></i>
<div class="default text">Proxy Type</div> <div class="default text">Proxy Type</div>
<div class="menu"> <div class="menu">
@ -22,7 +22,7 @@
<input type="text" id="rootname" placeholder="s1.mydomain.com"> <input type="text" id="rootname" placeholder="s1.mydomain.com">
</div> </div>
<div class="field"> <div class="field">
<label>IP Address or Domain Name with port</label> <label>Target IP Address or Domain Name with port</label>
<input type="text" id="proxyDomain" onchange="autoCheckTls(this.value);"> <input type="text" id="proxyDomain" onchange="autoCheckTls(this.value);">
<small>E.g. 192.168.0.101:8000 or example.com</small> <small>E.g. 192.168.0.101:8000 or example.com</small>
</div> </div>
@ -44,7 +44,13 @@
<div class="field"> <div class="field">
<div class="ui checkbox"> <div class="ui checkbox">
<input type="checkbox" id="skipTLSValidation"> <input type="checkbox" id="skipTLSValidation">
<label>Ignore TLS/SSL Verification Error<br><small>E.g. self-signed, expired certificate (Not Recommended)</small></label> <label>Ignore TLS/SSL Verification Error<br><small>For targets that is using self-signed, expired certificate (Not Recommended)</small></label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input type="checkbox" id="bypassGlobalTLS">
<label>Allow plain HTTP access<br><small>Allow this subdomain to be connected without TLS (Require HTTP server enabled on port 80)</small></label>
</div> </div>
</div> </div>
<div class="field"> <div class="field">
@ -123,6 +129,7 @@
var proxyDomain = $("#proxyDomain").val(); var proxyDomain = $("#proxyDomain").val();
var useTLS = $("#reqTls")[0].checked; var useTLS = $("#reqTls")[0].checked;
var skipTLSValidation = $("#skipTLSValidation")[0].checked; var skipTLSValidation = $("#skipTLSValidation")[0].checked;
var bypassGlobalTLS = $("#bypassGlobalTLS")[0].checked;
var requireBasicAuth = $("#requireBasicAuth")[0].checked; var requireBasicAuth = $("#requireBasicAuth")[0].checked;
if (type === "vdir") { if (type === "vdir") {
@ -162,6 +169,7 @@
tls: useTLS, tls: useTLS,
ep: proxyDomain, ep: proxyDomain,
tlsval: skipTLSValidation, tlsval: skipTLSValidation,
bypassGlobalTLS: bypassGlobalTLS,
bauth: requireBasicAuth, bauth: requireBasicAuth,
cred: JSON.stringify(credentials), cred: JSON.stringify(credentials),
}, },
@ -206,6 +214,14 @@
} }
function handleProxyTypeOptionChange(newType){
if (newType == "subd"){
$("#bypassGlobalTLS").parent().removeClass("disabled");
}else if (newType == "vdir"){
$("#bypassGlobalTLS").parent().addClass("disabled");
}
}
//Generic functions for delete rp endpoints //Generic functions for delete rp endpoints
function deleteEndpoint(ptype, epoint){ function deleteEndpoint(ptype, epoint){
if (confirm("Confirm remove proxy for :" + epoint + " (type: " + ptype + ")?")){ if (confirm("Confirm remove proxy for :" + epoint + " (type: " + ptype + ")?")){
@ -331,7 +347,7 @@
var columns = row.find('td[data-label]'); var columns = row.find('td[data-label]');
var payload = $(row).attr("payload"); var payload = $(row).attr("payload");
payload = JSON.parse(decodeURIComponent(payload)); payload = JSON.parse(decodeURIComponent(payload));
console.log(payload);
//console.log(payload); //console.log(payload);
columns.each(function(index) { columns.each(function(index) {
var column = $(this); var column = $(this);
@ -347,34 +363,37 @@
var datatype = $(this).attr("datatype"); var datatype = $(this).attr("datatype");
if (datatype == "domain"){ if (datatype == "domain"){
let domain = payload.Domain; let domain = payload.Domain;
//Target require TLS for proxying
let tls = payload.RequireTLS; let tls = payload.RequireTLS;
if (tls){ if (tls){
tls = "checked"; tls = "checked";
}else{ }else{
tls = ""; tls = "";
} }
//Require TLS validation
let skipTLSValidation = payload.SkipCertValidations;
let checkstate = "";
if (skipTLSValidation){
checkstate = "checked";
}
input = ` input = `
<div class="ui mini fluid input"> <div class="ui mini fluid input">
<input type="text" class="Domain" value="${domain}"> <input type="text" class="Domain" value="${domain}">
</div> </div>
<div class="ui checkbox" style="margin-top: 0.4em;"> <div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="RequireTLS" ${tls}> <input type="checkbox" class="RequireTLS" ${tls}>
<label>Require TLS</label> <label>Require TLS<br>
<small>Proxy target require HTTPS connection</small></label>
</div><br>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="SkipCertValidations" ${checkstate}>
<label>Skip Verification<br>
<small>Check this if proxy target is using self signed certificates</small></label>
</div> </div>
`; `;
column.empty().append(input); column.empty().append(input);
}else if (datatype == "skipver"){
let skipTLSValidation = payload.SkipCertValidations;
let checkstate = "";
if (skipTLSValidation){
checkstate = "checked";
}
column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="SkipCertValidations" ${checkstate}>
<label>Skip Verification</label>
<small>Check this if you are using self signed certificates</small>
</div>`);
}else if (datatype == "basicauth"){ }else if (datatype == "basicauth"){
let requireBasicAuth = payload.RequireBasicAuth; let requireBasicAuth = payload.RequireBasicAuth;
let checkstate = ""; let checkstate = "";
@ -392,6 +411,16 @@
<button title="Cancel" onclick="exitProxyInlineEdit('${endpointType}');" class="ui basic small circular icon button"><i class="ui remove icon"></i></button> <button title="Cancel" onclick="exitProxyInlineEdit('${endpointType}');" class="ui basic small circular icon button"><i class="ui remove icon"></i></button>
<button title="Save" onclick="saveProxyInlineEdit('${uuid}');" class="ui basic small circular icon button"><i class="ui green save icon"></i></button> <button title="Save" onclick="saveProxyInlineEdit('${uuid}');" class="ui basic small circular icon button"><i class="ui green save icon"></i></button>
`); `);
}else if (datatype == "inbound" && payload.ProxyType == 0){
let originalContent = $(column).html();
column.empty().append(`${originalContent}
<div class="ui divider"></div>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="BypassGlobalTLS" ${payload.BypassGlobalTLS?"checked":""}>
<label>Allow plain HTTP access<br>
<small>Allow inbound connections without TLS/SSL</small></label>
</div><br>
`);
}else{ }else{
//Unknown field. Leave it untouched //Unknown field. Leave it untouched
} }
@ -423,6 +452,7 @@
let requireTLS = $(row).find(".RequireTLS")[0].checked; let requireTLS = $(row).find(".RequireTLS")[0].checked;
let skipCertValidations = $(row).find(".SkipCertValidations")[0].checked; let skipCertValidations = $(row).find(".SkipCertValidations")[0].checked;
let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked; let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked;
let bypassGlobalTLS = $(row).find(".BypassGlobalTLS")[0].checked;
console.log(newDomain, requireTLS, skipCertValidations, requireBasicAuth) console.log(newDomain, requireTLS, skipCertValidations, requireBasicAuth)
@ -433,6 +463,7 @@
"type": epttype, "type": epttype,
"rootname": uuid, "rootname": uuid,
"ep":newDomain, "ep":newDomain,
"bpgtls": bypassGlobalTLS,
"tls" :requireTLS, "tls" :requireTLS,
"tlsval": skipCertValidations, "tlsval": skipCertValidations,
"bauth" :requireBasicAuth, "bauth" :requireBasicAuth,

View File

@ -72,10 +72,15 @@
<label>Use TLS to serve proxy request</label> <label>Use TLS to serve proxy request</label>
</div> </div>
<br> <br>
<div id="redirect" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em;"> <div id="listenP80" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em;" >
<input type="checkbox"> <input type="checkbox">
<label>Force redirect HTTP request to HTTPS<br> <label>Enable HTTP server on port 80<br>
<small>(Only apply when listening port is not 80)</small></label> <small>(Only apply when TLS enabled and not using port 80)</small></label>
</div>
<br>
<div id="redirect" class="ui toggle notloopbackOnly tlsEnabledOnly checkbox" style="margin-top: 0.6em; padding-left: 2em;">
<input type="checkbox">
<label>Force redirect HTTP request to HTTPS</label>
</div> </div>
<div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;"> <div class="ui basic segment" style="background-color: #f7f7f7; border-radius: 1em;">
<div class="ui accordion advanceSettings"> <div class="ui accordion advanceSettings">
@ -181,6 +186,7 @@
$("#serverstatus").removeClass("green"); $("#serverstatus").removeClass("green");
} }
$("#incomingPort").val(data.Option.Port); $("#incomingPort").val(data.Option.Port);
}); });
} }
@ -305,6 +311,27 @@
}); });
} }
function handleP80ListenerStateChange(enabled){
$.ajax({
url: "/api/proxy/listenPort80",
data: {"enable": enabled},
success: function(data){
if (data.error != undefined){
console.log(data.error);
return;
}
if (enabled){
$("#redirect").show();
msgbox("Port 80 listener enabled");
}else{
$("#redirect").hide();
msgbox("Port 80 listener disabled");
}
}
});
}
function handlePortChange(){ function handlePortChange(){
var newPortValue = $("#incomingPort").val(); var newPortValue = $("#incomingPort").val();
@ -323,6 +350,25 @@
}); });
} }
function initPort80ListenerSetting(){
$.get("/api/proxy/listenPort80", function(data){
if (data){
$("#listenP80").checkbox("set checked");
$("#redirect").show();
}else{
$("#listenP80").checkbox("set unchecked");
$("#redirect").hide();
}
$("#listenP80").find("input").on("change", function(){
let enabled = $(this)[0].checked;
handleP80ListenerStateChange(enabled);
})
});
}
initPort80ListenerSetting();
function initHTTPtoHTTPSRedirectSetting(){ function initHTTPtoHTTPSRedirectSetting(){
$.get("/api/proxy/useHttpsRedirect", function(data){ $.get("/api/proxy/useHttpsRedirect", function(data){
if (data == true){ if (data == true){
@ -356,8 +402,6 @@
}) })
}); });
}); });
} }
initHTTPtoHTTPSRedirectSetting(); initHTTPtoHTTPSRedirectSetting();

View File

@ -9,7 +9,6 @@
<tr> <tr>
<th>Matching Domain</th> <th>Matching Domain</th>
<th>Proxy To</th> <th>Proxy To</th>
<th>TLS/SSL Verification</th>
<th>Basic Auth</th> <th>Basic Auth</th>
<th class="no-sort" style="min-width: 7.2em;">Actions</th> <th class="no-sort" style="min-width: 7.2em;">Actions</th>
</tr> </tr>
@ -41,19 +40,14 @@
let subdData = encodeURIComponent(JSON.stringify(subd)); let subdData = encodeURIComponent(JSON.stringify(subd));
if (subd.RequireTLS){ if (subd.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`; tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
} if (subd.SkipCertValidations){
tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
let tlsVerificationField = ""; }
if (subd.RequireTLS){
tlsVerificationField = !subd.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`
}else{
tlsVerificationField = "N/A"
} }
$("#subdList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry"> $("#subdList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry">
<td data-label="" editable="false"><a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a></td> <td data-label="" editable="true" datatype="inbound"><a href="//${subd.RootOrMatchingDomain}" target="_blank">${subd.RootOrMatchingDomain}</a></td>
<td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td> <td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${tlsVerificationField}</td>
<td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td> <td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label=""> <td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button> <button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button>

View File

@ -86,7 +86,7 @@
let id = value[0].ID; let id = value[0].ID;
let name = value[0].Name; let name = value[0].Name;
let url = value[0].URL; let url = value[value.length - 1].URL;
let protocol = value[0].Protocol; let protocol = value[0].Protocol;
//Generate the status dot //Generate the status dot
@ -112,6 +112,9 @@
if (thisStatus.StatusCode >= 500 && thisStatus.StatusCode < 600){ if (thisStatus.StatusCode >= 500 && thisStatus.StatusCode < 600){
//Special type of error, cause by downstream reverse proxy //Special type of error, cause by downstream reverse proxy
dotType = "error"; dotType = "error";
}else if (thisStatus.StatusCode == 401){
//Unauthorized error
dotType = "error";
}else{ }else{
dotType = "offline"; dotType = "offline";
} }
@ -141,6 +144,28 @@
currentOnlineStatus = `<i class="exclamation circle icon"></i> Misconfigured`; currentOnlineStatus = `<i class="exclamation circle icon"></i> Misconfigured`;
onlineStatusCss = `color: #f38020;`; onlineStatusCss = `color: #f38020;`;
reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is online with misconfigured settings</small>`; reminderEle = `<small style="${onlineStatusCss}">Downstream proxy server is online with misconfigured settings</small>`;
}else if (value[value.length - 1].StatusCode >= 400 && value[value.length - 1].StatusCode <= 405){
switch(value[value.length - 1].StatusCode){
case 400:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Bad Request`;
break;
case 401:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Unauthorized`;
break;
case 403:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Forbidden`;
break;
case 404:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Not Found`;
break;
case 405:
currentOnlineStatus = `<i class="exclamation circle icon"></i> Method Not Allowed`;
break;
}
onlineStatusCss = `color: #f38020;`;
reminderEle = `<small style="${onlineStatusCss}">Target online but not accessible</small>`;
}else{ }else{
currentOnlineStatus = `<i class="circle icon"></i> Offline`; currentOnlineStatus = `<i class="circle icon"></i> Offline`;
onlineStatusCss = `color: #df484a;`; onlineStatusCss = `color: #df484a;`;

View File

@ -9,7 +9,6 @@
<tr> <tr>
<th>Virtual Directory</th> <th>Virtual Directory</th>
<th>Proxy To</th> <th>Proxy To</th>
<th>TLS/SSL Verification</th>
<th>Basic Auth</th> <th>Basic Auth</th>
<th class="no-sort" style="min-width: 7.2em;">Actions</th> <th class="no-sort" style="min-width: 7.2em;">Actions</th>
</tr> </tr>
@ -43,6 +42,9 @@
let vdirData = encodeURIComponent(JSON.stringify(vdir)); let vdirData = encodeURIComponent(JSON.stringify(vdir));
if (vdir.RequireTLS){ if (vdir.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`; tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
if (vdir.SkipCertValidations){
tlsIcon = `<i class="yellow lock icon" title="TLS/SSL mode without verification"></i>`
}
} }
let tlsVerificationField = ""; let tlsVerificationField = "";
@ -55,7 +57,6 @@
$("#vdirList").append(`<tr eptuuid="${vdir.RootOrMatchingDomain}" payload="${vdirData}" class="vdirEntry"> $("#vdirList").append(`<tr eptuuid="${vdir.RootOrMatchingDomain}" payload="${vdirData}" class="vdirEntry">
<td data-label="" editable="false">${vdir.RootOrMatchingDomain}</td> <td data-label="" editable="false">${vdir.RootOrMatchingDomain}</td>
<td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td> <td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${tlsVerificationField}</td>
<td data-label="" editable="true" datatype="basicauth">${vdir.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td> <td data-label="" editable="true" datatype="basicauth">${vdir.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label=""> <td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button> <button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button>

View File

@ -17,7 +17,7 @@
<h3>Web Server Settings</h3> <h3>Web Server Settings</h3>
<div class="ui form"> <div class="ui form">
<div class="inline field"> <div class="inline field">
<div class="ui toggle checkbox"> <div class="ui toggle checkbox webservRootDisabled">
<input id="webserv_enable" type="checkbox" class="hidden"> <input id="webserv_enable" type="checkbox" class="hidden">
<label>Enable Static Web Server</label> <label>Enable Static Web Server</label>
</div> </div>
@ -37,7 +37,7 @@
See the -webserv flag for more details. See the -webserv flag for more details.
</small> </small>
</div> </div>
<div class="field"> <div class="field webservRootDisabled">
<label>Port Number</label> <label>Port Number</label>
<input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);"> <input id="webserv_listenPort" type="number" step="1" min="0" max="65535" value="8081" onchange="updateWebServLinkExample(this.value);">
<small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small> <small>Use <code>http://127.0.0.1:<span class="webserv_port">8081</span></code> in proxy rules to access the web server</small>

View File

@ -39,7 +39,7 @@
<h3 style="margin-top: 1em;">403 - Forbidden</h3> <h3 style="margin-top: 1em;">403 - Forbidden</h3>
<div class="ui divider"></div> <div class="ui divider"></div>
<p>You do not have permission to view this directory or page. <br> <p>You do not have permission to view this directory or page. <br>
This might cause by the region limit setting of this site.</p> This might be caused by the region limit setting of this site.</p>
<div class="ui divider"></div> <div class="ui divider"></div>
<div style="text-align: left;"> <div style="text-align: left;">
<small>Request time: <span id="reqtime"></span></small><br> <small>Request time: <span id="reqtime"></span></small><br>

View File

@ -50,7 +50,7 @@
</a> </a>
<div class="ui divider menudivider">Access & Connections</div> <div class="ui divider menudivider">Access & Connections</div>
<a class="item" tag="cert"> <a class="item" tag="cert">
<i class="simplistic lock icon"></i> TLS / SSL certificate <i class="simplistic lock icon"></i> TLS / SSL certificates
</a> </a>
<a class="item" tag="redirectset"> <a class="item" tag="redirectset">
<i class="simplistic level up alternate icon"></i> Redirection <i class="simplistic level up alternate icon"></i> Redirection
@ -150,14 +150,13 @@
<br><br> <br><br>
<div class="ui divider"></div> <div class="ui divider"></div>
<div class="ui container" style="color: grey; font-size: 90%"> <div class="ui container" style="color: grey; font-size: 90%">
<p>CopyRight Zoraxy project and its author, 2022 - <span class="year"></span></p> <p>CopyRight Zoraxy Project and its authors © 2021 - <span class="year"></span></p>
</div> </div>
<div id="messageBox" class="ui green floating big compact message"> <div id="messageBox" class="ui green floating big compact message">
<p><i class="green check circle icon"></i> There are no message</p> <p><i class="green check circle icon"></i> There are no messages</p>
</div> </div>
<div id="confirmBox" style="display:none;"> <div id="confirmBox" style="display:none;">
<div class="ui top attached progress"> <div class="ui top attached progress">
<div class="bar" style="width: 100%; min-width: 0px;"></div> <div class="bar" style="width: 100%; min-width: 0px;"></div>
@ -351,7 +350,7 @@
$("#confirmBox").hide(); $("#confirmBox").hide();
//Unset the event listener //Unset the event listener
$("#confirmBox .ui.red.button").off("click"); $("#confirmBox .ui.red.button").off("click");
}); });
// Show the confirm box // Show the confirm box

View File

@ -119,7 +119,7 @@
<h2 class="diagramHeader">Host</h2> <h2 class="diagramHeader">Host</h2>
<p style="font-weight: 500; color: #bd2426;">Error</p> <p style="font-weight: 500; color: #bd2426;">Error</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div> <div>
@ -140,7 +140,7 @@
<div class="item">Visit the Reverse Proxy management interface to correct any setting errors</div> <div class="item">Visit the Reverse Proxy management interface to correct any setting errors</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<br> <br>
</div> </div>

View File

@ -19,7 +19,6 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -104,7 +103,21 @@ func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) {
/* /*
Up Time Monitor Up Time Monitor
*/ */
//Generate uptime monitor targets from reverse proxy rules
// Update uptime monitor targets after rules updated
// See https://github.com/tobychui/zoraxy/issues/77
func UpdateUptimeMonitorTargets() {
if uptimeMonitor != nil {
uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter)
go func() {
uptimeMonitor.ExecuteUptimeCheck()
}()
SystemWideLogger.PrintAndLog("Uptime", "Uptime monitor config updated", nil)
}
}
// Generate uptime monitor targets from reverse proxy rules
func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target { func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target {
subds := dp.GetSDProxyEndpointsAsMap() subds := dp.GetSDProxyEndpointsAsMap()
vdirs := dp.GetVDProxyEndpointsAsMap() vdirs := dp.GetVDProxyEndpointsAsMap()
@ -263,7 +276,7 @@ func HandleWakeOnLan(w http.ResponseWriter, r *http.Request) {
return return
} }
log.Println("[WoL] Sending Wake on LAN magic packet to " + wake) SystemWideLogger.PrintAndLog("WoL", "Sending Wake on LAN magic packet to "+wake, nil)
err := wakeonlan.WakeTarget(wake) err := wakeonlan.WakeTarget(wake)
if err != nil { if err != nil {
utils.SendErrorResponse(w, err.Error()) utils.SendErrorResponse(w, err.Error())