浏览代码

Merge pull request #2324 from fatedier/dev

bump version v0.36.2
fatedier 4 年之前
父节点
当前提交
c5c79e4148

+ 1 - 1
Makefile.cross-compiles

@@ -2,7 +2,7 @@ export PATH := $(GOPATH)/bin:$(PATH)
 export GO111MODULE=on
 LDFLAGS := -s -w
 
-os-archs=darwin:amd64 darwin:arm64 freebsd:386 freebsd:amd64 linux:386 linux:amd64 linux:arm windows:386 windows:amd64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat
+os-archs=darwin:amd64 darwin:arm64 freebsd:386 freebsd:amd64 linux:386 linux:amd64 linux:arm linux:arm64 windows:386 windows:amd64 linux:mips64 linux:mips64le linux:mips:softfloat linux:mipsle:softfloat
 
 all: build
 

+ 2 - 2
README.md

@@ -732,7 +732,7 @@ This feature is suitable for a large number of short connections.
 
 Load balancing is supported by `group`.
 
-This feature is only available for types `tcp` and `http` now.
+This feature is only available for types `tcp`, `http`, `tcpmux` now.
 
 ```ini
 # frpc.ini
@@ -1006,7 +1006,7 @@ frpc will generate 8 proxies like `test_tcp_0`, `test_tcp_1`, ..., `test_tcp_7`.
 
 frpc only forwards requests to local TCP or UDP ports by default.
 
-Plugins are used for providing rich features. There are built-in plugins such as `unix_domain_socket`, `http_proxy`, `socks5`, `static_file` and you can see [example usage](#example-usage).
+Plugins are used for providing rich features. There are built-in plugins such as `unix_domain_socket`, `http_proxy`, `socks5`, `static_file`, `http2https`, `https2http`, `https2https` and you can see [example usage](#example-usage).
 
 Specify which plugin to use with the `plugin` parameter. Configuration parameters of plugin should be started with `plugin_`. `local_ip` and `local_port` are not used for plugin.
 

文件差异内容过多而无法显示
+ 0 - 0
assets/frpc/statik/statik.go


+ 1 - 1
assets/frps/static/index.html

@@ -1 +1 @@
-<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?b8b55d8156200869417b"></script><script type="text/javascript" src="vendor.js?3e078a9d741093b909de"></script></body> </html> 
+<!doctype html> <html lang=en> <head> <meta charset=utf-8> <title>frps dashboard</title> <link rel="shortcut icon" href="favicon.ico"></head> <body> <div id=app></div> <script type="text/javascript" src="manifest.js?782d7b1b910e824ac986"></script><script type="text/javascript" src="vendor.js?7f899297af075fb3b085"></script></body> </html> 

+ 1 - 1
assets/frps/static/manifest.js

@@ -1 +1 @@
-!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"3e078a9d741093b909de"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);
+!function(e){function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}var r=window.webpackJsonp;window.webpackJsonp=function(t,u,c){for(var i,a,f,l=0,s=[];l<t.length;l++)a=t[l],o[a]&&s.push(o[a][0]),o[a]=0;for(i in u)Object.prototype.hasOwnProperty.call(u,i)&&(e[i]=u[i]);for(r&&r(t,u,c);s.length;)s.shift()();if(c)for(l=0;l<c.length;l++)f=n(n.s=c[l]);return f};var t={},o={1:0};n.e=function(e){function r(){i.onerror=i.onload=null,clearTimeout(a);var n=o[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),o[e]=void 0)}var t=o[e];if(0===t)return new Promise(function(e){e()});if(t)return t[2];var u=new Promise(function(n,r){t=o[e]=[n,r]});t[2]=u;var c=document.getElementsByTagName("head")[0],i=document.createElement("script");i.type="text/javascript",i.charset="utf-8",i.async=!0,i.timeout=12e4,n.nc&&i.setAttribute("nonce",n.nc),i.src=n.p+""+e+".js?"+{0:"7f899297af075fb3b085"}[e];var a=setTimeout(r,12e4);return i.onerror=i.onload=r,c.appendChild(i),u},n.m=e,n.c=t,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},n.p="",n.oe=function(e){throw console.error(e),e}}([]);

文件差异内容过多而无法显示
+ 0 - 0
assets/frps/static/vendor.js


文件差异内容过多而无法显示
+ 0 - 0
assets/frps/statik/statik.go


+ 7 - 11
cmd/frpc/sub/root.go

@@ -139,8 +139,10 @@ func parseClientCommonCfg(fileType int, source []byte) (cfg config.ClientCommonC
 		return
 	}
 
-	err = cfg.Check()
+	cfg.Complete()
+	err = cfg.Validate()
 	if err != nil {
+		err = fmt.Errorf("Parse config error: %v", err)
 		return
 	}
 	return
@@ -167,11 +169,6 @@ func parseClientCommonCfgFromCmd() (cfg config.ClientCommonConf, err error) {
 	cfg.LogLevel = logLevel
 	cfg.LogFile = logFile
 	cfg.LogMaxDays = int64(logMaxDays)
-	if logFile == "console" {
-		cfg.LogWay = "console"
-	} else {
-		cfg.LogWay = "file"
-	}
 	cfg.DisableLogColor = disableLogColor
 
 	// Only token authentication is supported in cmd mode
@@ -186,21 +183,20 @@ func runClient(cfgFilePath string) (err error) {
 	var content []byte
 	content, err = config.GetRenderedConfFromFile(cfgFilePath)
 	if err != nil {
-		return
+		return err
 	}
 
 	cfg, err := parseClientCommonCfg(CfgFileTypeIni, content)
 	if err != nil {
-		return
+		return err
 	}
 
 	pxyCfgs, visitorCfgs, err := config.LoadAllProxyConfsFromIni(cfg.User, content, cfg.Start)
 	if err != nil {
-		return
+		return err
 	}
 
-	err = startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)
-	return
+	return startService(cfg, pxyCfgs, visitorCfgs, cfgFilePath)
 }
 
 func startService(

+ 10 - 10
cmd/frps/root.go

@@ -105,7 +105,6 @@ var rootCmd = &cobra.Command{
 		var cfg config.ServerCommonConf
 		var err error
 		if cfgFile != "" {
-			log.Info("frps uses config file: %s", cfgFile)
 			var content []byte
 			content, err = config.GetRenderedConfFromFile(cfgFile)
 			if err != nil {
@@ -113,7 +112,6 @@ var rootCmd = &cobra.Command{
 			}
 			cfg, err = parseServerCommonCfg(CfgFileTypeIni, content)
 		} else {
-			log.Info("frps uses command line arguments for config")
 			cfg, err = parseServerCommonCfg(CfgFileTypeCmd, nil)
 		}
 		if err != nil {
@@ -144,9 +142,10 @@ func parseServerCommonCfg(fileType int, source []byte) (cfg config.ServerCommonC
 	if err != nil {
 		return
 	}
-
-	err = cfg.Check()
+	cfg.Complete()
+	err = cfg.Validate()
 	if err != nil {
+		err = fmt.Errorf("Parse config error: %v", err)
 		return
 	}
 	return
@@ -190,18 +189,19 @@ func parseServerCommonCfgFromCmd() (cfg config.ServerCommonConf, err error) {
 		}
 	}
 	cfg.MaxPortsPerClient = maxPortsPerClient
-
-	if logFile == "console" {
-		cfg.LogWay = "console"
-	} else {
-		cfg.LogWay = "file"
-	}
 	cfg.DisableLogColor = disableLogColor
 	return
 }
 
 func runServer(cfg config.ServerCommonConf) (err error) {
 	log.InitLog(cfg.LogWay, cfg.LogFile, cfg.LogLevel, cfg.LogMaxDays, cfg.DisableLogColor)
+
+	if cfgFile != "" {
+		log.Info("frps uses config file: %s", cfgFile)
+	} else {
+		log.Info("frps uses command line arguments for config")
+	}
+
 	svr, err := server.NewService(cfg)
 	if err != nil {
 		return err

+ 16 - 4
pkg/config/client.go

@@ -29,7 +29,7 @@ import (
 // recommended to use GetDefaultClientConf instead of creating this object
 // directly, so that all unspecified fields have reasonable default values.
 type ClientCommonConf struct {
-	auth.ClientConfig `ini:",extends" json:"inline"`
+	auth.ClientConfig `ini:",extends"`
 
 	// ServerAddr specifies the address of the server to connect to. By
 	// default, this value is "0.0.0.0".
@@ -173,13 +173,21 @@ func GetDefaultClientConf() ClientCommonConf {
 	}
 }
 
-func (cfg *ClientCommonConf) Check() error {
+func (cfg *ClientCommonConf) Complete() {
+	if cfg.LogFile == "console" {
+		cfg.LogWay = "console"
+	} else {
+		cfg.LogWay = "file"
+	}
+}
+
+func (cfg *ClientCommonConf) Validate() error {
 	if cfg.HeartbeatInterval <= 0 {
-		return fmt.Errorf("Parse conf error: invalid heartbeat_interval")
+		return fmt.Errorf("invalid heartbeat_interval")
 	}
 
 	if cfg.HeartbeatTimeout < cfg.HeartbeatInterval {
-		return fmt.Errorf("Parse conf error: invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval")
+		return fmt.Errorf("invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval")
 	}
 
 	if cfg.TLSEnable == false {
@@ -196,6 +204,10 @@ func (cfg *ClientCommonConf) Check() error {
 		}
 	}
 
+	if cfg.Protocol != "tcp" && cfg.Protocol != "kcp" && cfg.Protocol != "websocket" {
+		return fmt.Errorf("invalid protocol")
+	}
+
 	return nil
 }
 

+ 13 - 13
pkg/config/proxy.go

@@ -144,8 +144,8 @@ type BaseProxyConf struct {
 	Metas map[string]string `ini:"-" json:"metas"`
 
 	// TODO: LocalSvrConf => LocalAppConf
-	LocalSvrConf    `ini:",extends" json:"inline"`
-	HealthCheckConf `ini:",extends" json:"inline"`
+	LocalSvrConf    `ini:",extends"`
+	HealthCheckConf `ini:",extends"`
 }
 
 type DomainConf struct {
@@ -155,8 +155,8 @@ type DomainConf struct {
 
 // HTTP
 type HTTPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
-	DomainConf    `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
+	DomainConf    `ini:",extends"`
 
 	Locations         []string          `ini:"locations" json:"locations"`
 	HTTPUser          string            `ini:"http_user" json:"http_user"`
