mirror of
https://github.com/yusing/godoxy.git
synced 2025-05-19 20:32:35 +02:00
run as non root and non host network mode
This commit is contained in:
parent
357897a0cd
commit
b3290e2665
15 changed files with 107 additions and 73 deletions
13
.env.example
13
.env.example
|
@ -1,6 +1,9 @@
|
|||
# set timezone to get correct log timestamp
|
||||
TZ=ETC/UTC
|
||||
|
||||
# Enable Prometheus Metrics
|
||||
GODOXY_PROMETHEUS_ENABLED=true
|
||||
|
||||
# API/WebUI user password login credentials (optional)
|
||||
# These fields are not required for OIDC authentication
|
||||
GODOXY_API_USER=admin
|
||||
|
@ -35,15 +38,5 @@ GODOXY_API_JWT_TOKEN_TTL=1h
|
|||
# Optional: Comma-separated list of allowed groups.
|
||||
# GODOXY_OIDC_ALLOWED_GROUPS=group1,group2
|
||||
|
||||
# Proxy listening address
|
||||
GODOXY_HTTP_ADDR=:80
|
||||
GODOXY_HTTPS_ADDR=:443
|
||||
|
||||
# API listening address
|
||||
GODOXY_API_ADDR=127.0.0.1:8888
|
||||
|
||||
# Prometheus Metrics listening address (uncomment to enable)
|
||||
#GODOXY_PROMETHEUS_ADDR=:8889
|
||||
|
||||
# Debug mode
|
||||
GODOXY_DEBUG=false
|
25
Dockerfile
25
Dockerfile
|
@ -1,10 +1,11 @@
|
|||
# trunk-ignore-all(checkov/CKV_DOCKER_3)
|
||||
# Stage 1: Builder
|
||||
FROM golang:1.23.5-alpine AS builder
|
||||
HEALTHCHECK NONE
|
||||
|
||||
# package version does not matter
|
||||
# trunk-ignore(hadolint/DL3018)
|
||||
RUN apk add --no-cache tzdata make libcap-setcap
|
||||
RUN apk add --no-cache make
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
|
@ -35,30 +36,36 @@ RUN --mount=type=cache,target="/go/pkg/mod" \
|
|||
mv bin/godoxy /app/godoxy
|
||||
|
||||
# Stage 2: Final image
|
||||
FROM scratch
|
||||
FROM alpine:3
|
||||
|
||||
LABEL maintainer="yusing@6uo.me"
|
||||
LABEL proxy.exclude=1
|
||||
|
||||
# copy timezone data
|
||||
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
|
||||
# trunk-ignore(hadolint/DL3018)
|
||||
RUN apk add --no-cache tzdata ca-certificates runuser libcap-setcap socat
|
||||
|
||||
# copy binary
|
||||
COPY --from=builder /app /app
|
||||
|
||||
# copy startup script
|
||||
COPY scripts/docker-start.sh /app/docker-start.sh
|
||||
|
||||
RUN chmod +x /app/docker-start.sh
|
||||
|
||||
# copy example config
|
||||
COPY config.example.yml /app/config/config.yml
|
||||
|
||||
# copy certs
|
||||
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
|
||||
|
||||
ENV DOCKER_HOST=unix:///var/run/docker.sock
|
||||
ENV SOCKET_FORK=/app/forked.sock
|
||||
ENV DOCKER_HOST=unix://${SOCKET_FORK}
|
||||
ENV GODOXY_DEBUG=0
|
||||
|
||||
ENV PUID=1002
|
||||
ENV PGID=1002
|
||||
|
||||
EXPOSE 80
|
||||
EXPOSE 8888
|
||||
EXPOSE 443
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
CMD ["/app/godoxy"]
|
||||
ENTRYPOINT [ "/app/docker-start.sh" ]
|
2
Makefile
2
Makefile
|
@ -45,9 +45,11 @@ get:
|
|||
build:
|
||||
mkdir -p bin
|
||||
go build ${BUILD_FLAGS} -o bin/godoxy ./cmd
|
||||
if which setcap; then \
|
||||
if [ $(shell id -u) -eq 0 ]; \
|
||||
then setcap CAP_NET_BIND_SERVICE=+eip bin/godoxy; \
|
||||
else sudo setcap CAP_NET_BIND_SERVICE=+eip bin/godoxy; \
|
||||
fi \
|
||||
fi
|
||||
|
||||
run:
|
||||
|
|
|
@ -4,14 +4,12 @@ services:
|
|||
image: ghcr.io/yusing/go-proxy-frontend:latest
|
||||
container_name: godoxy-frontend
|
||||
restart: unless-stopped
|
||||
network_mode: host
|
||||
env_file: .env
|
||||
depends_on:
|
||||
- app
|
||||
# modify below to fit your needs
|
||||
labels:
|
||||
proxy.aliases: gp
|
||||
proxy.#1.port: 3000
|
||||
proxy.aliases: godoxy
|
||||
# proxy.#1.middlewares.cidr_whitelist.status: 403
|
||||
# proxy.#1.middlewares.cidr_whitelist.message: IP not allowed
|
||||
# proxy.#1.middlewares.cidr_whitelist.allow: |
|
||||
|
@ -23,8 +21,13 @@ services:
|
|||
image: ghcr.io/yusing/go-proxy:latest
|
||||
container_name: godoxy
|
||||
restart: always
|
||||
network_mode: host
|
||||
env_file: .env
|
||||
ports:
|
||||
- 80:80 # http
|
||||
- 443:443 # https
|
||||
- 8081:8081 # prometheus
|
||||
extra_hosts:
|
||||
- host.docker.internal:host-gateway
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- ./config:/app/config
|
||||
|
|
|
@ -2,19 +2,17 @@ package query
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
v1 "github.com/yusing/go-proxy/internal/api/v1"
|
||||
U "github.com/yusing/go-proxy/internal/api/v1/utils"
|
||||
"github.com/yusing/go-proxy/internal/common"
|
||||
E "github.com/yusing/go-proxy/internal/error"
|
||||
"github.com/yusing/go-proxy/internal/net/http/middleware"
|
||||
)
|
||||
|
||||
func ReloadServer() E.Error {
|
||||
resp, err := U.Post(common.APIHTTPURL+"/v1/reload", "", nil)
|
||||
resp, err := U.FetchAPI(http.MethodPost, "/v1/reload", nil)
|
||||
if err != nil {
|
||||
return E.From(err)
|
||||
}
|
||||
|
@ -32,7 +30,7 @@ func ReloadServer() E.Error {
|
|||
}
|
||||
|
||||
func List[T any](what string) (_ T, outErr E.Error) {
|
||||
resp, err := U.Get(fmt.Sprintf("%s/v1/list/%s", common.APIHTTPURL, what))
|
||||
resp, err := U.FetchAPI(http.MethodGet, "/v1/list/"+what, nil)
|
||||
if err != nil {
|
||||
outErr = E.From(err)
|
||||
return
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/tls"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
|
||||
|
@ -26,3 +28,15 @@ var (
|
|||
Post = httpClient.Post
|
||||
Head = httpClient.Head
|
||||
)
|
||||
|
||||
func FetchAPI(method, endpoint string, body []byte) (*http.Response, error) {
|
||||
var bodyReader io.Reader
|
||||
if body != nil {
|
||||
bodyReader = bytes.NewReader(body)
|
||||
}
|
||||
req, err := http.NewRequest(method, "http://localhost"+common.APIHTTPAddr+endpoint, bodyReader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return httpClient.Do(req)
|
||||
}
|
||||
|
|
|
@ -10,6 +10,13 @@ const (
|
|||
KeepAlive = 60 * time.Second
|
||||
)
|
||||
|
||||
const (
|
||||
ProxyHTTPAddr = ":80"
|
||||
ProxyHTTPSAddr = ":443"
|
||||
APIHTTPAddr = ":8080"
|
||||
MetricsHTTPAddr = ":8081"
|
||||
)
|
||||
|
||||
// file, folder structure
|
||||
|
||||
const (
|
||||
|
|
|
@ -23,26 +23,7 @@ var (
|
|||
EnableLogStreaming = GetEnvBool("LOG_STREAMING", true)
|
||||
DebugMemLogger = GetEnvBool("DEBUG_MEM_LOGGER", false) && EnableLogStreaming
|
||||
|
||||
ProxyHTTPAddr,
|
||||
ProxyHTTPHost,
|
||||
ProxyHTTPPort,
|
||||
ProxyHTTPURL = GetAddrEnv("HTTP_ADDR", ":80", "http")
|
||||
|
||||
ProxyHTTPSAddr,
|
||||
ProxyHTTPSHost,
|
||||
ProxyHTTPSPort,
|
||||
ProxyHTTPSURL = GetAddrEnv("HTTPS_ADDR", ":443", "https")
|
||||
|
||||
APIHTTPAddr,
|
||||
APIHTTPHost,
|
||||
APIHTTPPort,
|
||||
APIHTTPURL = GetAddrEnv("API_ADDR", "127.0.0.1:8888", "http")
|
||||
|
||||
MetricsHTTPAddr,
|
||||
MetricsHTTPHost,
|
||||
MetricsHTTPPort,
|
||||
MetricsHTTPURL = GetAddrEnv("PROMETHEUS_ADDR", "", "http")
|
||||
PrometheusEnabled = MetricsHTTPURL != ""
|
||||
PrometheusEnabled = GetEnvBool("PROMETHEUS_ENABLED", true)
|
||||
|
||||
APIJWTSecret = decodeJWTKey(GetEnvString("API_JWT_SECRET", ""))
|
||||
APIJWTTokenTTL = GetDurationEnv("API_JWT_TOKEN_TTL", time.Hour)
|
||||
|
|
|
@ -124,30 +124,30 @@ func (c *Container) setPublicIP() {
|
|||
return
|
||||
}
|
||||
if strings.HasPrefix(c.DockerHost, "unix://") {
|
||||
c.PublicIP = "127.0.0.1"
|
||||
c.PublicIP = "localhost"
|
||||
return
|
||||
}
|
||||
url, err := url.Parse(c.DockerHost)
|
||||
if err != nil {
|
||||
logging.Err(err).Msgf("invalid docker host %q, falling back to 127.0.0.1", c.DockerHost)
|
||||
c.PublicIP = "127.0.0.1"
|
||||
logging.Err(err).Msgf("invalid docker host %q, falling back to localhost", c.DockerHost)
|
||||
c.PublicIP = "localhost"
|
||||
return
|
||||
}
|
||||
c.PublicIP = url.Hostname()
|
||||
}
|
||||
|
||||
func (c *Container) setPrivateIP(helper containerHelper) {
|
||||
if !strings.HasPrefix(c.DockerHost, "unix://") {
|
||||
return
|
||||
}
|
||||
if helper.NetworkSettings == nil {
|
||||
return
|
||||
}
|
||||
for _, v := range helper.NetworkSettings.Networks {
|
||||
if v.IPAddress == "" {
|
||||
continue
|
||||
}
|
||||
c.PrivateIP = v.IPAddress
|
||||
return
|
||||
}
|
||||
// if !strings.HasPrefix(c.DockerHost, "unix://") {
|
||||
// return
|
||||
// }
|
||||
// if helper.NetworkSettings == nil {
|
||||
// return
|
||||
// }
|
||||
// for _, v := range helper.NetworkSettings.Networks {
|
||||
// if v.IPAddress == "" {
|
||||
// continue
|
||||
// }
|
||||
// c.PrivateIP = v.IPAddress
|
||||
// return
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -4,14 +4,13 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/yusing/go-proxy/internal/net/http/loadbalancer/types"
|
||||
loadbalance "github.com/yusing/go-proxy/internal/net/http/loadbalancer/types"
|
||||
. "github.com/yusing/go-proxy/internal/utils/testing"
|
||||
)
|
||||
|
||||
func TestRebalance(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Run("zero", func(t *testing.T) {
|
||||
lb := New(new(loadbalance.Config))
|
||||
lb := New(new(types.Config))
|
||||
for range 10 {
|
||||
lb.AddServer(types.TestNewServer(0))
|
||||
}
|
||||
|
@ -19,7 +18,7 @@ func TestRebalance(t *testing.T) {
|
|||
ExpectEqual(t, lb.sumWeight, maxWeight)
|
||||
})
|
||||
t.Run("less", func(t *testing.T) {
|
||||
lb := New(new(loadbalance.Config))
|
||||
lb := New(new(types.Config))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .1))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .2))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .3))
|
||||
|
@ -30,7 +29,7 @@ func TestRebalance(t *testing.T) {
|
|||
ExpectEqual(t, lb.sumWeight, maxWeight)
|
||||
})
|
||||
t.Run("more", func(t *testing.T) {
|
||||
lb := New(new(loadbalance.Config))
|
||||
lb := New(new(types.Config))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .1))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .2))
|
||||
lb.AddServer(types.TestNewServer(float64(maxWeight) * .3))
|
||||
|
|
|
@ -22,7 +22,7 @@ func (redirectHTTP) before(w http.ResponseWriter, r *http.Request) (proceed bool
|
|||
if i := strings.Index(host, ":"); i != -1 {
|
||||
host = host[:i] // strip port number if present
|
||||
}
|
||||
r.URL.Host = host + ":" + common.ProxyHTTPSPort
|
||||
r.URL.Host = host + common.ProxyHTTPSAddr
|
||||
logging.Debug().Str("url", r.URL.String()).Msg("redirect to https")
|
||||
http.Redirect(w, r, r.URL.String(), http.StatusTemporaryRedirect)
|
||||
return true
|
||||
|
|
|
@ -15,7 +15,7 @@ func TestRedirectToHTTPs(t *testing.T) {
|
|||
})
|
||||
ExpectNoError(t, err)
|
||||
ExpectEqual(t, result.ResponseStatus, http.StatusTemporaryRedirect)
|
||||
ExpectEqual(t, result.ResponseHeaders.Get("Location"), "https://example.com:"+common.ProxyHTTPSPort)
|
||||
ExpectEqual(t, result.ResponseHeaders.Get("Location"), "https://example.com"+common.ProxyHTTPSAddr)
|
||||
}
|
||||
|
||||
func TestNoRedirect(t *testing.T) {
|
||||
|
|
|
@ -41,7 +41,7 @@ func TestHTTPConfigDeserialize(t *testing.T) {
|
|||
if err != nil {
|
||||
ExpectNoError(t, err)
|
||||
}
|
||||
ExpectDeepEqual(t, cfg.HTTPConfig, &tt.expected)
|
||||
ExpectDeepEqual(t, cfg.HTTPConfig, tt.expected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -116,6 +116,11 @@ func (e *RawEntry) Finalize() {
|
|||
}
|
||||
}
|
||||
|
||||
switch e.Host {
|
||||
case "localhost", "127.0.0.1", "[::1]":
|
||||
e.Host = "host.docker.internal"
|
||||
}
|
||||
|
||||
if e.Scheme == "" && isDocker {
|
||||
switch {
|
||||
case e.Host == cont.PublicIP && cont.PublicPortMapping[pp].Type == "udp":
|
||||
|
|
25
scripts/docker-start.sh
Executable file
25
scripts/docker-start.sh
Executable file
|
@ -0,0 +1,25 @@
|
|||
#!/bin/sh
|
||||
echo "Running as PUID: ${PUID}, PGID: ${PGID}"
|
||||
echo "Creating user"
|
||||
addgroup -S -g "${PGID}" godoxyg
|
||||
adduser -S -D -H -s /bin/false -u "${PUID}" -g "${PGID}" godoxy
|
||||
|
||||
echo "Setting up permissions"
|
||||
chown -R godoxy:godoxyg /app
|
||||
setcap CAP_NET_BIND_SERVICE=+eip /app/godoxy
|
||||
|
||||
# fork docker socket if exists
|
||||
if test -e /var/run/docker.sock; then
|
||||
echo "Proxying docker socket"
|
||||
socat -v "UNIX-LISTEN:${SOCKET_FORK}",fork UNIX-CONNECT:/var/run/docker.sock >/dev/null 2>&1 &
|
||||
# wait for socket to be ready
|
||||
while [ ! -S "${SOCKET_FORK}" ]; do
|
||||
sleep 0.1
|
||||
done
|
||||
chmod 660 "${SOCKET_FORK}"
|
||||
chown godoxy:godoxyg "${SOCKET_FORK}"
|
||||
fi
|
||||
|
||||
echo "Done"
|
||||
|
||||
runuser -u godoxy -g godoxyg -- /app/godoxy
|
Loading…
Add table
Reference in a new issue