diff --git a/src/README.md b/src/README.md index a456db2..520869a 100644 --- a/src/README.md +++ b/src/README.md @@ -1,118 +1,31 @@ -# Zoraxy +# ReverseProxy -General purpose request (reverse) proxy and forwarding tool for low power devices. Now written in Go! +Reverse proxy subservice for ArozOS -### Features -- Simple to use interface with detail in-system instructions -- Reverse Proxy - - - Subdomain Reverse Proxy - - - Virtual Directory Reverse Proxy +### Install -- Redirection Rules +Git clone this inside the subservice folder of ArozOS, build it and start it up in ArozOS subservice menu. -- TLS / SSL setup and deploy +You can also use it separately as a really basic reverse proxy server that server website based on domain / virtual directories. You can also add another load balancer in front of multiple reverse proxy server nodes if it is necessary in your case. -- Blacklist by country or IP address (single IP, CIDR or wildcard for beginners :D) -- (More features work in progress) -## Usage +### Build -Zoraxy provide basic authentication system for standalone mode. To use it in standalone mode, follow the instruction below for your desired deployment platform. +Requirement: Go 1.16 or above -### 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. - -#### Linux - -```bash -//Download the latest zoraxy binary and web.tar.gz from the Release page -sudo chmod 775 ./zoraxy web.tar.gz -sudo ./zoraxy -port=:8000 ``` - -#### Windows - -Download the binary executable and web.tar.gz, put them into the same folder and double click the binary file to start it. - -#### 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. - -#### 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. - -### External Permission Managment 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 no-auth mode, start Zoraxy with the following flag - -```bash -./zoraxy -noauth=true -``` - -*Note: For security reaons, you should only enable no-auth if you are running Zoraxy in a trusted environment or with another authentication management proxy in front.* - -#### 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 - -```bash -# cd into your arozos subservice folder. Sometime it is under ~/arozos/src/subservice cd ~/arozos/subservices -mkdir zoraxy -cd ./zoraxy - -# Download the release binary from Github release -wget {binary executable link from release page} -wget {web.tar.gz link from release page} - -# Set permission. Change this if required -sudo chmod 775 -R ./ - -# Start zoraxy to see if the downloaded arch is correct. If yes, you should -# see it start unzipping -./zoraxy - -# After the unzip done, press Ctrl + C to kill it -# Rename it to valid arozos subservice binary format -mv ./zoraxy zoraxy_linux_amd64 - -# If you are using SBCs with different CPU arch -mv ./zoraxy zoraxy_linux_arm -mv ./zoraxy zoraxy_linux_arm64 - -# Restart arozos -sudo systemctl restart arozos - - +git clone {this_repo} +cd ReverseProxy +./build.sh ``` -To start the module, go to System Settings > Modules > Subservice and enable it in the menu. You should be able to see a new module named "Zoraxy" pop up in the start menu. +To start the module, make sure .disabled file does not exists and start arozos system. You should be able to see a new module named "ReverseProxy" pop up in the start menu. - - -## Build from Source - -*Requirement: Go 1.17 or above* - -```bash -git clone https://github.com/tobychui/zoraxy -cd ./zoraxy/src -go mod tidy -go build - -./zoraxy -``` - - - -### Forward Modes +### Usage #### Proxy Modes @@ -121,8 +34,12 @@ There are two mode in the ReverseProxy Subservice 1. vdir mode (Virtual Dirctories) 2. subd mode (Subdomain Proxying Mode) + + Vdir mode proxy web request based on the virtual directories given in the request URL. For example, when configured to redirect /example to example.com, any visits to {your_domain}/example will be proxied to example.com. + + Subd mode proxy web request based on sub-domain exists in the request URL. For example, when configured to redirect example.localhost to example.com, any visits that includes example.localhost (e.g. example.localhost/page1) will be proxied to example.com (e.g. example.com/page1) #### Root Proxy @@ -131,6 +48,3 @@ Root proxy is the main proxy destination where if all proxy root name did not ma -## License - -To be decided (Currently: All Right Reserved) diff --git a/src/api.go b/src/api.go index 9713e62..06e56f8 100644 --- a/src/api.go +++ b/src/api.go @@ -68,9 +68,10 @@ func initAPIs() { authRouter.HandleFunc("/api/blacklist/ip/remove", handleIpBlacklistRemove) authRouter.HandleFunc("/api/blacklist/enable", handleBlacklistEnable) - //Statistic API + //Statistic & uptime monitoring API authRouter.HandleFunc("/api/stats/summary", statisticCollector.HandleTodayStatLoad) - + authRouter.HandleFunc("/api/stats/countries", HandleCountryDistrSummary) + authRouter.HandleFunc("/api/utm/list", HandleUptimeMonitorListing) //Upnp authRouter.HandleFunc("/api/upnp/discover", handleUpnpDiscover) //If you got APIs to add, append them here diff --git a/src/helpers.go b/src/helpers.go new file mode 100644 index 0000000..2287ecd --- /dev/null +++ b/src/helpers.go @@ -0,0 +1,97 @@ +package main + +import ( + "encoding/json" + "net/http" + + "imuslab.com/zoraxy/mod/dynamicproxy" + "imuslab.com/zoraxy/mod/uptime" + "imuslab.com/zoraxy/mod/utils" +) + +/* + Statistic Summary +*/ +//Handle conversion of statistic daily summary to country summary +func HandleCountryDistrSummary(w http.ResponseWriter, r *http.Request) { + requestClientCountry := map[string]int{} + statisticCollector.DailySummary.RequestClientIp.Range(func(key, value interface{}) bool { + //Get this client country of original + clientIp := key.(string) + //requestCount := value.(int) + + ci, err := geodbStore.ResolveCountryCodeFromIP(clientIp) + if err != nil { + return true + } + + isoCode := ci.CountryIsoCode + if isoCode == "" { + //local or reserved addr + isoCode = "local" + } + uc, ok := requestClientCountry[isoCode] + if !ok { + //Create the counter + requestClientCountry[isoCode] = 1 + } else { + requestClientCountry[isoCode] = uc + 1 + } + return true + }) + + js, _ := json.Marshal(requestClientCountry) + utils.SendJSONResponse(w, string(js)) +} + +/* + Up Time Monitor +*/ +//Generate uptime monitor targets from reverse proxy rules +func GetUptimeTargetsFromReverseProxyRules(dp *dynamicproxy.Router) []*uptime.Target { + subds := dp.GetSDProxyEndpointsAsMap() + vdirs := dp.GetVDProxyEndpointsAsMap() + + UptimeTargets := []*uptime.Target{} + for subd, target := range subds { + url := "http://" + target.Domain + protocol := "http" + if target.RequireTLS { + url = "https://" + target.Domain + protocol = "https" + } + UptimeTargets = append(UptimeTargets, &uptime.Target{ + ID: subd, + Name: subd, + URL: url, + Protocol: protocol, + }) + } + + for vdir, target := range vdirs { + url := "http://" + target.Domain + protocol := "http" + if target.RequireTLS { + url = "https://" + target.Domain + protocol = "https" + } + UptimeTargets = append(UptimeTargets, &uptime.Target{ + ID: vdir, + Name: "*" + vdir, + URL: url, + Protocol: protocol, + }) + } + + return UptimeTargets +} + +//Handle rendering up time monitor data +func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) { + if uptimeMonitor != nil { + uptimeMonitor.HandleUptimeLogRead(w, r) + } else { + http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError) + return + } +} diff --git a/src/main.go b/src/main.go index d4ac5c9..99c409c 100644 --- a/src/main.go +++ b/src/main.go @@ -1,14 +1,12 @@ package main import ( - "errors" "flag" "fmt" "log" "net/http" "os" "os/signal" - "path/filepath" "syscall" "time" @@ -20,7 +18,7 @@ import ( "imuslab.com/zoraxy/mod/statistic" "imuslab.com/zoraxy/mod/tlscert" "imuslab.com/zoraxy/mod/upnp" - "imuslab.com/zoraxy/mod/utils" + "imuslab.com/zoraxy/mod/uptime" ) //General flags @@ -29,16 +27,17 @@ var showver = flag.Bool("version", false, "Show version of this server") var ( name = "Zoraxy" - version = "2.1" + version = "2.11" - handler *aroz.ArozHandler - sysdb *database.Database - authAgent *auth.AuthAgent - tlsCertManager *tlscert.Manager - redirectTable *redirection.RuleTable - geodbStore *geodb.Store - statisticCollector *statistic.Collector - upnpClient *upnp.UPnPClient + handler *aroz.ArozHandler //Handle arozos managed permission system + sysdb *database.Database //System database + authAgent *auth.AuthAgent //Authentication agent + tlsCertManager *tlscert.Manager //TLS / SSL management + redirectTable *redirection.RuleTable //Handle special redirection rule sets + geodbStore *geodb.Store //GeoIP database + statisticCollector *statistic.Collector //Collecting statistic from visitors + upnpClient *upnp.UPnPClient //UPnP Client for poking holes + uptimeMonitor *uptime.Monitor //Uptime monitor service worker ) // Kill signal handler. Do something before the system the core terminate. @@ -63,11 +62,11 @@ func main() { Name: name, Desc: "Dynamic Reverse Proxy Server", Group: "Network", - IconPath: "Zoraxy/img/small_icon.png", + IconPath: "reverseproxy/img/small_icon.png", Version: version, - StartDir: "Zoraxy/index.html", + StartDir: "reverseproxy/index.html", SupportFW: true, - LaunchFWDir: "Zoraxy/index.html", + LaunchFWDir: "reverseproxy/index.html", SupportEmb: false, InitFWSize: []int{1080, 580}, }) @@ -79,9 +78,6 @@ func main() { SetupCloseHandler() - //Check if all required files are here - ValidateSystemFiles() - //Create database db, err := database.NewDatabase("sys.db", false) if err != nil { @@ -127,6 +123,10 @@ func main() { panic(err) } + if err != nil { + panic(err) + } + //Create a upnp client err = initUpnp() if err != nil { @@ -151,34 +151,3 @@ func main() { } } - -//Unzip web.tar.gz if file exists -func ValidateSystemFiles() error { - if !utils.FileExists("./web") || !utils.FileExists("./system") { - //Check if the web.tar.gz exists - if utils.FileExists("./web.tar.gz") { - //Unzip the file - f, err := os.Open("./web.tar.gz") - if err != nil { - return err - } - - err = utils.ExtractTarGzipByStream(filepath.Clean("./"), f, true) - if err != nil { - return err - } - - err = f.Close() - if err != nil { - return err - } - - //Delete the web.tar.gz - os.Remove("./web.tar.gz") - } else { - return errors.New("system files not found") - } - } - return errors.New("system files not found or corrupted") - -} diff --git a/src/reverseproxy.go b/src/reverseproxy.go index 3df14a6..4ff9534 100644 --- a/src/reverseproxy.go +++ b/src/reverseproxy.go @@ -11,6 +11,7 @@ import ( "time" "imuslab.com/zoraxy/mod/dynamicproxy" + "imuslab.com/zoraxy/mod/uptime" "imuslab.com/zoraxy/mod/utils" ) @@ -95,6 +96,18 @@ func ReverseProxtInit() { dynamicProxyRouter.StartProxyService() log.Println("Dynamic Reverse Proxy service started") + //Add all proxy services to uptime monitor + //Create a uptime monitor service + go func() { + //This must be done in go routine to prevent blocking on system startup + uptimeMonitor, _ = uptime.NewUptimeMonitor(&uptime.Config{ + Targets: GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter), + Interval: 300, //5 minutes + MaxRecordsStore: 288, //1 day + }) + log.Println("Uptime Monitor background service started") + }() + } func ReverseProxyHandleOnOff(w http.ResponseWriter, r *http.Request) { @@ -178,6 +191,12 @@ func ReverseProxyHandleAddEndpoint(w http.ResponseWriter, r *http.Request) { //Save it SaveReverseProxyConfig(eptype, rootname, endpoint, useTLS) + //Update utm if exists + if uptimeMonitor != nil { + uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter) + uptimeMonitor.CleanRecords() + } + utils.SendOK(w) } @@ -199,6 +218,13 @@ func DeleteProxyEndpoint(w http.ResponseWriter, r *http.Request) { } RemoveReverseProxyConfig(ep) + + //Update utm if exists + if uptimeMonitor != nil { + uptimeMonitor.Config.Targets = GetUptimeTargetsFromReverseProxyRules(dynamicProxyRouter) + uptimeMonitor.CleanRecords() + } + utils.SendOK(w) } diff --git a/src/specialRouter.go b/src/specialRouter.go new file mode 100644 index 0000000..126b05f --- /dev/null +++ b/src/specialRouter.go @@ -0,0 +1,12 @@ +package main + +/* + specialRouter.go + + This script holds special routers + that handle special features in sub modules +*/ + +func injectSpecialRoutingRules() { + +}