diff --git a/pkg/config/flags.go b/pkg/config/flags.go
index f9d9e3e4..09d8f145 100644
--- a/pkg/config/flags.go
+++ b/pkg/config/flags.go
@@ -230,6 +230,7 @@ func RegisterServerConfigFlags(cmd *cobra.Command, c *v1.ServerConfig, opts ...R
 	cmd.PersistentFlags().IntVarP(&c.QUICBindPort, "quic_bind_port", "", 0, "quic bind udp port")
 	cmd.PersistentFlags().StringVarP(&c.ProxyBindAddr, "proxy_bind_addr", "", "0.0.0.0", "proxy bind address")
 	cmd.PersistentFlags().IntVarP(&c.VhostHTTPPort, "vhost_http_port", "", 0, "vhost http port")
+	cmd.PersistentFlags().BoolVarP(&c.VhostEnableH2C, "vhost_enable_h2c", "", false, "vhost enable h2c")
 	cmd.PersistentFlags().IntVarP(&c.VhostHTTPSPort, "vhost_https_port", "", 0, "vhost https port")
 	cmd.PersistentFlags().Int64VarP(&c.VhostHTTPTimeout, "vhost_http_timeout", "", 60, "vhost http response header timeout")
 	cmd.PersistentFlags().StringVarP(&c.WebServer.Addr, "dashboard_addr", "", "0.0.0.0", "dashboard address")
diff --git a/pkg/config/legacy/conversion.go b/pkg/config/legacy/conversion.go
index dd8c4a11..a9f0e911 100644
--- a/pkg/config/legacy/conversion.go
+++ b/pkg/config/legacy/conversion.go
@@ -110,6 +110,7 @@ func Convert_ServerCommonConf_To_v1(conf *ServerCommonConf) *v1.ServerConfig {
 
 	out.ProxyBindAddr = conf.ProxyBindAddr
 	out.VhostHTTPPort = conf.VhostHTTPPort
+	out.VhostEnableH2C = conf.VhostEnableH2C
 	out.VhostHTTPSPort = conf.VhostHTTPSPort
 	out.TCPMuxHTTPConnectPort = conf.TCPMuxHTTPConnectPort
 	out.TCPMuxPassthrough = conf.TCPMuxPassthrough
diff --git a/pkg/config/legacy/server.go b/pkg/config/legacy/server.go
index c58f76ad..8798d3d8 100644
--- a/pkg/config/legacy/server.go
+++ b/pkg/config/legacy/server.go
@@ -61,6 +61,11 @@ type ServerCommonConf struct {
 	// requests. If this value is 0, the server will not listen for HTTP
 	// requests. By default, this value is 0.
 	VhostHTTPPort int `ini:"vhost_http_port" json:"vhost_http_port"`
+	// VhostEnableH2c specifies whether to enable HTTP/2 cleartext upgrade.
+	// By default, this value is false. If enabled, the server will be compatible
+	// with http2 on cleartext, accordingly, the vhost server will use http2
+	// transport to proxy the request.
+	VhostEnableH2C bool `json:"vhostEnableH2C,omitempty"`
 	// VhostHTTPSPort specifies the port that the server listens for HTTPS
 	// Vhost requests. If this value is 0, the server will not listen for HTTPS
 	// requests. By default, this value is 0.
diff --git a/pkg/config/v1/server.go b/pkg/config/v1/server.go
index 3108cd34..8946eafe 100644
--- a/pkg/config/v1/server.go
+++ b/pkg/config/v1/server.go
@@ -47,6 +47,11 @@ type ServerConfig struct {
 	// VhostHTTPTimeout specifies the response header timeout for the Vhost
 	// HTTP server, in seconds. By default, this value is 60.
 	VhostHTTPTimeout int64 `json:"vhostHTTPTimeout,omitempty"`
+	// VhostEnableH2c specifies whether to enable HTTP/2 cleartext upgrade.
+	// By default, this value is false. If enabled, the server will be compatible
+	// with http2 on cleartext, accordingly, the vhost server will use http2
+	// transport to proxy the request.
+	VhostEnableH2C bool `json:"vhostEnableH2C,omitempty"`
 	// VhostHTTPSPort specifies the port that the server listens for HTTPS
 	// Vhost requests. If this value is 0, the server will not listen for HTTPS
 	// requests.
diff --git a/pkg/util/vhost/http.go b/pkg/util/vhost/http.go
index 30f9631e..87c5a43f 100644
--- a/pkg/util/vhost/http.go
+++ b/pkg/util/vhost/http.go
@@ -16,6 +16,7 @@ package vhost
 
 import (
 	"context"
+	"crypto/tls"
 	"encoding/base64"
 	"errors"
 	"fmt"
@@ -29,6 +30,8 @@ import (
 
 	libio "github.com/fatedier/golib/io"
 	"github.com/fatedier/golib/pool"
+	"golang.org/x/net/http2"
+	"golang.org/x/net/http2/h2c"
 
 	httppkg "github.com/fatedier/frp/pkg/util/http"
 	"github.com/fatedier/frp/pkg/util/log"
@@ -38,10 +41,11 @@ var ErrNoRouteFound = errors.New("no route found")
 
 type HTTPReverseProxyOptions struct {
 	ResponseHeaderTimeoutS int64
+	EnableH2C              bool
 }
 
 type HTTPReverseProxy struct {
-	proxy       *httputil.ReverseProxy
+	proxy       http.Handler
 	vhostRouter *Routers
 
 	responseHeaderTimeout time.Duration
@@ -55,6 +59,40 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 		responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,
 		vhostRouter:           vhostRouter,
 	}
+
+	var transport http.RoundTripper
+	// Create a connection to one proxy routed by route policy.
+	transport = &http.Transport{
+		ResponseHeaderTimeout: rp.responseHeaderTimeout,
+		IdleConnTimeout:       60 * time.Second,
+		MaxIdleConnsPerHost:   5,
+		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+			return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
+		},
+		Proxy: func(req *http.Request) (*url.URL, error) {
+			// Use proxy mode if there is host in HTTP first request line.
+			// GET http://example.com/ HTTP/1.1
+			// Host: example.com
+			//
+			// Normal:
+			// GET / HTTP/1.1
+			// Host: example.com
+			urlHost := req.Context().Value(RouteInfoKey).(*RequestRouteInfo).URLHost
+			if urlHost != "" {
+				return req.URL, nil
+			}
+			return nil, nil
+		},
+	}
+	if option.EnableH2C {
+		transport = &http2.Transport{
+			AllowHTTP: true,
+			DialTLSContext: func(ctx context.Context, network, addr string, _ *tls.Config) (net.Conn, error) {
+				return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
+			},
+		}
+	}
+
 	proxy := &httputil.ReverseProxy{
 		// Modify incoming requests by route policies.
 		Rewrite: func(r *httputil.ProxyRequest) {
@@ -101,29 +139,7 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 			}
 			return nil
 		},
-		// Create a connection to one proxy routed by route policy.
-		Transport: &http.Transport{
-			ResponseHeaderTimeout: rp.responseHeaderTimeout,
-			IdleConnTimeout:       60 * time.Second,
-			MaxIdleConnsPerHost:   5,
-			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
-				return rp.CreateConnection(ctx.Value(RouteInfoKey).(*RequestRouteInfo), true)
-			},
-			Proxy: func(req *http.Request) (*url.URL, error) {
-				// Use proxy mode if there is host in HTTP first request line.
-				// GET http://example.com/ HTTP/1.1
-				// Host: example.com
-				//
-				// Normal:
-				// GET / HTTP/1.1
-				// Host: example.com
-				urlHost := req.Context().Value(RouteInfoKey).(*RequestRouteInfo).URLHost
-				if urlHost != "" {
-					return req.URL, nil
-				}
-				return nil, nil
-			},
-		},
+		Transport:  transport,
 		BufferPool: pool.NewBuffer(32 * 1024),
 		ErrorLog:   stdlog.New(log.NewWriteLogger(log.WarnLevel, 2), "", 0),
 		ErrorHandler: func(rw http.ResponseWriter, req *http.Request, err error) {
@@ -138,7 +154,11 @@ func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *
 			_, _ = rw.Write(getNotFoundPageContent())
 		},
 	}
-	rp.proxy = proxy
+	if option.EnableH2C {
+		rp.proxy = h2c.NewHandler(proxy, &http2.Server{})
+	} else {
+		rp.proxy = proxy
+	}
 	return rp
 }
 
diff --git a/server/dashboard_api.go b/server/dashboard_api.go
index f34da4ef..8aeb8519 100644
--- a/server/dashboard_api.go
+++ b/server/dashboard_api.go
@@ -70,6 +70,7 @@ type serverInfoResp struct {
 	Version               string `json:"version"`
 	BindPort              int    `json:"bindPort"`
 	VhostHTTPPort         int    `json:"vhostHTTPPort"`
+	VhostEnableH2C        bool   `json:"vhostEnableH2C"`
 	VhostHTTPSPort        int    `json:"vhostHTTPSPort"`
 	TCPMuxHTTPConnectPort int    `json:"tcpmuxHTTPConnectPort"`
 	KCPBindPort           int    `json:"kcpBindPort"`
@@ -111,6 +112,7 @@ func (svr *Service) apiServerInfo(w http.ResponseWriter, r *http.Request) {
 		BindPort:              svr.cfg.BindPort,
 		VhostHTTPPort:         svr.cfg.VhostHTTPPort,
 		VhostHTTPSPort:        svr.cfg.VhostHTTPSPort,
+		VhostEnableH2C:        svr.cfg.VhostEnableH2C,
 		TCPMuxHTTPConnectPort: svr.cfg.TCPMuxHTTPConnectPort,
 		KCPBindPort:           svr.cfg.KCPBindPort,
 		QUICBindPort:          svr.cfg.QUICBindPort,
diff --git a/server/service.go b/server/service.go
index 27c4110d..7eb5efcf 100644
--- a/server/service.go
+++ b/server/service.go
@@ -281,6 +281,7 @@ func NewService(cfg *v1.ServerConfig) (*Service, error) {
 	if cfg.VhostHTTPPort > 0 {
 		rp := vhost.NewHTTPReverseProxy(vhost.HTTPReverseProxyOptions{
 			ResponseHeaderTimeoutS: cfg.VhostHTTPTimeout,
+			EnableH2C:              cfg.VhostEnableH2C,
 		}, svr.httpVhostRouter)
 		svr.rc.HTTPReverseProxy = rp