@@ -167,27 +167,27 @@ type HTTPProxyConf struct {
 
 // HTTPS
 type HTTPSProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
-	DomainConf    `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
+	DomainConf    `ini:",extends"`
 }
 
 // TCP
 type TCPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
 	RemotePort    int `ini:"remote_port" json:"remote_port"`
 }
 
 // TCPMux
 type TCPMuxProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
-	DomainConf    `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
+	DomainConf    `ini:",extends"`
 
 	Multiplexer string `ini:"multiplexer"`
 }
 
 // STCP
 type STCPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
 
 	Role string `ini:"role" json:"role"`
 	Sk   string `ini:"sk" json:"sk"`
@@ -195,7 +195,7 @@ type STCPProxyConf struct {
 
 // XTCP
 type XTCPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
 
 	Role string `ini:"role" json:"role"`
 	Sk   string `ini:"sk" json:"sk"`
@@ -203,14 +203,14 @@ type XTCPProxyConf struct {
 
 // UDP
 type UDPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
 
 	RemotePort int `ini:"remote_port" json:"remote_port"`
 }
 
 // SUDP
 type SUDPProxyConf struct {
-	BaseProxyConf `ini:",extends" json:"inline"`
+	BaseProxyConf `ini:",extends"`
 
 	Role string `ini:"role" json:"role"`
 	Sk   string `ini:"sk" json:"sk"`

+ 24 - 8
pkg/config/server.go

@@ -29,7 +29,7 @@ import (
 // recommended to use GetDefaultServerConf instead of creating this object
 // directly, so that all unspecified fields have reasonable default values.
 type ServerCommonConf struct {
-	auth.ServerConfig `ini:",extends" json:"inline"`
+	auth.ServerConfig `ini:",extends"`
 
 	// BindAddr specifies the address that the server binds to. By default,
 	// this value is "0.0.0.0".
@@ -46,7 +46,7 @@ type ServerCommonConf struct {
 	// this value is 0.
 	KCPBindPort int `ini:"kcp_bind_port" json:"kcp_bind_port"`
 	// ProxyBindAddr specifies the address that the proxy binds to. This value
-	// may be the same as BindAddr. By default, this value is "0.0.0.0".
+	// may be the same as BindAddr.
 	ProxyBindAddr string `ini:"proxy_bind_addr" json:"proxy_bind_addr"`
 	// VhostHTTPPort specifies the port that the server listens for HTTP Vhost
 	// requests. If this value is 0, the server will not listen for HTTP
@@ -174,7 +174,7 @@ func GetDefaultServerConf() ServerCommonConf {
 		BindPort:               7000,
 		BindUDPPort:            0,
 		KCPBindPort:            0,
-		ProxyBindAddr:          "0.0.0.0",
+		ProxyBindAddr:          "",
 		VhostHTTPPort:          0,
 		VhostHTTPSPort:         0,
 		TCPMuxHTTPConnectPort:  0,
@@ -208,10 +208,6 @@ func GetDefaultServerConf() ServerCommonConf {
 	}
 }
 
-func (cfg *ServerCommonConf) Check() error {
-	return nil
-}
-
 func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
 
 	f, err := ini.LoadSources(ini.LoadOptions{
@@ -242,7 +238,7 @@ func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
 	if allowPortStr != "" {
 		allowPorts, err := util.ParseRangeNumbers(allowPortStr)
 		if err != nil {
-			return ServerCommonConf{}, fmt.Errorf("Parse conf error: allow_ports: %v", err)
+			return ServerCommonConf{}, fmt.Errorf("invalid allow_ports: %v", err)
 		}
 		for _, port := range allowPorts {
 			common.AllowPorts[int(port)] = struct{}{}
@@ -269,6 +265,26 @@ func UnmarshalServerConfFromIni(source interface{}) (ServerCommonConf, error) {
 	return common, nil
 }
 
+func (cfg *ServerCommonConf) Complete() {
+	if cfg.LogFile == "console" {
+		cfg.LogWay = "console"
+	} else {
+		cfg.LogWay = "file"
+	}
+
+	if cfg.ProxyBindAddr == "" {
+		cfg.ProxyBindAddr = cfg.BindAddr
+	}
+
+	if cfg.TLSTrustedCaFile != "" {
+		cfg.TLSOnly = true
+	}
+}
+
+func (cfg *ServerCommonConf) Validate() error {
+	return nil
+}
+
 func loadHTTPPluginOpt(section *ini.Section) (*plugin.HTTPPluginOptions, error) {
 	name := strings.TrimSpace(strings.TrimPrefix(section.Name(), "plugin."))
 

+ 4 - 3
pkg/config/server_test.go

@@ -18,7 +18,7 @@ import (
 	"testing"
 
 	"github.com/fatedier/frp/pkg/auth"
-	"github.com/fatedier/frp/pkg/plugin/server"
+	plugin "github.com/fatedier/frp/pkg/plugin/server"
 
 	"github.com/stretchr/testify/assert"
 )
@@ -133,7 +133,7 @@ func Test_LoadServerCommonConf(t *testing.T) {
 				},
 				MaxPoolCount:      59,
 				MaxPortsPerClient: 9,
-				TLSOnly:           false,
+				TLSOnly:           true,
 				TLSCertFile:       "server.crt",
 				TLSKeyFile:        "server.key",
 				TLSTrustedCaFile:  "ca.crt",
@@ -177,7 +177,7 @@ func Test_LoadServerCommonConf(t *testing.T) {
 				BindAddr:               "0.0.0.9",
 				BindPort:               7009,
 				BindUDPPort:            7008,
-				ProxyBindAddr:          "0.0.0.0",
+				ProxyBindAddr:          "0.0.0.9",
 				VhostHTTPTimeout:       60,
 				DashboardAddr:          "0.0.0.0",
 				DashboardUser:          "admin",
@@ -202,6 +202,7 @@ func Test_LoadServerCommonConf(t *testing.T) {
 	for _, c := range testcases {
 		actual, err := UnmarshalServerConfFromIni(c.source)
 		assert.NoError(err)
+		actual.Complete()
 		assert.Equal(c.expected, actual)
 	}
 }

+ 3 - 3
pkg/config/visitor.go

@@ -52,15 +52,15 @@ type BaseVisitorConf struct {
 }
 
 type SUDPVisitorConf struct {
-	BaseVisitorConf `ini:",extends" json:"inline"`
+	BaseVisitorConf `ini:",extends"`
 }
 
 type STCPVisitorConf struct {
-	BaseVisitorConf `ini:",extends" json:"inline"`
+	BaseVisitorConf `ini:",extends"`
 }
 
 type XTCPVisitorConf struct {
-	BaseVisitorConf `ini:",extends" json:"inline"`
+	BaseVisitorConf `ini:",extends"`
 }
 
 // DefaultVisitorConf creates a empty VisitorConf object by visitorType.

+ 1 - 1
pkg/util/version/version.go

@@ -19,7 +19,7 @@ import (
 	"strings"
 )
 
-var version string = "0.36.1"
+var version string = "0.36.2"
 
 func Full() string {
 	return version

+ 1 - 1
web/frps/src/components/Overview.vue

@@ -78,7 +78,7 @@
         },
         methods: {
             fetchData() {
-                fetch('/api/serverinfo', {credentials: 'include'})
+                fetch('../api/serverinfo', {credentials: 'include'})
               .then(res => {
                 return res.json()
               }).then(json => {

+ 2 - 2
web/frps/src/components/ProxiesHttp.vue

@@ -116,7 +116,7 @@
         return Humanize.fileSize(row.traffic_out)
       },
       fetchData() {
-        fetch('/api/serverinfo', {credentials: 'include'})
+        fetch('../api/serverinfo', {credentials: 'include'})
           .then(res => {
             return res.json()
           }).then(json => {
@@ -125,7 +125,7 @@
             if (this.vhost_http_port == null || this.vhost_http_port == 0) {
               return
             } else {
-              fetch('/api/proxy/http', {credentials: 'include'})
+              fetch('../api/proxy/http', {credentials: 'include'})
                 .then(res => {
                   return res.json()
                 }).then(json => {

+ 2 - 2
web/frps/src/components/ProxiesHttps.vue

@@ -111,7 +111,7 @@
         return Humanize.fileSize(row.traffic_out)
       },
       fetchData() {
-        fetch('/api/serverinfo', {credentials: 'include'})
+        fetch('../api/serverinfo', {credentials: 'include'})
           .then(res => {
             return res.json()
           }).then(json => {
@@ -120,7 +120,7 @@
             if (this.vhost_https_port == null || this.vhost_https_port == 0) {
               return
             } else {
-              fetch('/api/proxy/https', {credentials: 'include'})
+              fetch('../api/proxy/https', {credentials: 'include'})
                 .then(res => {
                   return res.json()
                 }).then(json => {

+ 1 - 1
web/frps/src/components/ProxiesStcp.vue

@@ -95,7 +95,7 @@
         return Humanize.fileSize(row.traffic_out)
       },
       fetchData() {
-        fetch('/api/proxy/stcp', {credentials: 'include'})
+        fetch('../api/proxy/stcp', {credentials: 'include'})
           .then(res => {
             return res.json()
           }).then(json => {

+ 1 - 1
web/frps/src/components/ProxiesTcp.vue

@@ -103,7 +103,7 @@
         return Humanize.fileSize(row.traffic_out)
       },
       fetchData() {
-        fetch('/api/proxy/tcp', {credentials: 'include'})
+        fetch('../api/proxy/tcp', {credentials: 'include'})
           .then(res => {
             return res.json()
           }).then(json => {

+ 1 - 1
web/frps/src/components/ProxiesUdp.vue

@@ -105,7 +105,7 @@
         return Humanize.fileSize(row.traffic_out)
       },
       fetchData() {
-        fetch('/api/proxy/udp', {credentials: 'include'})
+        fetch('../api/proxy/udp', {credentials: 'include'})
           .then(res => {
             return res.json()
           }).then(json => {

+ 1 - 1
web/frps/src/components/Traffic.vue

@@ -14,7 +14,7 @@ export default {
     //},
     methods: {
         fetchData() {
-            let url = '/api/traffic/' + this.proxy_name
+            let url = '../api/traffic/' + this.proxy_name
             fetch(url, {credentials: 'include'})
               .then(res => {
                 return res.json()

+ 4 - 4
web/frps/src/utils/proxy.js

@@ -54,8 +54,8 @@ class HttpProxy extends BaseProxy {
             this.custom_domains = proxyStats.conf.custom_domains
             this.host_header_rewrite = proxyStats.conf.host_header_rewrite
             this.locations = proxyStats.conf.locations
-            if (proxyStats.conf.sub_domain != "") {
-                this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
+            if (proxyStats.conf.subdomain != "") {
+                this.subdomain = proxyStats.conf.subdomain + "." + subdomain_host
             } else {
                 this.subdomain = ""
             }
@@ -75,8 +75,8 @@ class HttpsProxy extends BaseProxy {
         this.port = port
         if (proxyStats.conf != null) {
             this.custom_domains = proxyStats.conf.custom_domains
-            if (proxyStats.conf.sub_domain != "") {
-                this.subdomain = proxyStats.conf.sub_domain + "." + subdomain_host
+            if (proxyStats.conf.subdomain != "") {
+                this.subdomain = proxyStats.conf.subdomain + "." + subdomain_host
             } else {
                 this.subdomain = ""
             }

部分文件因为文件数量过多而无法显示