add global config struct
This commit is contained in:
parent
cc429c44f9
commit
cd1e1a42f3
9 changed files with 251 additions and 214 deletions
84
api/api.go
84
api/api.go
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"caddydash/apic"
|
"caddydash/apic"
|
||||||
"caddydash/config"
|
"caddydash/config"
|
||||||
"caddydash/db"
|
"caddydash/db"
|
||||||
"caddydash/user"
|
"caddydash/gen"
|
||||||
|
|
||||||
"github.com/infinite-iroha/touka"
|
"github.com/infinite-iroha/touka"
|
||||||
)
|
)
|
||||||
|
|
@ -21,40 +21,43 @@ func ApiGroup(v0 touka.IRouter, cdb *db.ConfigDB, cfg *config.Config) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// 配置参数相关
|
// 配置参数相关
|
||||||
api.GET("/config/file/:filename", GetConfig(cdb)) // 读取配置(与写入一致)
|
cfgr := api.Group("/config")
|
||||||
api.PUT("/config/file/:filename", PutConfig(cdb, cfg)) // 写入配置
|
{
|
||||||
api.DELETE("/config/file/:filename", DeleteConfig(cdb, cfg)) //删除配置
|
cfgr.GET("/file/:filename", GetConfig(cdb)) // 读取配置(与写入一致)
|
||||||
|
cfgr.PUT("/file/:filename", PutConfig(cdb, cfg)) // 写入配置
|
||||||
|
cfgr.DELETE("/file/:filename", DeleteConfig(cdb, cfg)) //删除配置
|
||||||
|
|
||||||
api.GET("/config/files/params", FilesParams(cdb)) // 获取所有配置, 需进行decode
|
cfgr.GET("/files/params", FilesParams(cdb)) // 获取所有配置, 需进行decode
|
||||||
api.GET("/config/files/templates", FilesTemplates(cdb)) // 获取所有模板
|
cfgr.GET("/files/templates", FilesTemplates(cdb)) // 获取所有模板
|
||||||
api.GET("/config/files/rendered", FilesRendered(cdb)) // 获取所有渲染产物
|
cfgr.GET("/files/rendered", FilesRendered(cdb)) // 获取所有渲染产物
|
||||||
|
|
||||||
api.GET("/config/templates", GetTemplates(cdb)) // 获取可用模板名称
|
cfgr.GET("/templates", GetTemplates(cdb)) // 获取可用模板名称
|
||||||
|
|
||||||
api.GET("/config/headers-presets", func(c *touka.Context) {
|
cfgr.GET("/headers-presets", func(c *touka.Context) {
|
||||||
c.JSON(200, GetHeaderSetMetadataList())
|
c.JSON(200, GetHeaderSetMetadataList())
|
||||||
})
|
})
|
||||||
|
cfgr.GET("/headers-presets/:name", GetHeadersPreset())
|
||||||
|
|
||||||
api.GET("/config/headers-presets/:name", func(c *touka.Context) {
|
glbr := api.Group("/global")
|
||||||
presetName := c.Param("name")
|
{
|
||||||
if presetName == "" {
|
glbr.GET("/log/levels", func(c *touka.Context) {
|
||||||
c.JSON(400, touka.H{"error": "presetName is required"})
|
c.JSON(200, gen.LogLevelList)
|
||||||
return
|
})
|
||||||
|
glbr.GET("/tls/providers", func(c *touka.Context) {
|
||||||
|
c.JSON(200, gen.ProviderList)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
preset, found := GetHeaderSetByID(presetName)
|
}
|
||||||
if !found {
|
|
||||||
c.JSON(404, touka.H{"error": "preset not found"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(200, preset)
|
|
||||||
})
|
|
||||||
|
|
||||||
// caddy实例相关
|
// caddy实例相关
|
||||||
api.POST("/caddy/stop", apic.StopCaddy()) // 无需payload
|
{
|
||||||
api.POST("/caddy/run", apic.StartCaddy(cfg))
|
api.POST("/caddy/stop", apic.StopCaddy()) // 无需payload
|
||||||
api.POST("/caddy/restart", apic.RestartCaddy(cfg))
|
api.POST("/caddy/run", apic.StartCaddy(cfg))
|
||||||
api.GET("/caddy/status", apic.IsCaddyRunning())
|
api.POST("/caddy/restart", apic.RestartCaddy(cfg))
|
||||||
|
api.GET("/caddy/status", apic.IsCaddyRunning())
|
||||||
|
}
|
||||||
|
|
||||||
|
// 鉴权相关
|
||||||
auth := api.Group("/auth")
|
auth := api.Group("/auth")
|
||||||
{
|
{
|
||||||
auth.POST("/login", func(c *touka.Context) {
|
auth.POST("/login", func(c *touka.Context) {
|
||||||
|
|
@ -66,31 +69,8 @@ func ApiGroup(v0 touka.IRouter, cdb *db.ConfigDB, cfg *config.Config) {
|
||||||
auth.GET("/logout", func(c *touka.Context) {
|
auth.GET("/logout", func(c *touka.Context) {
|
||||||
AuthLogout(c)
|
AuthLogout(c)
|
||||||
})
|
})
|
||||||
auth.GET("/init", func(c *touka.Context) {
|
auth.GET("/init", AuthInitStatus())
|
||||||
// 返回是否init管理员
|
auth.POST("/init", AuthInitHandle(cdb))
|
||||||
isInit := user.IsAdminInit()
|
|
||||||
if isInit {
|
|
||||||
c.JSON(200, touka.H{"admin_init": true})
|
|
||||||
} else {
|
|
||||||
c.JSON(200, touka.H{"admin_init": false})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
auth.POST("/init", func(c *touka.Context) {
|
|
||||||
username := c.PostForm("username")
|
|
||||||
password := c.PostForm("password")
|
|
||||||
// 验证是否为空
|
|
||||||
if username == "" || password == "" {
|
|
||||||
c.JSON(400, touka.H{"error": "username and password are required"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 初始化管理员
|
|
||||||
err := user.InitAdminUser(username, password, cdb)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.JSON(200, touka.H{"message": "admin initialized"})
|
|
||||||
})
|
|
||||||
auth.POST("resetpwd", ResetPassword(cdb))
|
auth.POST("resetpwd", ResetPassword(cdb))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
api/auth.go
31
api/auth.go
|
|
@ -183,3 +183,34 @@ func ResetPassword(cdb *db.ConfigDB) touka.HandlerFunc {
|
||||||
AuthLogout(c)
|
AuthLogout(c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func AuthInitHandle(cdb *db.ConfigDB) touka.HandlerFunc {
|
||||||
|
return func(c *touka.Context) {
|
||||||
|
username := c.PostForm("username")
|
||||||
|
password := c.PostForm("password")
|
||||||
|
// 验证是否为空
|
||||||
|
if username == "" || password == "" {
|
||||||
|
c.JSON(400, touka.H{"error": "username and password are required"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 初始化管理员
|
||||||
|
err := user.InitAdminUser(username, password, cdb)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(500, touka.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(200, touka.H{"message": "admin initialized"})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func AuthInitStatus() touka.HandlerFunc {
|
||||||
|
return func(c *touka.Context) {
|
||||||
|
// 返回是否init管理员
|
||||||
|
isInit := user.IsAdminInit()
|
||||||
|
if isInit {
|
||||||
|
c.JSON(200, touka.H{"admin_init": true})
|
||||||
|
} else {
|
||||||
|
c.JSON(200, touka.H{"admin_init": false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
105
api/config.go
105
api/config.go
|
|
@ -119,107 +119,18 @@ func DeleteConfig(cdb *db.ConfigDB, cfg *config.Config) touka.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
func GetHeadersPreset() touka.HandlerFunc {
|
||||||
func PutConfig(cdb *db.ConfigDB, cfg *config.Config) touka.HandlerFunc {
|
|
||||||
return func(c *touka.Context) {
|
return func(c *touka.Context) {
|
||||||
filename := c.Param("filename")
|
presetName := c.Param("name")
|
||||||
var config gen.CaddyUniConfig
|
if presetName == "" {
|
||||||
err := c.ShouldBindJSON(&config)
|
c.JSON(400, touka.H{"error": "presetName is required"})
|
||||||
if err != nil {
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var (
|
preset, found := GetHeaderSetByID(presetName)
|
||||||
paramsGOB []byte
|
if !found {
|
||||||
paramsOrigin []byte
|
c.JSON(404, touka.H{"error": "preset not found"})
|
||||||
)
|
|
||||||
switch config.TmplType {
|
|
||||||
case "file_server":
|
|
||||||
caddyfscfg := gen.CaddyFileServerConfig{
|
|
||||||
Domain: config.Domain,
|
|
||||||
FileDirPath: config.FileServer.FileDirPath,
|
|
||||||
EnableBrowser: config.FileServer.EnableBrowser,
|
|
||||||
Headers: gen.HeadersMapToHeadersUp(config.Headers),
|
|
||||||
EnableLog: config.Log.EnableLog,
|
|
||||||
LogDomain: config.Log.LogDomain,
|
|
||||||
EnableErrorPage: config.ErrorPage.EnableErrorPage,
|
|
||||||
EnableEncode: config.Encode.EnableEncode,
|
|
||||||
}
|
|
||||||
paramsGOB, err = gen.EncodeGobConfig(caddyfscfg)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("encode gob config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 把json变为gob []byte
|
|
||||||
paramsOrigin, err = gen.EncodeGobConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("encode origin config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
paramsEntry := db.ParamsEntry{
|
|
||||||
Filename: filename,
|
|
||||||
TemplateType: config.TmplType,
|
|
||||||
ParamsGOB: paramsGOB,
|
|
||||||
ParamsOrigin: paramsOrigin,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WriteConfig(cdb, paramsEntry, cfg, filename)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("write config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(200, touka.H{"message": "config saved and rendered"})
|
|
||||||
return
|
|
||||||
|
|
||||||
case "reverse_proxy":
|
|
||||||
caddyrpCfg := gen.CaddyReverseProxyConfig{
|
|
||||||
Domain: config.Domain,
|
|
||||||
ReverseProxy: config.UpStream.UpStream,
|
|
||||||
Headers: gen.HeadersMapToHeadersUp(config.Headers),
|
|
||||||
HeadersUp: gen.HeadersMapToHeadersUp(config.UpStream.UpStreamHeaders),
|
|
||||||
EnableLog: config.Log.EnableLog,
|
|
||||||
LogDomain: config.Log.LogDomain,
|
|
||||||
EnableErrorPage: config.ErrorPage.EnableErrorPage,
|
|
||||||
EnableEncode: config.Encode.EnableEncode,
|
|
||||||
}
|
|
||||||
paramsGOB, err = gen.EncodeGobConfig(caddyrpCfg)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("encode gob config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// 把json变为gob []byte
|
|
||||||
paramsOrigin, err = gen.EncodeGobConfig(config)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("encode origin config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
paramsEntry := db.ParamsEntry{
|
|
||||||
Filename: filename,
|
|
||||||
TemplateType: config.TmplType,
|
|
||||||
ParamsGOB: paramsGOB,
|
|
||||||
ParamsOrigin: paramsOrigin,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = WriteConfig(cdb, paramsEntry, cfg, filename)
|
|
||||||
if err != nil {
|
|
||||||
c.Warnf("write config error: %v", err)
|
|
||||||
c.JSON(500, touka.H{"error": err.Error()})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(200, touka.H{"message": "config saved and rendered"})
|
|
||||||
return
|
|
||||||
|
|
||||||
default:
|
|
||||||
c.JSON(500, touka.H{"error": "unknown template type"})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
c.JSON(200, preset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
||||||
1
api/global.go
Normal file
1
api/global.go
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
package api
|
||||||
|
|
@ -1,29 +1,5 @@
|
||||||
package gen
|
package gen
|
||||||
|
|
||||||
/*
|
|
||||||
type CaddyReverseProxyConfig struct {
|
|
||||||
Domain string // 域名; 例如 example.com
|
|
||||||
ReverseProxy string // 反向代理目标; 例如 127.0.0.1:8080 (这里简化为单个目标)
|
|
||||||
Headers []string // 自定义响应Header
|
|
||||||
HeadersUp []string // 自定义请求头列表; 例如 ["XXX0 XX", "XXX1 XXX"]
|
|
||||||
EnableLog bool // 是否导入 log 指令
|
|
||||||
LogDomain string // log 指令的域名参数
|
|
||||||
EnableErrorPage bool // 是否导入 error_page 指令
|
|
||||||
EnableEncode bool // 是否导入 encode 指令
|
|
||||||
}
|
|
||||||
|
|
||||||
type CaddyFileServerConfig struct {
|
|
||||||
Domain string // 域名; 例如 example.com
|
|
||||||
FileDirPath string // 文件目录
|
|
||||||
EnableBrowser bool // 是否导入 browse 指令
|
|
||||||
Headers []string //
|
|
||||||
EnableLog bool // 是否导入 log 指令
|
|
||||||
LogDomain string // log 指令的域名参数
|
|
||||||
EnableErrorPage bool // 是否导入 error_page 指令
|
|
||||||
EnableEncode bool // 是否导入 encode 指令
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func HeadersMapToHeadersUp(headers map[string][]string) []string {
|
func HeadersMapToHeadersUp(headers map[string][]string) []string {
|
||||||
var headersUp []string
|
var headersUp []string
|
||||||
for key, values := range headers {
|
for key, values := range headers {
|
||||||
|
|
@ -77,3 +53,46 @@ type CaddyUniErrorPageConfig struct {
|
||||||
type CaddyUniEncodeConfig struct {
|
type CaddyUniEncodeConfig struct {
|
||||||
EnableEncode bool `json:"enable_encode"`
|
EnableEncode bool `json:"enable_encode"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CaddyGlobalConfig struct {
|
||||||
|
Debug bool `json:"debug"`
|
||||||
|
PortsConfig CaddyGlobalPortsConfig `json:"ports_config"`
|
||||||
|
Metrics bool `json:"metrics"`
|
||||||
|
LogConfig CaddyGlobalLogConfig `json:"log_config"`
|
||||||
|
TLSConfig CaddyGlobalTLSConfig `json:"tls_config"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyGlobalPortsConfig struct {
|
||||||
|
AdminPort string `json:"admin_port"`
|
||||||
|
HTTPPort uint16 `json:"http_port"`
|
||||||
|
HTTPSPort uint16 `json:"https_port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyGlobalLogConfig struct {
|
||||||
|
Level string `json:"level"`
|
||||||
|
// 日志滚动配置
|
||||||
|
RotateSize string `json:"rotate_size"`
|
||||||
|
RotateKeep string `json:"rotate_keep"`
|
||||||
|
RotateKeepForTime string `json:"rotate_keep_for_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 维护一个日志等级列表
|
||||||
|
// Possible levels: DEBUG, INFO, WARN, ERROR, PANIC, and FATAL
|
||||||
|
var LogLevelList = map[string]struct{}{
|
||||||
|
"DEBUG": {},
|
||||||
|
"INFO": {},
|
||||||
|
"WARN": {},
|
||||||
|
"ERROR": {},
|
||||||
|
"PANIC": {},
|
||||||
|
"FATAL": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
type CaddyGlobalTLSConfig struct {
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// 维护一个提供商列表
|
||||||
|
var ProviderList = map[string]struct{}{
|
||||||
|
"cloudflare": {},
|
||||||
|
}
|
||||||
|
|
|
||||||
6
go.mod
6
go.mod
|
|
@ -7,13 +7,13 @@ require (
|
||||||
github.com/fenthope/record v0.0.3
|
github.com/fenthope/record v0.0.3
|
||||||
github.com/fenthope/sessions v0.0.1
|
github.com/fenthope/sessions v0.0.1
|
||||||
github.com/infinite-iroha/touka v0.2.2
|
github.com/infinite-iroha/touka v0.2.2
|
||||||
golang.org/x/crypto v0.37.0
|
golang.org/x/crypto v0.39.0
|
||||||
modernc.org/sqlite v1.38.0
|
modernc.org/sqlite v1.38.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4 // indirect
|
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4 // indirect
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0 // indirect
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fenthope/reco v0.0.3 // indirect
|
github.com/fenthope/reco v0.0.3 // indirect
|
||||||
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 // indirect
|
github.com/go-json-experiment/json v0.0.0-20250517221953-25912455fbc8 // indirect
|
||||||
|
|
@ -25,7 +25,7 @@ require (
|
||||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/sys v0.33.0 // indirect
|
||||||
modernc.org/libc v1.65.10 // indirect
|
modernc.org/libc v1.65.10 // indirect
|
||||||
modernc.org/mathutil v1.7.1 // indirect
|
modernc.org/mathutil v1.7.1 // indirect
|
||||||
|
|
|
||||||
12
go.sum
12
go.sum
|
|
@ -2,8 +2,8 @@ github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg
|
||||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||||
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4 h1:JLtFd00AdFg/TP+dtvIzLkdHwKUGPOAijN1sMtEYoFg=
|
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4 h1:JLtFd00AdFg/TP+dtvIzLkdHwKUGPOAijN1sMtEYoFg=
|
||||||
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4/go.mod h1:FZ6XE+4TKy4MOfX1xWKe6Rwsg0ucYFCdNh1KLvyKTfc=
|
github.com/WJQSERVER-STUDIO/go-utils/copyb v0.0.4/go.mod h1:FZ6XE+4TKy4MOfX1xWKe6Rwsg0ucYFCdNh1KLvyKTfc=
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0 h1:iHhqlxppJBjlmvsIjvLZKRbWXqSdbeSGGofjHGmqGJc=
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1 h1:D3NlfY52pwKIOSzkdRrLinUynyKELrcPZEO8QjlBq2M=
|
||||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
github.com/WJQSERVER-STUDIO/httpc v0.7.1/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
||||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
github.com/fenthope/reco v0.0.3 h1:RmnQ0D9a8PWtwOODawitTe4BztTnS9wYwrDbipISNq4=
|
github.com/fenthope/reco v0.0.3 h1:RmnQ0D9a8PWtwOODawitTe4BztTnS9wYwrDbipISNq4=
|
||||||
|
|
@ -34,10 +34,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||||
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
|
||||||
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8=
|
||||||
|
|
|
||||||
95
gtmpl/caddyfile
Normal file
95
gtmpl/caddyfile
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
{
|
||||||
|
debug
|
||||||
|
admin :2019
|
||||||
|
http_port 80
|
||||||
|
https_port 443
|
||||||
|
metrics
|
||||||
|
order ja4h_header first
|
||||||
|
order webdav before file_server
|
||||||
|
order cache before rewrite
|
||||||
|
cache {
|
||||||
|
cache_name CaddyCache
|
||||||
|
}
|
||||||
|
log {
|
||||||
|
level INFO
|
||||||
|
output file ./log/caddy.log {
|
||||||
|
roll_size 10MB
|
||||||
|
roll_keep 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(log) {
|
||||||
|
log {
|
||||||
|
format transform `{request>headers>X-Forwarded-For>[0]:request>remote_ip} - {user_id} [{ts}] "{request>method} {request>uri} {request>proto}" {status} {size} "{request>headers>Referer>[0]}" "{request>headers>User-Agent>[0]}"` {
|
||||||
|
time_format "02/Jan/2006:15:04:05 -0700"
|
||||||
|
}
|
||||||
|
output file ./log/{args[0]}/access.log {
|
||||||
|
roll_size 10MB
|
||||||
|
roll_keep 10
|
||||||
|
roll_keep_for 24h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(error_page) {
|
||||||
|
handle_errors {
|
||||||
|
rewrite * /{err.status_code}.html
|
||||||
|
root * ./pages/errors
|
||||||
|
file_server
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(encode) {
|
||||||
|
encode {
|
||||||
|
zstd
|
||||||
|
br
|
||||||
|
gzip
|
||||||
|
minimum_length 512
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(cache) {
|
||||||
|
cache {
|
||||||
|
allowed_http_verbs GET
|
||||||
|
stale {args[0]}
|
||||||
|
ttl {args[1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(header_realip_cf) {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
header_up X-Real-IP {http.request.header.CF-Connecting-IP}
|
||||||
|
header_up X-Forwarded-For {http.request.header.CF-Connecting-IP}
|
||||||
|
header_up X-Forwarded-Proto {http.request.header.CF-Visitor}
|
||||||
|
}
|
||||||
|
|
||||||
|
(header_realip) {
|
||||||
|
header_up X-Real-IP {remote_host}
|
||||||
|
header_up X-Forwarded-For {remote_host}
|
||||||
|
header_up X-Forwarded-Proto {scheme}
|
||||||
|
}
|
||||||
|
|
||||||
|
(tls) {
|
||||||
|
tls {
|
||||||
|
dns {args[0]} {args[1]}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(rate_limit) {
|
||||||
|
route /* {
|
||||||
|
rate_limit {remote.ip} {args[0]}r/m 10000 429
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(route_nocache) {
|
||||||
|
route {args[0]} {
|
||||||
|
rate_limit {remote.ip} {args[1]}r/m 10000 429
|
||||||
|
cache {
|
||||||
|
stale 0s
|
||||||
|
ttl 0s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
import ./config.d/*
|
||||||
64
tmpl/uni
64
tmpl/uni
|
|
@ -1,42 +1,42 @@
|
||||||
{{- if .DomainConfig.MutiDomains -}}
|
{{- if .DomainConfig.MutiDomains -}}
|
||||||
{{- range $i, $domain := .DomainConfig.Domains -}}
|
{{- range $i, $domain := .DomainConfig.Domains -}}
|
||||||
{{- if $i}} {{" "}}{{- end -}}
|
{{- if $i}} {{" "}}{{- end -}}
|
||||||
{{- . -}}
|
{{- . -}}
|
||||||
{{- end -}} {
|
{{- end -}} {
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
{{- .DomainConfig.Domain}} {
|
{{- .DomainConfig.Domain}} {
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|
||||||
{{- if .Upstream.EnableUpStream}}
|
{{- if .Upstream.EnableUpStream}}
|
||||||
reverse_proxy {
|
reverse_proxy {
|
||||||
to{{if .Upstream.MutiUpStreams}}{{range .Upstream.UpStreams}} {{.}}{{end}}{{else}} {{.Upstream.UpStream}}{{end}}
|
to{{if .Upstream.MutiUpStreams}}{{range .Upstream.UpStreams}} {{.}}{{end}}{{else}} {{.Upstream.UpStream}}{{end}}
|
||||||
|
|
||||||
{{- range $key, $values := .Upstream.UpStreamHeaders}}
|
{{- range $key, $values := .Upstream.UpStreamHeaders}}
|
||||||
{{- range $values}}
|
{{- range $values}}
|
||||||
header_up {{$key}} "{{.}}"
|
header_up {{$key}} "{{.}}"
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
}
|
}
|
||||||
{{- else if .FileServer.EnableFileServer}}
|
{{- else if .FileServer.EnableFileServer}}
|
||||||
root * {{.FileServer.FileDirPath}}
|
root * {{.FileServer.FileDirPath}}
|
||||||
file_server{{if .FileServer.EnableBrowser}} browse{{end}}
|
file_server{{if .FileServer.EnableBrowser}} browse{{end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
{{- range $key, $values := .Headers}}
|
{{- range $key, $values := .Headers}}
|
||||||
{{- range $values}}
|
{{- range $values}}
|
||||||
header {{$key}} "{{.}}"
|
header {{$key}} "{{.}}"
|
||||||
{{- end}}
|
{{- end}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
{{- if .Log.EnableLog}}
|
{{- if .Log.EnableLog}}
|
||||||
import log {{.Log.LogDomain}}
|
import log {{.Log.LogDomain}}
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
{{- if .ErrorPage.EnableErrorPage}}
|
{{- if .ErrorPage.EnableErrorPage}}
|
||||||
import error_page
|
import error_page
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
{{- if .Encode.EnableEncode}}
|
{{- if .Encode.EnableEncode}}
|
||||||
import encode
|
import encode
|
||||||
{{- end}}
|
{{- end}}
|
||||||
}
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue