Compare commits

...

5 Commits

Author SHA1 Message Date
yusing
6a8f6fb4b5 chore(accesslog): reduce buffering for stdout 2025-04-26 08:29:55 +08:00
yusing
8f20bd3840 fix(acl): caching logic 2025-04-26 08:05:26 +08:00
yusing
f1abb745fe fix(tcp): return a dummy connection instead of nil 2025-04-26 07:57:20 +08:00
yusing
cb2990f6e8 chore: enrich example config 2025-04-26 07:40:55 +08:00
yusing
fb2f850311 fix(oidc): incorrect redirect url 2025-04-26 06:57:02 +08:00
7 changed files with 55 additions and 30 deletions

View File

@@ -1,3 +1,6 @@
# docker image tag (latest, nightly)
TAG=latest
# set timezone to get correct log timestamp
TZ=ETC/UTC
@@ -47,8 +50,12 @@ GODOXY_API_ADDR=127.0.0.1:8888
# Frontend listening port
GODOXY_FRONTEND_PORT=3000
# Prometheus Metrics
GODOXY_PROMETHEUS_ENABLED=true
# Frontend aliases (subdomains / FQDNs, e.g. godoxy, godoxy.domain.com)
GODOXY_FRONTEND_ALIASES=godoxy
# Docker socket
# /var/run/podman/podman.sock for podman
DOCKER_SOCKET=/var/run/docker.sock
# Debug mode
GODOXY_DEBUG=false

View File

@@ -1,7 +1,7 @@
---
services:
frontend:
image: ghcr.io/yusing/godoxy-frontend:latest
image: ghcr.io/yusing/godoxy-frontend:${TAG:-latest}
container_name: godoxy-frontend
restart: unless-stopped
network_mode: host # do not change this
@@ -13,7 +13,7 @@ services:
# modify below to fit your needs
labels:
proxy.aliases: godoxy
proxy.aliases: ${GODOXY_FRONTEND_ALIASES:-godoxy}
proxy.godoxy.port: ${GODOXY_FRONTEND_PORT:-3000}
# proxy.godoxy.middlewares.cidr_whitelist: |
# status: 403
@@ -24,13 +24,13 @@ services:
# - 192.168.0.0/16
# - 172.16.0.0/12
app:
image: ghcr.io/yusing/godoxy:latest
image: ghcr.io/yusing/godoxy:${TAG:-latest}
container_name: godoxy
restart: always
network_mode: host # do not change this
env_file: .env
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ${DOCKER_SOCKET:-/var/run/docker.sock}:/var/run/docker.sock
- ./config:/app/config
- ./logs:/app/logs
- ./error_pages:/app/error_pages

View File

