Browse Source

feat(kernal): add support for h2 and h3 protocols

Jacky 1 day ago
parent
commit
86390a5ec2

+ 15 - 0
api/settings/settings.go

@@ -106,6 +106,21 @@ func SaveSettings(c *gin.Context) {
 		}
 	}
 
+	// Validate HTTP/2 and HTTP/3 configuration
+	if json.Server.EnableH2 && !json.Server.EnableHTTPS {
+		c.JSON(http.StatusBadRequest, gin.H{
+			"message": "HTTP/2 requires HTTPS to be enabled",
+		})
+		return
+	}
+
+	if json.Server.EnableH3 && !json.Server.EnableHTTPS {
+		c.JSON(http.StatusBadRequest, gin.H{
+			"message": "HTTP/3 requires HTTPS to be enabled",
+		})
+		return
+	}
+
 	cSettings.ProtectedFill(cSettings.AppSettings, &json.App)
 	cSettings.ProtectedFill(cSettings.ServerSettings, &json.Server)
 	cSettings.ProtectedFill(settings.AuthSettings, &json.Auth)

+ 4 - 0
app.example.ini

@@ -6,6 +6,10 @@ JwtSecret =
 Host    = 0.0.0.0
 Port    = 9000
 RunMode = debug
+EnableHTTPS = false
+EnableH2 = false
+EnableH3 = false
+
 
 [database]
 Name = database

+ 3 - 0
app/src/api/settings.ts

