diff --git a/internal/bootstrap/data/data.go b/internal/bootstrap/data/data.go
index 94a1c727af6..832ffce149a 100644
--- a/internal/bootstrap/data/data.go
+++ b/internal/bootstrap/data/data.go
@@ -7,5 +7,6 @@ func InitData() {
 	initSettings()
 	if args.Dev {
 		initDevData()
+		initDevDo()
 	}
 }
diff --git a/internal/bootstrap/data/dev.go b/internal/bootstrap/data/dev.go
index 2d360062e9d..cb290bd3914 100644
--- a/internal/bootstrap/data/dev.go
+++ b/internal/bootstrap/data/dev.go
@@ -2,7 +2,9 @@ package data
 
 import (
 	"context"
+	"github.com/alist-org/alist/v3/cmd/args"
 	"github.com/alist-org/alist/v3/internal/db"
+	"github.com/alist-org/alist/v3/internal/message"
 	"github.com/alist-org/alist/v3/internal/model"
 	"github.com/alist-org/alist/v3/internal/operations"
 	log "github.com/sirupsen/logrus"
@@ -30,3 +32,23 @@ func initDevData() {
 		log.Fatalf("failed to create user: %+v", err)
 	}
 }
+
+func initDevDo() {
+	if args.Dev {
+		go func() {
+			err := message.GetMessenger().WaitSend(map[string]string{
+				"type": "dev",
+				"msg":  "dev mode",
+			}, 10)
+			if err != nil {
+				log.Debugf("%+v", err)
+			}
+			m, err := message.GetMessenger().WaitReceive(10)
+			if err != nil {
+				log.Debugf("%+v", err)
+			} else {
+				log.Debugf("received: %+v", m)
+			}
+		}()
+	}
+}
diff --git a/internal/message/message.go b/internal/message/message.go
index 24adb38f799..baf753ffd1c 100644
--- a/internal/message/message.go
+++ b/internal/message/message.go
@@ -1,8 +1,12 @@
 package message
 
 type Messenger interface {
-	Send(string, interface{}) error
-	WaitSend(string, interface{}) error
-	Receive(string) (string, error)
-	WaitReceive(string) (string, error)
+	Send(interface{}) error
+	Receive() (string, error)
+	WaitSend(interface{}, int) error
+	WaitReceive(int) (string, error)
+}
+
+func GetMessenger() Messenger {
+	return PostInstance
 }
diff --git a/internal/message/post.go b/internal/message/post.go
new file mode 100644
index 00000000000..c7e5fd3909c
--- /dev/null
+++ b/internal/message/post.go
@@ -0,0 +1,81 @@
+package message
+
+import (
+	"github.com/alist-org/alist/v3/server/common"
+	"github.com/gin-gonic/gin"
+	"github.com/pkg/errors"
+	"time"
+)
+
+type Post struct {
+	Received chan string      // received messages from web
+	ToSend   chan interface{} // messages to send to web
+}
+
+type Req struct {
+	Message string `json:"message" form:"message"`
+}
+
+func (p *Post) GetHandle(c *gin.Context) {
+	select {
+	case message := <-p.ToSend:
+		common.SuccessResp(c, message)
+	default:
+		common.ErrorStrResp(c, "no message", 404)
+	}
+}
+
+func (p *Post) SendHandle(c *gin.Context) {
+	var req Req
+	if err := c.ShouldBind(&req); err != nil {
+		common.ErrorResp(c, err, 400)
+		return
+	}
+	select {
+	case p.Received <- req.Message:
+		common.SuccessResp(c)
+	default:
+		common.ErrorStrResp(c, "send failed", 500)
+	}
+}
+
+func (p *Post) Send(data interface{}) error {
+	select {
+	case p.ToSend <- data:
+		return nil
+	default:
+		return errors.New("send failed")
+	}
+}
+
+func (p *Post) Receive() (string, error) {
+	select {
+	case message := <-p.Received:
+		return message, nil
+	default:
+		return "", errors.New("receive failed")
+	}
+}
+
+func (p *Post) WaitSend(data interface{}, d int) error {
+	select {
+	case p.ToSend <- data:
+		return nil
+	case <-time.After(time.Duration(d) * time.Second):
+		return errors.New("send timeout")
+	}
+}
+
+func (p *Post) WaitReceive(d int) (string, error) {
+	select {
+	case message := <-p.Received:
+		return message, nil
+	case <-time.After(time.Duration(d) * time.Second):
+		return "", errors.New("receive timeout")
+	}
+}
+
+var PostInstance = &Post{
+	Received: make(chan string),
+	ToSend:   make(chan interface{}),
+}
diff --git a/internal/message/ws.go b/internal/message/ws.go
new file mode 100644
index 00000000000..725b71d3297
--- /dev/null
+++ b/internal/message/ws.go
@@ -0,0 +1,3 @@
+package message
+
+// TODO websocket implementation
diff --git a/server/router.go b/server/router.go
index 6334063666e..3d59fe5f15c 100644
--- a/server/router.go
+++ b/server/router.go
@@ -2,6 +2,7 @@ package server
 
 import (
 	"github.com/alist-org/alist/v3/internal/conf"
+	"github.com/alist-org/alist/v3/internal/message"
 	"github.com/alist-org/alist/v3/server/common"
 	"github.com/alist-org/alist/v3/server/controllers"
 	"github.com/alist-org/alist/v3/server/middlewares"
@@ -68,6 +69,10 @@ func Init(r *gin.Engine) {
 	task.GET("/copy/done", controllers.DoneCopyTask)
 	task.POST("/copy/cancel", controllers.CancelCopyTask)
 
+	ms := admin.Group("/message")
+	ms.GET("/get", message.PostInstance.GetHandle)
+	ms.POST("/send", message.PostInstance.SendHandle)
+
 	// guest can
 	public := api.Group("/public")
 	public.GET("/settings", controllers.PublicSettings)