@@ -3,11 +3,9 @@ package acl
import (
"github.com/puzpuzpuz/xsync/v3"
acl "github.com/yusing/go-proxy/internal/acl/types"
"go.uber.org/atomic"
)
var cityCache = xsync.NewMapOf[string, *acl.City]()
var numCachedLookup atomic.Uint64
func (cfg *MaxMindConfig) lookupCity(ip *acl.IPInfo) (*acl.City, bool) {
if ip.City != nil {
@@ -20,7 +18,7 @@ func (cfg *MaxMindConfig) lookupCity(ip *acl.IPInfo) (*acl.City, bool) {
city, ok := cityCache.Load(ip.Str)
if ok {
numCachedLookup.Inc()
ip.City = city
return city, true
}

View File

@@ -63,7 +63,7 @@ type checkCache struct {
const cacheTTL = 1 * time.Minute
func (c *checkCache) Expired() bool {
return c.created.Add(cacheTTL).After(utils.TimeNow())
return c.created.Add(cacheTTL).Before(utils.TimeNow())
}
//TODO: add stats

View File

@@ -1,7 +1,9 @@
package acl
import (
"io"
"net"
"time"
)
type TCPListener struct {
@@ -9,6 +11,17 @@ type TCPListener struct {
lis net.Listener
}
type noConn struct{}
func (noConn) Read(b []byte) (int, error) { return 0, io.EOF }
func (noConn) Write(b []byte) (int, error) { return 0, io.EOF }
func (noConn) Close() error { return nil }
func (noConn) LocalAddr() net.Addr { return nil }
func (noConn) RemoteAddr() net.Addr { return nil }
func (noConn) SetDeadline(t time.Time) error { return nil }
func (noConn) SetReadDeadline(t time.Time) error { return nil }
func (noConn) SetWriteDeadline(t time.Time) error { return nil }
func (cfg *Config) WrapTCP(lis net.Listener) net.Listener {
if cfg == nil {
return lis
@@ -32,11 +45,11 @@ func (s *TCPListener) Accept() (net.Conn, error) {
if !ok {
// Not a TCPAddr, drop
c.Close()
return nil, nil
return noConn{}, nil
}
if !s.acl.IPAllowed(addr.IP) {
c.Close()
return nil, nil
return noConn{}, nil
}
return c, nil
}

View File

@@ -53,7 +53,7 @@ func RequireAuth(next http.HandlerFunc) http.HandlerFunc {
func AuthCheckHandler(w http.ResponseWriter, r *http.Request) {
if err := defaultAuth.CheckToken(r); err != nil {
http.Redirect(w, r, "/v1/auth/login", http.StatusFound)
defaultAuth.LoginHandler(w, r)
} else {
w.WriteHeader(http.StatusOK)
}

View File

@@ -4,6 +4,7 @@ import (
"bufio"
"io"
"net/http"
"os"
"sync"
"time"
@@ -53,6 +54,7 @@ type (
)
const (
StdoutbufSize = 64
MinBufferSize = 4 * kilobyte
MaxBufferSize = 1 * megabyte
)
@@ -79,6 +81,22 @@ func NewMockAccessLogger(parent task.Parent, cfg *RequestLoggerConfig) *AccessLo
return NewAccessLoggerWithIO(parent, NewMockFile(), cfg)
}
func unwrap[Writer any](w io.Writer) []Writer {
var result []Writer
if unwrapped, ok := w.(MultiWriterInterface); ok {
for _, w := range unwrapped.Unwrap() {
if unwrapped, ok := w.(Writer); ok {
result = append(result, unwrapped)
}
}
return result
}
if unwrapped, ok := w.(Writer); ok {
return []Writer{unwrapped}
}
return nil
}
func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg AnyConfig) *AccessLogger {
cfg := anyCfg.ToConfig()
if cfg.BufferSize == 0 {
@@ -90,6 +108,10 @@ func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg Any
if cfg.BufferSize > MaxBufferSize {
cfg.BufferSize = MaxBufferSize
}
if _, ok := writer.(*os.File); ok {
cfg.BufferSize = StdoutbufSize
}
l := &AccessLogger{
task: parent.Subtask("accesslog."+writer.Name(), true),
cfg: cfg,
@@ -99,23 +121,8 @@ func NewAccessLoggerWithIO(parent task.Parent, writer WriterWithName, anyCfg Any
logger: logging.With().Str("file", writer.Name()).Logger(),
}
if unwrapped, ok := writer.(MultiWriterInterface); ok {
for _, w := range unwrapped.Unwrap() {
if sr, ok := w.(supportRotate); ok {
l.supportRotate = append(l.supportRotate, sr)
}
if closer, ok := w.(io.Closer); ok {
l.closer = append(l.closer, closer)
}
}
} else {
if sr, ok := writer.(supportRotate); ok {
l.supportRotate = append(l.supportRotate, sr)
}
if closer, ok := writer.(io.Closer); ok {
l.closer = append(l.closer, closer)
}
}
l.supportRotate = unwrap[supportRotate](writer)
l.closer = unwrap[io.Closer](writer)
if cfg.req != nil {
fmt := CommonFormatter{cfg: &cfg.req.Fields}