mirror of
https://github.com/yusing/godoxy.git
synced 2026-02-06 10:39:31 +01:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd49f1b348 | ||
|
|
953ec80556 | ||
|
|
fc540ea419 | ||
|
|
211e4ad465 | ||
|
|
0a2df3b9e3 |
@@ -1,5 +1,5 @@
|
||||
# Stage 1: deps
|
||||
FROM golang:1.25.6-alpine AS deps
|
||||
FROM golang:1.25.7-alpine AS deps
|
||||
HEALTHCHECK NONE
|
||||
|
||||
# package version does not matter
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/yusing/godoxy/agent
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
exclude (
|
||||
github.com/moby/moby/api v1.53.0 // allow older daemon versions
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.25.6-alpine AS builder
|
||||
FROM golang:1.25.7-alpine AS builder
|
||||
|
||||
HEALTHCHECK NONE
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module github.com/yusing/godoxy/cmd/bench_server
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
@@ -181,7 +181,6 @@ func newApiHandler(debugMux *debugMux) *gin.Engine {
|
||||
registerGinRoute(v1, "GET", "Route favicon", "/favicon", apiV1.FavIcon)
|
||||
registerGinRoute(v1, "GET", "Route health", "/health", apiV1.Health)
|
||||
registerGinRoute(v1, "GET", "List icons", "/icons", apiV1.Icons)
|
||||
registerGinRoute(v1, "POST", "Config reload", "/reload", apiV1.Reload)
|
||||
registerGinRoute(v1, "GET", "Route stats", "/stats", apiV1.Stats)
|
||||
|
||||
route := v1.Group("/route")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.25.6-alpine AS builder
|
||||
FROM golang:1.25.7-alpine AS builder
|
||||
|
||||
HEALTHCHECK NONE
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/yusing/godoxy/cmd/h2c_test_server
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
require golang.org/x/net v0.49.0
|
||||
|
||||
|
||||
@@ -66,6 +66,10 @@ func main() {
|
||||
|
||||
err := config.Load()
|
||||
if err != nil {
|
||||
var criticalErr config.CriticalError
|
||||
if errors.As(err, &criticalErr) {
|
||||
gperr.LogFatal("critical error in config", criticalErr)
|
||||
}
|
||||
gperr.LogWarn("errors in config", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,8 @@ services:
|
||||
user: ${GODOXY_UID:-1000}:${GODOXY_GID:-1000}
|
||||
read_only: true
|
||||
tmpfs:
|
||||
- /app/.next/cache # next image caching
|
||||
|
||||
- /tmp:rw
|
||||
- /app/node_modules/.cache:rw
|
||||
# for lite variant, do not change uid/gid
|
||||
# - /var/cache/nginx:uid=101,gid=101
|
||||
# - /run:uid=101,gid=101
|
||||
|
||||
2
go.mod
2
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/yusing/godoxy
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
exclude (
|
||||
github.com/moby/moby/api v1.53.0 // allow older daemon versions
|
||||
|
||||
@@ -76,7 +76,6 @@ func NewHandler(requireAuth bool) *gin.Engine {
|
||||
v1.GET("/favicon", apiV1.FavIcon)
|
||||
v1.GET("/health", apiV1.Health)
|
||||
v1.GET("/icons", apiV1.Icons)
|
||||
v1.POST("/reload", apiV1.Reload)
|
||||
v1.GET("/stats", apiV1.Stats)
|
||||
|
||||
route := v1.Group("/route")
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/yusing/godoxy/internal/config"
|
||||
apitypes "github.com/yusing/goutils/apitypes"
|
||||
)
|
||||
|
||||
// @x-id "reload"
|
||||
// @BasePath /api/v1
|
||||
// @Summary Reload config
|
||||
// @Description Reload config
|
||||
// @Tags v1
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} apitypes.SuccessResponse
|
||||
// @Failure 403 {object} apitypes.ErrorResponse
|
||||
// @Failure 500 {object} apitypes.ErrorResponse
|
||||
// @Router /reload [post]
|
||||
func Reload(c *gin.Context) {
|
||||
if err := config.Reload(); err != nil {
|
||||
c.Error(apitypes.InternalServerError(err, "failed to reload config"))
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, apitypes.Success("config reloaded"))
|
||||
}
|
||||
@@ -60,6 +60,16 @@ func Load() error {
|
||||
|
||||
cfgWatcher = watcher.NewConfigFileWatcher(common.ConfigFileName)
|
||||
|
||||
initErr := state.InitFromFile(common.ConfigPath)
|
||||
if initErr != nil {
|
||||
// if error is critical, notify and return it without starting providers
|
||||
var criticalErr CriticalError
|
||||
if errors.As(initErr, &criticalErr) {
|
||||
logNotifyError("init", criticalErr.err)
|
||||
return criticalErr.err
|
||||
}
|
||||
}
|
||||
|
||||
// disable pool logging temporary since we already have pretty logging
|
||||
routes.HTTP.DisableLog(true)
|
||||
routes.Stream.DisableLog(true)
|
||||
|
||||
@@ -50,6 +50,18 @@ type state struct {
|
||||
tmpLog zerolog.Logger
|
||||
}
|
||||
|
||||
type CriticalError struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (e CriticalError) Error() string {
|
||||
return e.err.Error()
|
||||
}
|
||||
|
||||
func (e CriticalError) Unwrap() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func NewState() config.State {
|
||||
tmpLogBuf := bytes.NewBuffer(make([]byte, 0, 4096))
|
||||
return &state{
|
||||
@@ -96,7 +108,7 @@ func (state *state) InitFromFile(filename string) error {
|
||||
if errors.Is(err, fs.ErrNotExist) {
|
||||
state.Config = config.DefaultConfig()
|
||||
} else {
|
||||
return err
|
||||
return CriticalError{err}
|
||||
}
|
||||
}
|
||||
return state.Init(data)
|
||||
@@ -105,7 +117,7 @@ func (state *state) InitFromFile(filename string) error {
|
||||
func (state *state) Init(data []byte) error {
|
||||
err := serialization.UnmarshalValidate(data, &state.Config, yaml.Unmarshal)
|
||||
if err != nil {
|
||||
return err
|
||||
return CriticalError{err}
|
||||
}
|
||||
|
||||
g := gperr.NewGroup("config load error")
|
||||
@@ -117,7 +129,9 @@ func (state *state) Init(data []byte) error {
|
||||
// these won't benefit from running on goroutines
|
||||
errs.Add(state.initNotification())
|
||||
errs.Add(state.initACL())
|
||||
errs.Add(state.initEntrypoint())
|
||||
if err := state.initEntrypoint(); err != nil {
|
||||
errs.Add(CriticalError{err})
|
||||
}
|
||||
errs.Add(state.loadRouteProviders())
|
||||
return errs.Error()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/yusing/godoxy/internal/dnsproviders
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
replace github.com/yusing/godoxy => ../..
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ type Entrypoint struct {
|
||||
notFoundHandler http.Handler
|
||||
accessLogger accesslog.AccessLogger
|
||||
findRouteFunc func(host string) types.HTTPRoute
|
||||
shortLinkTree *ShortLinkMatcher
|
||||
shortLinkMatcher *ShortLinkMatcher
|
||||
}
|
||||
|
||||
// nil-safe
|
||||
@@ -36,12 +36,12 @@ func init() {
|
||||
func NewEntrypoint() Entrypoint {
|
||||
return Entrypoint{
|
||||
findRouteFunc: findRouteAnyDomain,
|
||||
shortLinkTree: newShortLinkTree(),
|
||||
shortLinkMatcher: newShortLinkMatcher(),
|
||||
}
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) ShortLinkMatcher() *ShortLinkMatcher {
|
||||
return ep.shortLinkTree
|
||||
return ep.shortLinkMatcher
|
||||
}
|
||||
|
||||
func (ep *Entrypoint) SetFindRouteDomains(domains []string) {
|
||||
@@ -130,9 +130,9 @@ func (ep *Entrypoint) tryHandleShortLink(w http.ResponseWriter, r *http.Request)
|
||||
}
|
||||
if strings.EqualFold(host, common.ShortLinkPrefix) {
|
||||
if ep.middleware != nil {
|
||||
ep.middleware.ServeHTTP(ep.shortLinkTree.ServeHTTP, w, r)
|
||||
ep.middleware.ServeHTTP(ep.shortLinkMatcher.ServeHTTP, w, r)
|
||||
} else {
|
||||
ep.shortLinkTree.ServeHTTP(w, r)
|
||||
ep.shortLinkMatcher.ServeHTTP(w, r)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ type ShortLinkMatcher struct {
|
||||
subdomainRoutes *xsync.Map[string, struct{}]
|
||||
}
|
||||
|
||||
func newShortLinkTree() *ShortLinkMatcher {
|
||||
func newShortLinkMatcher() *ShortLinkMatcher {
|
||||
return &ShortLinkMatcher{
|
||||
fqdnRoutes: xsync.NewMap[string, string](),
|
||||
subdomainRoutes: xsync.NewMap[string, struct{}](),
|
||||
|
||||
@@ -3,12 +3,19 @@
|
||||
do: pass
|
||||
- name: protected
|
||||
on: |
|
||||
!path regex("(_next/static|_next/image|favicon.ico).*")
|
||||
!path glob("/api/v1/auth/*")
|
||||
!path glob("/auth/*")
|
||||
!path regex("[A-Za-z0-9_-]+\.(svg|png|jpg|jpeg|gif|ico|webp|woff2?|eot|ttf|otf|txt)(\?.+)?")
|
||||
!path /icon0.svg
|
||||
!path /favicon.ico
|
||||
!path /apple-icon.png
|
||||
!path glob("/web-app-manifest-*x*.png")
|
||||
!path regex("\/assets\/(chunks\/)?[a-zA-Z0-9\-_]+\.(css|js|woff2)")
|
||||
!path regex("\/assets\/workbox-window\.prod\.es5-[a-zA-Z0-9]+\.js")
|
||||
!path regex("/workbox-[a-zA-Z0-9]+\.js")
|
||||
!path /api/v1/version
|
||||
!path /manifest.json
|
||||
!path /manifest.webmanifest
|
||||
!path /sw.js
|
||||
!path /registerSW.js
|
||||
do: require_auth
|
||||
- name: proxy to backend
|
||||
on: path glob("/api/v1/*")
|
||||
|
||||
24
internal/route/rules/presets/webui_dev.yml
Normal file
24
internal/route/rules/presets/webui_dev.yml
Normal file
@@ -0,0 +1,24 @@
|
||||
- name: login page
|
||||
on: path /login
|
||||
do: pass
|
||||
- name: protected
|
||||
on: |
|
||||
!path glob("@tanstack-start/*")
|
||||
!path /@react-refresh
|
||||
!path /@vite/client
|
||||
!path regex("\?token=\w{5}-\w{5}")
|
||||
!path glob("/@id/*")
|
||||
!path glob("/api/v1/auth/*")
|
||||
!path glob("/auth/*")
|
||||
!path regex("[A-Za-z0-9_\-/]+\.(css|ts|js|mjs|svg|png|jpg|jpeg|gif|ico|webp|woff2?|eot|ttf|otf|txt)(\?.+)?")
|
||||
!path /api/v1/version
|
||||
!path /manifest.webmanifest
|
||||
do: require_auth
|
||||
- name: proxy to backend
|
||||
on: path glob("/api/v1/*")
|
||||
do: proxy http://${API_ADDR}/
|
||||
- name: proxy to auth api
|
||||
on: path glob("/auth/*")
|
||||
do: |
|
||||
rewrite /auth /api/v1/auth
|
||||
proxy http://${API_ADDR}/
|
||||
@@ -1,5 +1,5 @@
|
||||
# Stage 1: deps
|
||||
FROM golang:1.25.6-alpine AS deps
|
||||
FROM golang:1.25.7-alpine AS deps
|
||||
HEALTHCHECK NONE
|
||||
|
||||
# package version does not matter
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module github.com/yusing/godoxy/socketproxy
|
||||
|
||||
go 1.25.6
|
||||
go 1.25.7
|
||||
|
||||
replace github.com/yusing/goutils => ../goutils
|
||||
|
||||
|
||||
Reference in New Issue
Block a user