@@ -12,6 +12,9 @@ export interface ServerSettings {
   enable_https: boolean
   ssl_cert: string
   ssl_key: string
+  // HTTP/2 and HTTP/3 protocol support (fixed priority: h3->h2->h1)
+  enable_h2: boolean
+  enable_h3: boolean
 }
 
 export interface DatabaseSettings {

+ 2 - 0
app/src/views/preference/store/index.ts

@@ -18,6 +18,8 @@ const useSystemSettingsStore = defineStore('systemSettings', () => {
       enable_https: false,
       ssl_cert: '',
       ssl_key: '',
+      enable_h2: false,
+      enable_h3: false,
     },
     database: {
       name: '',

+ 15 - 0
app/src/views/preference/tabs/ServerSettings.vue

@@ -41,6 +41,21 @@ function handleCertChange(certs: Cert[]) {
       <AFormItem :label="$gettext('SSL Key Path')">
         <p>{{ data.server.ssl_key }}</p>
       </AFormItem>
+
+      <AAlert
+        type="info"
+        :message="$gettext('Protocol configuration only takes effect when directly connecting. If using reverse proxy, please configure the protocol separately in the reverse proxy.')"
+        show-icon
+        class="mb-4"
+      />
+
+      <AFormItem :label="$gettext('Enable HTTP/2')" :help="$gettext('Enables HTTP/2 support with multiplexing and server push capabilities')">
+        <ASwitch v-model:checked="data.server.enable_h2" />
+      </AFormItem>
+
+      <AFormItem :label="$gettext('Enable HTTP/3')" :help="$gettext('Enables HTTP/3 support based on QUIC protocol for best performance')">
+        <ASwitch v-model:checked="data.server.enable_h3" />
+      </AFormItem>
     </div>
   </AForm>
 </template>

+ 1 - 1
app/src/views/site/site_edit/components/Cert/ChangeCert.vue

@@ -66,7 +66,7 @@ const columns = computed(() => certColumns.filter(item => item.pure))
         :columns
         :row-selection-type="selectionType"
         :table-props="{
-          rowKey: 'name',
+          rowKey: 'id',
         }"
         @update:selected-row-keys="handleSelectionChange"
       />

+ 29 - 0
docs/guide/config-server.md

@@ -33,6 +33,35 @@ When using the `debug` mode, Nginx UI will print SQL and its execution time and
 
 When using the `release` mode, Nginx UI will not print the execution time and caller of SQL on the console, and only the log of `Info` level or higher will be printed.
 
+## EnableHTTPS
+
+- Type: `bool`
+- Default: `false`
+
+This option is used to enable HTTPS support for the Nginx UI server. When enabled, the server will listen for HTTPS requests in addition to HTTP requests.
+
+## EnableH2
+
+- Type: `bool`
+- Default: `false`
+
+This option is used to enable HTTP/2 support for the Nginx UI server. 
+
+::: warning
+HTTP/2 requires HTTPS to be enabled. If you enable HTTP/2 without enabling HTTPS, the server will return an error during startup.
+:::
+
+## EnableH3
+
+- Type: `bool`
+- Default: `false`
+
+This option is used to enable HTTP/3 support for the Nginx UI server.
+
+::: warning
+HTTP/3 requires HTTPS to be enabled. If you enable HTTP/3 without enabling HTTPS, the server will return an error during startup.
+:::
+
 ## HttpHost
 - Type: `string`
 - Default:`0.0.0.0`

+ 3 - 0
docs/guide/env.md

@@ -15,6 +15,9 @@ Applicable for version v2.0.0-beta.37 and above.
 | Host                  | NGINX_UI_SERVER_HOST                  |
 | Port                  | NGINX_UI_SERVER_PORT                  |
 | RunMode               | NGINX_UI_SERVER_RUN_MODE              |
+| EnableHTTPS           | NGINX_UI_SERVER_ENABLE_HTTPS          |
+| EnableH2              | NGINX_UI_SERVER_ENABLE_H2             |
+| EnableH3              | NGINX_UI_SERVER_ENABLE_H3             |
 
 ## Database
 | Configuration Setting | Environment Variable |

+ 29 - 0
docs/zh_CN/guide/config-server.md

@@ -30,6 +30,35 @@ Nginx UI 的日志分为 6 个级别,分别为 `Debug`、`Info`、`Warn`、`Er
 
 当使用 `release` 模式时,Nginx UI 将不会在控制台打印 SQL 的执行时间和调用者, 只有 `Info` 级别或更高等级的日志才会被打印。
 
+## EnableHTTPS
+
+- 类型:`bool`
+- 默认值:`false`
+
+此选项用于启用 Nginx UI 服务器的 HTTPS 支持。启用后,服务器将同时监听 HTTPS 和 HTTP 请求。
+
+## EnableH2
+
+- 类型:`bool`
+- 默认值:`false`
+
+此选项用于启用 Nginx UI 服务器的 HTTP/2 支持。
+
+::: warning 警告
+HTTP/2 需要启用 HTTPS。如果在未启用 HTTPS 的情况下启用 HTTP/2,服务器将在启动时返回错误。
+:::
+
+## EnableH3
+
+- 类型:`bool`
+- 默认值:`false`
+
+此选项用于启用 Nginx UI 服务器的 HTTP/3 支持。
+
+::: warning 警告
+HTTP/3 需要启用 HTTPS。如果在未启用 HTTPS 的情况下启用 HTTP/3,服务器将在启动时返回错误。
+:::
+
 ## HttpHost
 - 类型: `string`
 - Default:`0.0.0.0`

+ 8 - 5
docs/zh_CN/guide/env.md

@@ -11,11 +11,14 @@
 
 ## Server
 
-| 配置      | 环境变量                     |
-|---------|--------------------------|
-| Host    | NGINX_UI_SERVER_HOST     |
-| Port    | NGINX_UI_SERVER_PORT     |
-| RunMode | NGINX_UI_SERVER_RUN_MODE |
+| 配置        | 环境变量                         |
+|-----------|------------------------------|
+| Host      | NGINX_UI_SERVER_HOST         |
+| Port      | NGINX_UI_SERVER_PORT         |
+| RunMode   | NGINX_UI_SERVER_RUN_MODE     |
+| EnableHTTPS | NGINX_UI_SERVER_ENABLE_HTTPS |
+| EnableH2  | NGINX_UI_SERVER_ENABLE_H2    |
+| EnableH3  | NGINX_UI_SERVER_ENABLE_H3    |
 
 ## Database
 

+ 8 - 5
docs/zh_TW/guide/env.md

@@ -11,11 +11,14 @@
 
 ## Server
 
-| 設定      | 環境變數                     |
-|---------|--------------------------|
-| Host    | NGINX_UI_SERVER_HOST     |
-| Port    | NGINX_UI_SERVER_PORT     |
-| RunMode | NGINX_UI_SERVER_RUN_MODE |
+| 設定        | 環境變數                         |
+|-----------|------------------------------|
+| Host      | NGINX_UI_SERVER_HOST         |
+| Port      | NGINX_UI_SERVER_PORT         |
+| RunMode   | NGINX_UI_SERVER_RUN_MODE     |
+| EnableHTTPS | NGINX_UI_SERVER_ENABLE_HTTPS |
+| EnableH2  | NGINX_UI_SERVER_ENABLE_H2    |
+| EnableH3  | NGINX_UI_SERVER_ENABLE_H3    |
 
 ## Database
 

+ 13 - 10
go.mod

@@ -43,7 +43,7 @@ require (
 	github.com/spf13/cast v1.9.2
 	github.com/stretchr/testify v1.10.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20250620092546-c3e307e36701
-	github.com/uozi-tech/cosy v1.23.1
+	github.com/uozi-tech/cosy v1.24.0
 	github.com/uozi-tech/cosy-driver-sqlite v0.2.1
 	github.com/urfave/cli/v3 v3.3.8
 	golang.org/x/crypto v0.39.0
@@ -81,9 +81,9 @@ require (
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
 	github.com/Microsoft/go-winio v0.6.2 // indirect
 	github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
-	github.com/RoaringBitmap/roaring/v2 v2.4.5 // indirect
+	github.com/RoaringBitmap/roaring/v2 v2.6.0 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
-	github.com/aliyun/aliyun-log-go-sdk v0.1.101 // indirect
+	github.com/aliyun/aliyun-log-go-sdk v0.1.102 // indirect
 	github.com/baidubce/bce-sdk-go v0.9.233 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bits-and-blooms/bitset v1.22.0 // indirect
@@ -193,7 +193,7 @@ require (
 	github.com/libdns/huaweicloud v1.0.0-beta.2 // indirect
 	github.com/libdns/libdns v1.1.0 // indirect
 	github.com/libdns/tencentcloud v1.4.1 // indirect
-	github.com/linode/linodego v1.52.2 // indirect
+	github.com/linode/linodego v1.53.0 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
 	github.com/lufia/plan9stats v0.0.0-20250317134145-8bc96cf8fc35 // indirect
@@ -202,7 +202,7 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.28 // indirect
 	github.com/miekg/dns v1.1.66 // indirect
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
-	github.com/minio/crc64nvme v1.0.1 // indirect
+	github.com/minio/crc64nvme v1.0.2 // indirect
 	github.com/minio/md5-simd v1.1.2 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
@@ -232,7 +232,7 @@ require (
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect
 	github.com/peterhellberg/link v1.2.0 // indirect
-	github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
+	github.com/philhofer/fwd v1.2.0 // indirect
 	github.com/pierrec/lz4/v4 v4.1.22 // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
@@ -240,8 +240,10 @@ require (
 	github.com/prometheus/client_golang v1.22.0 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.65.0 // indirect
-	github.com/prometheus/procfs v0.16.1 // indirect
+	github.com/prometheus/procfs v0.17.0 // indirect
 	github.com/prometheus/prometheus v0.304.2 // indirect
+	github.com/quic-go/qpack v0.5.1 // indirect
+	github.com/quic-go/quic-go v0.53.0 // indirect
 	github.com/redis/go-redis/v9 v9.11.0 // indirect
 	github.com/regfish/regfish-dnsapi-go v0.1.1 // indirect
 	github.com/robfig/cron/v3 v3.0.1 // indirect
@@ -275,19 +277,20 @@ require (
 	github.com/uozi-tech/cosy-driver-mysql v0.2.2 // indirect
 	github.com/uozi-tech/cosy-driver-postgres v0.2.1 // indirect
 	github.com/vinyldns/go-vinyldns v0.9.16 // indirect
-	github.com/volcengine/volc-sdk-golang v1.0.213 // indirect
+	github.com/volcengine/volc-sdk-golang v1.0.214 // indirect
 	github.com/vultr/govultr/v3 v3.21.0 // indirect
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
 	github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
-	go.etcd.io/bbolt v1.4.0 // indirect
+	go.etcd.io/bbolt v1.4.2 // indirect
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
 	go.opentelemetry.io/otel v1.37.0 // indirect
 	go.opentelemetry.io/otel/metric v1.37.0 // indirect
 	go.opentelemetry.io/otel/trace v1.37.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
+	go.uber.org/mock v0.5.2 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap v1.27.0 // indirect
 	go.yaml.in/yaml/v2 v2.4.2 // indirect
@@ -299,7 +302,7 @@ require (
 	golang.org/x/text v0.26.0 // indirect
 	golang.org/x/time v0.12.0 // indirect
 	golang.org/x/tools v0.34.0 // indirect
-	google.golang.org/api v0.239.0 // indirect
+	google.golang.org/api v0.240.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect
 	google.golang.org/grpc v1.73.0 // indirect
 	google.golang.org/protobuf v1.36.6 // indirect

+ 29 - 0
go.sum

@@ -684,6 +684,8 @@ github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
 github.com/RoaringBitmap/roaring/v2 v2.4.5 h1:uGrrMreGjvAtTBobc0g5IrW1D5ldxDQYe2JW2gggRdg=
 github.com/RoaringBitmap/roaring/v2 v2.4.5/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
+github.com/RoaringBitmap/roaring/v2 v2.6.0 h1:Ip8+kROnvVVcry+ESkfFdTPoLeKcoj7vhL2wJJKx2QA=
+github.com/RoaringBitmap/roaring/v2 v2.6.0/go.mod h1:FiJcsfkGje/nZBZgCu0ZxCPOKD/hVXDS2dXi7/eUFE0=
 github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
 github.com/Shopify/sarama v1.30.1/go.mod h1:hGgx05L/DiW8XYBXeJdKIN6V2QUy2H6JqME5VT1NLRw=
 github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
@@ -725,6 +727,8 @@ github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZ
 github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
 github.com/aliyun/aliyun-log-go-sdk v0.1.101 h1:bd+4FEhB33BLup4eG129J4fSDLqC2tAyU6mDrRCcKhU=
 github.com/aliyun/aliyun-log-go-sdk v0.1.101/go.mod h1:7QcyHasd4WLdC+lx4uCmdIBcl7WcgRHctwz8t1zAuPo=
+github.com/aliyun/aliyun-log-go-sdk v0.1.102 h1:93SswdufRjZ6Hf97Q22pDjWaa/LCwur/mX8jVZcFgow=
+github.com/aliyun/aliyun-log-go-sdk v0.1.102/go.mod h1:7QcyHasd4WLdC+lx4uCmdIBcl7WcgRHctwz8t1zAuPo=
 github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
 github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
@@ -829,6 +833,7 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -1451,6 +1456,8 @@ github.com/libdns/libdns v1.1.0 h1:9ze/tWvt7Df6sbhOJRB8jT33GHEHpEQXdtkE3hPthbU=
 github.com/libdns/libdns v1.1.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
 github.com/linode/linodego v1.52.2 h1:N9ozU27To1LMSrDd8WvJZ5STSz1eGYdyLnxhAR/dIZg=
 github.com/linode/linodego v1.52.2/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
+github.com/linode/linodego v1.53.0 h1:UWr7bUUVMtcfsuapC+6blm6+jJLPd7Tf9MZUpdOERnI=
+github.com/linode/linodego v1.53.0/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
@@ -1515,6 +1522,8 @@ github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8/go.mod h1:mC1jAcs
 github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
 github.com/minio/crc64nvme v1.0.1 h1:DHQPrYPdqK7jQG/Ls5CTBZWeex/2FMS3G5XGkycuFrY=
 github.com/minio/crc64nvme v1.0.1/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
+github.com/minio/crc64nvme v1.0.2 h1:6uO1UxGAD+kwqWWp7mBFsi5gAse66C4NXO8cmcVculg=
+github.com/minio/crc64nvme v1.0.2/go.mod h1:eVfm2fAzLlxMdUGc0EEBGSMmPwmXD5XiNRpnu9J3bvg=
 github.com/minio/highwayhash v1.0.1/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
 github.com/minio/highwayhash v1.0.2/go.mod h1:BQskDq+xkJ12lmlUUi7U0M5Swg3EWR+dLTk+kldvVxY=
 github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34=
@@ -1659,10 +1668,13 @@ github.com/peterhellberg/link v1.2.0 h1:UA5pg3Gp/E0F2WdX7GERiNrPQrM1K6CVJUUWfHa4
 github.com/peterhellberg/link v1.2.0/go.mod h1:gYfAh+oJgQu2SrZHg5hROVRQe1ICoK0/HHJTcE0edxc=
 github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c h1:dAMKvw0MlJT1GshSTtih8C2gDs04w8dReiOGXrGLNoY=
 github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
+github.com/philhofer/fwd v1.2.0 h1:e6DnBTl7vGY+Gz322/ASL4Gyp1FspeMvx1RNDoToZuM=
+github.com/philhofer/fwd v1.2.0/go.mod h1:RqIHx9QI14HlwKwm98g9Re5prTQ6LdeRQn+gXJFxsJM=
 github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
+github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
 github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
@@ -1727,11 +1739,17 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg=
 github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
+github.com/prometheus/procfs v0.17.0 h1:FuLQ+05u4ZI+SS/w9+BWEM2TXiHKsUQ9TADiRH7DuK0=
+github.com/prometheus/procfs v0.17.0/go.mod h1:oPQLaDAMRbA+u8H5Pbfq+dl3VDAvHxMUOVhe0wYB2zw=
 github.com/prometheus/prometheus v0.304.2 h1:HhjbaAwet87x8Be19PFI/5W96UMubGy3zt24kayEuh4=
 github.com/prometheus/prometheus v0.304.2/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so=
 github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8=
 github.com/prometheus/sigv4 v0.1.2/go.mod h1:GF9fwrvLgkQwDdQ5BXeV9XUSCH/IPNqzvAoaohfjqMU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
+github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
+github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
+github.com/quic-go/quic-go v0.53.0 h1:QHX46sISpG2S03dPeZBgVIZp8dGagIaiu2FiVYvpCZI=
+github.com/quic-go/quic-go v0.53.0/go.mod h1:e68ZEaCdyviluZmy44P6Iey98v/Wfz6HCjQEm+l8zTY=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/redis/go-redis/v9 v9.11.0 h1:E3S08Gl/nJNn5vkxd2i78wZxWAPNZgUNTp8WIJUAiIs=
@@ -1893,6 +1911,8 @@ github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
 github.com/uozi-tech/cosy v1.23.1 h1:+3QMMqcvWdh0oq6VJFA4NO/nXy2ez30I0fzzqygyQjc=
 github.com/uozi-tech/cosy v1.23.1/go.mod h1:ErH1Oo8nR3IwV+ek9wM8fGPcwr2fq9avnVpyMQj4ayE=
+github.com/uozi-tech/cosy v1.24.0 h1:bNQ4QurtTJrVBXihpXHZHYLskReOk6eNj1HxCPaEcOc=
+github.com/uozi-tech/cosy v1.24.0/go.mod h1:M393/6QxTvP0cJpZPbv/pvoZAW/PI3BRcWSJdXsq1vo=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2/go.mod h1:EZnRIbSj1V5U0gEeTobrXai/d1SV11lkl4zP9NFEmyE=
 github.com/uozi-tech/cosy-driver-postgres v0.2.1 h1:OICakGuT+omva6QOJCxTJ5Lfr7CGXLmk/zD+aS51Z2o=
@@ -1906,6 +1926,8 @@ github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
 github.com/volcengine/volc-sdk-golang v1.0.213 h1:Y/OlbZfv6hTI+r4vmcvtyKZ+KEsoibm9DGeEtNlymJE=
 github.com/volcengine/volc-sdk-golang v1.0.213/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
+github.com/volcengine/volc-sdk-golang v1.0.214 h1:70M2qibj0UeSjO9r+CRf/UuFqh/Iu0J86NSKUD6EEtc=
+github.com/volcengine/volc-sdk-golang v1.0.214/go.mod h1:zHJlaqiMbIB+0mcrsZPTwOb3FB7S/0MCfqlnO8R7hlM=
 github.com/vultr/govultr/v3 v3.21.0 h1:G/gOmCT7MGlII+iI98DjPdt/8IytC26oNcuk0LpJ8Y4=
 github.com/vultr/govultr/v3 v3.21.0/go.mod h1:9WwnWGCKnwDlNjHjtt+j+nP+0QWq6hQXzaHgddqrLWY=
 github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
@@ -1936,6 +1958,8 @@ github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxt
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.4.0 h1:TU77id3TnN/zKr7CO/uk+fBCwF2jGcMuw2B/FMAzYIk=
 go.etcd.io/bbolt v1.4.0/go.mod h1:AsD+OCi/qPN1giOX1aiLAha3o1U8rAz65bvN4j0sRuk=
+go.etcd.io/bbolt v1.4.2 h1:IrUHp260R8c+zYx/Tm8QZr04CX+qWS5PGfPdevhdm1I=
+go.etcd.io/bbolt v1.4.2/go.mod h1:Is8rSHO/b4f3XigBC0lL0+4FwAQv3HXEEIgFMuKHceM=
 go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
 go.etcd.io/etcd/api/v3 v3.5.7/go.mod h1:9qew1gCdDDLu+VwmeG+iFpL+QlpHTo7iubavdVDgCAA=
 go.etcd.io/etcd/api/v3 v3.5.9/go.mod h1:uyAal843mC8uUVSLWz6eHa/d971iDGnCRpmKd2Z+X8k=
@@ -1989,6 +2013,8 @@ go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpK
 go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko=
+go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o=
 go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
 go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
 go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
@@ -2559,6 +2585,8 @@ google.golang.org/api v0.114.0/go.mod h1:ifYI2ZsFK6/uGddGfAD5BMxlnkBqCmqHSDUVi45
 google.golang.org/api v0.122.0/go.mod h1:gcitW0lvnyWjSp9nKxAbdHKIZ6vF4aajGueeslZOyms=
 google.golang.org/api v0.239.0 h1:2hZKUnFZEy81eugPs4e2XzIJ5SOwQg0G82bpXD65Puo=
 google.golang.org/api v0.239.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
+google.golang.org/api v0.240.0 h1:PxG3AA2UIqT1ofIzWV2COM3j3JagKTKSwy7L6RHNXNU=
+google.golang.org/api v0.240.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2851,6 +2879,7 @@ k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
 k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
 k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=

+ 2 - 2
internal/cache/index.go

@@ -112,7 +112,7 @@ func (s *Scanner) watchAllDirectories() error {
 				logger.Error("Failed to watch directory:", path, err)
 				return err
 			}
-			logger.Debug("Watching directory:", path)
+			// logger.Debug("Watching directory:", path)
 		}
 		return nil
 	})
@@ -138,7 +138,7 @@ func (s *Scanner) periodicScan() {
 // handleShutdown listens for context cancellation and shuts down gracefully
 func (s *Scanner) handleShutdown() {
 	<-s.ctx.Done()
-	logger.Debug("Shutting down scanner")
+	logger.Info("Shutting down Index Scanner")
 	s.Shutdown()
 }
 

+ 9 - 11
internal/cron/upstream_availability.go

@@ -3,6 +3,7 @@ package cron
 import (
 	"time"
 
+	apiUpstream "github.com/0xJacky/Nginx-UI/api/upstream"
 	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/go-co-op/gocron/v2"
 	"github.com/uozi-tech/cosy/logger"
@@ -36,32 +37,29 @@ func executeUpstreamAvailabilityTest() {
 
 	targetCount := service.GetTargetCount()
 	if targetCount == 0 {
-		logger.Debug("No upstream targets to test")
+		// logger.Debug("No upstream targets to test")
 		return
 	}
 
 	// Check if we should skip this test due to active WebSocket connections
 	// (WebSocket connections trigger more frequent checks)
 	if hasActiveWebSocketConnections() {
-		logger.Debug("Skipping scheduled test due to active WebSocket connections")
+		// logger.Debug("Skipping scheduled test due to active WebSocket connections")
 		return
 	}
 
-	start := time.Now()
-	logger.Debug("Starting scheduled upstream availability test for", targetCount, "targets")
+	// start := time.Now()
+	// logger.Debug("Starting scheduled upstream availability test for", targetCount, "targets")
 
-	service.PerformAvailabilityTest()
+	// service.PerformAvailabilityTest()
 
-	duration := time.Since(start)
-	logger.Debug("Upstream availability test completed in", duration)
+	// duration := time.Since(start)
+	// logger.Debug("Upstream availability test completed in", duration)
 }
 
 // hasActiveWebSocketConnections checks if there are active WebSocket connections
-// This is a placeholder - the actual implementation should check the API package
 func hasActiveWebSocketConnections() bool {
-	// TODO: This should check api/upstream.HasActiveWebSocketConnections()
-	// but we need to avoid circular dependencies
-	return false
+	return apiUpstream.HasActiveWebSocketConnections()
 }
 
 // RestartUpstreamAvailabilityJob restarts the upstream availability job

+ 9 - 10
internal/upstream/service.go

@@ -5,7 +5,6 @@ import (
 	"time"
 
 	"github.com/0xJacky/Nginx-UI/internal/cache"
-	"github.com/uozi-tech/cosy/logger"
 )
 
 // TargetInfo contains proxy target information with source config
@@ -89,9 +88,9 @@ func (s *UpstreamService) updateTargetsFromConfig(configPath string, targets []P
 				if isOnlyConfig {
 					delete(s.targets, key)
 					delete(s.availabilityMap, key)
-					logger.Debug("Removed proxy target:", key, "from config:", configPath)
+					// logger.Debug("Removed proxy target:", key, "from config:", configPath)
 				} else {
-					logger.Debug("Keeping proxy target:", key, "still used by other configs")
+					// logger.Debug("Keeping proxy target:", key, "still used by other configs")
 				}
 			}
 		}
@@ -178,7 +177,7 @@ func (s *UpstreamService) PerformAvailabilityTest() {
 	s.testMutex.Lock()
 	if s.testInProgress {
 		s.testMutex.Unlock()
-		logger.Debug("Availability test already in progress, skipping")
+		// logger.Debug("Availability test already in progress, skipping")
 		return
 	}
 	s.testInProgress = true
@@ -196,11 +195,11 @@ func (s *UpstreamService) PerformAvailabilityTest() {
 	s.targetsMutex.RUnlock()
 
 	if targetCount == 0 {
-		logger.Debug("No targets to test")
+		// logger.Debug("No targets to test")
 		return
 	}
 
-	logger.Debug("Performing availability test for", targetCount, "unique targets")
+	// logger.Debug("Performing availability test for", targetCount, "unique targets")
 
 	// Get target keys for testing
 	s.targetsMutex.RLock()
@@ -218,7 +217,7 @@ func (s *UpstreamService) PerformAvailabilityTest() {
 	s.availabilityMap = results
 	s.targetsMutex.Unlock()
 
-	logger.Debug("Availability test completed for", len(results), "targets")
+	// logger.Debug("Availability test completed for", len(results), "targets")
 }
 
 // ClearTargets clears all targets (useful for testing or reloading)
@@ -231,7 +230,7 @@ func (s *UpstreamService) ClearTargets() {
 	s.configTargets = make(map[string][]string)
 	s.lastUpdateTime = time.Now()
 
-	logger.Debug("Cleared all proxy targets")
+	// logger.Debug("Cleared all proxy targets")
 }
 
 // GetLastUpdateTime returns the last time targets were updated
@@ -274,11 +273,11 @@ func (s *UpstreamService) RemoveConfigTargets(configPath string) {
 			if !isUsedByOthers {
 				delete(s.targets, key)
 				delete(s.availabilityMap, key)
-				logger.Debug("Removed proxy target:", key, "after config removal:", configPath)
+				// logger.Debug("Removed proxy target:", key, "after config removal:", configPath)
 			}
 		}
 		delete(s.configTargets, configPath)
 		s.lastUpdateTime = time.Now()
-		logger.Debug("Removed config targets for:", configPath)
+		// logger.Debug("Removed config targets for:", configPath)
 	}
 }

+ 44 - 18
main.go

@@ -5,7 +5,6 @@ import (
 	"crypto/tls"
 	"fmt"
 	"net"
-	"net/http"
 	"os/signal"
 	"syscall"
 
@@ -63,37 +62,64 @@ func Program(ctx context.Context, confPath string) func(l []net.Listener) error
 		// Kernel boot
 		cKernel.Boot(ctx)
 
-		srv := &http.Server{
-			Handler: cRouter.GetEngine(),
-		}
-
-		// defer Shutdown to wait for ongoing requests to be served before returning
-		defer srv.Shutdown(ctx)
+		// Get the HTTP handler from Cosy router
+		handler := cRouter.GetEngine()
 
-		var err error
+		// Configure TLS if HTTPS is enabled
+		var tlsConfig *tls.Config
 		if cSettings.ServerSettings.EnableHTTPS {
 			// Load TLS certificate
-			err = cert.LoadServerTLSCertificate()
+			err := cert.LoadServerTLSCertificate()
 			if err != nil {
 				logger.Fatalf("Failed to load TLS certificate: %v", err)
 				return err
 			}
 
-			tlsConfig := &tls.Config{
+			// Configure ALPN protocols based on settings
+			// Protocol negotiation priority is fixed: h3 -> h2 -> h1
+			var nextProtos []string
+			if cSettings.ServerSettings.EnableH3 {
+				nextProtos = append(nextProtos, "h3")
+			}
+			if cSettings.ServerSettings.EnableH2 {
+				nextProtos = append(nextProtos, "h2")
+			}
+			// HTTP/1.1 is always supported as fallback
+			nextProtos = append(nextProtos, "http/1.1")
+
+			tlsConfig = &tls.Config{
 				GetCertificate: func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
 					return cert.GetServerTLSCertificate()
 				},
 				MinVersion: tls.VersionTLS12,
+				NextProtos: nextProtos,
 			}
-			srv.TLSConfig = tlsConfig
-
-			logger.Info("Starting HTTPS server")
-			tlsListener := tls.NewListener(listener, tlsConfig)
-			return srv.Serve(tlsListener)
-		} else {
-			logger.Info("Starting HTTP server")
-			return srv.Serve(listener)
 		}
+
+		// Create and initialize the server factory
+		serverFactory := cKernel.NewServerFactory(handler, tlsConfig)
+		if err := serverFactory.Initialize(); err != nil {
+			logger.Fatalf("Failed to initialize server factory: %v", err)
+			return err
+		}
+
+		// Start the servers
+		if err := serverFactory.Start(ctx, listener); err != nil {
+			logger.Fatalf("Failed to start servers: %v", err)
+			return err
+		}
+
+		// Wait for context cancellation
+		<-ctx.Done()
+
+		// Graceful shutdown
+		logger.Info("Shutting down servers...")
+		if err := serverFactory.Shutdown(ctx); err != nil {
+			logger.Errorf("Error during server shutdown: %v", err)
+			return err
+		}
+
+		return nil
 	}
 }