add global config struct
This commit is contained in:
parent
cc429c44f9
commit
cd1e1a42f3
9 changed files with 251 additions and 214 deletions
72
api/api.go
72
api/api.go
|
|
@ -4,7 +4,7 @@ import (
|
|||
"caddydash/apic"
|
||||
"caddydash/config"
|
||||
"caddydash/db"
|
||||
"caddydash/user"
|
||||
"caddydash/gen"
|
||||
|
||||
"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)) // 读取配置(与写入一致)
|
||||
api.PUT("/config/file/:filename", PutConfig(cdb, cfg)) // 写入配置
|
||||
api.DELETE("/config/file/:filename", DeleteConfig(cdb, cfg)) //删除配置
|
||||
cfgr := api.Group("/config")
|
||||
{
|
||||
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
|
||||
api.GET("/config/files/templates", FilesTemplates(cdb)) // 获取所有模板
|
||||
api.GET("/config/files/rendered", FilesRendered(cdb)) // 获取所有渲染产物
|
||||
cfgr.GET("/files/params", FilesParams(cdb)) // 获取所有配置, 需进行decode
|
||||
cfgr.GET("/files/templates", FilesTemplates(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())
|
||||
})
|
||||
cfgr.GET("/headers-presets/:name", GetHeadersPreset())
|
||||
|
||||
api.GET("/config/headers-presets/:name", func(c *touka.Context) {
|
||||
presetName := c.Param("name")
|
||||
if presetName == "" {
|
||||
c.JSON(400, touka.H{"error": "presetName is required"})
|
||||
return
|
||||
}
|
||||
preset, found := GetHeaderSetByID(presetName)
|
||||
if !found {
|
||||
c.JSON(404, touka.H{"error": "preset not found"})
|
||||
return
|
||||
}
|
||||
c.JSON(200, preset)
|
||||
glbr := api.Group("/global")
|
||||
{
|
||||
glbr.GET("/log/levels", func(c *touka.Context) {
|
||||
c.JSON(200, gen.LogLevelList)
|
||||
})
|
||||
glbr.GET("/tls/providers", func(c *touka.Context) {
|
||||
c.JSON(200, gen.ProviderList)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// caddy实例相关
|
||||
{
|
||||
api.POST("/caddy/stop", apic.StopCaddy()) // 无需payload
|
||||
api.POST("/caddy/run", apic.StartCaddy(cfg))
|
||||
api.POST("/caddy/restart", apic.RestartCaddy(cfg))
|
||||
api.GET("/caddy/status", apic.IsCaddyRunning())
|
||||
}
|
||||
|
||||
// 鉴权相关
|
||||
auth := api.Group("/auth")
|
||||
{
|
||||
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) {
|
||||
AuthLogout(c)
|
||||
})
|
||||
auth.GET("/init", 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})
|
||||
}
|
||||
})
|
||||
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.GET("/init", AuthInitStatus())
|
||||
auth.POST("/init", AuthInitHandle(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)
|
||||
}
|
||||
}
|
||||
|
||||
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 PutConfig(cdb *db.ConfigDB, cfg *config.Config) touka.HandlerFunc {
|
||||
func GetHeadersPreset() touka.HandlerFunc {
|
||||
return func(c *touka.Context) {
|
||||
filename := c.Param("filename")
|
||||
var config gen.CaddyUniConfig
|
||||
err := c.ShouldBindJSON(&config)
|
||||
if err != nil {
|
||||
c.JSON(500, touka.H{"error": err.Error()})
|
||||
presetName := c.Param("name")
|
||||
if presetName == "" {
|
||||
c.JSON(400, touka.H{"error": "presetName is required"})
|
||||
return
|
||||
}
|
||||
var (
|
||||
paramsGOB []byte
|
||||
paramsOrigin []byte
|
||||
)
|
||||
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()})
|
||||
preset, found := GetHeaderSetByID(presetName)
|
||||
if !found {
|
||||
c.JSON(404, touka.H{"error": "preset not found"})
|
||||
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
|
||||
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
|
||||
|
||||
/*
|
||||
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 {
|
||||
var headersUp []string
|
||||
for key, values := range headers {
|
||||
|
|
@ -77,3 +53,46 @@ type CaddyUniErrorPageConfig struct {
|
|||
type CaddyUniEncodeConfig struct {
|
||||
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/sessions v0.0.1
|
||||
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
|
||||
)
|
||||
|
||||
require (
|
||||
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/fenthope/reco v0.0.3 // 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/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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
|
||||
modernc.org/libc v1.65.10 // 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/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/httpc v0.7.0 h1:iHhqlxppJBjlmvsIjvLZKRbWXqSdbeSGGofjHGmqGJc=
|
||||
github.com/WJQSERVER-STUDIO/httpc v0.7.0/go.mod h1:M7KNUZjjhCkzzcg9lBPs9YfkImI+7vqjAyjdA19+joE=
|
||||
github.com/WJQSERVER-STUDIO/httpc v0.7.1 h1:D3NlfY52pwKIOSzkdRrLinUynyKELrcPZEO8QjlBq2M=
|
||||
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/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
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.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 h1:bsqhLWFR6G6xiQcb+JoGqdKdRU6WzPWmK8E0jxTjzo4=
|
||||
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
|
||||
golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
|
||||
golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
|
||||
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/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
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/*
|
||||
Loading…
Add table
Add a link
Reference in a new issue