Files
pz8-relay/main.go
T

77 lines
1.8 KiB
Go
Raw Normal View History

2026-05-06 00:11:40 +02:00
package main
import (
"crypto/subtle"
2026-05-06 01:45:38 +02:00
"log/slog"
2026-05-06 00:11:40 +02:00
"net/http"
"net/http/httputil"
"net/url"
"os"
"strings"
2026-05-06 00:11:40 +02:00
)
func main() {
2026-05-06 01:48:00 +02:00
logger := slog.New(slog.NewTextHandler(os.Stdout, nil))
2026-05-06 01:45:38 +02:00
slog.SetDefault(logger)
2026-05-06 00:11:40 +02:00
target := mustEnv("PZ8_RELAY_TARGET_URL")
username := mustEnv("PZ8_RELAY_USERNAME")
password := mustEnv("PZ8_RELAY_PASSWORD")
addr := os.Getenv("PZ8_RELAY_LISTEN_ADDR")
if addr == "" {
addr = ":8080"
}
targetURL, err := url.Parse(target)
if err != nil {
2026-05-06 01:45:38 +02:00
slog.Error("invalid PZ8_RELAY_TARGET_URL", "err", err)
os.Exit(1)
2026-05-06 00:11:40 +02:00
}
proxy := &httputil.ReverseProxy{
Rewrite: func(preq *httputil.ProxyRequest) {
preq.SetURL(targetURL)
},
}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
u, p, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(u), []byte(username)) != 1 ||
subtle.ConstantTimeCompare([]byte(p), []byte(password)) != 1 {
2026-05-06 01:45:38 +02:00
slog.Warn("unauthorized request", "client", clientIP(r))
2026-05-06 00:11:40 +02:00
w.Header().Set("WWW-Authenticate", `Basic realm="pz8-relay"`)
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
proxy.ServeHTTP(w, r)
})
2026-05-06 01:45:38 +02:00
slog.Info("pz8-relay listening", "addr", addr, "target", targetURL.Redacted())
if err := http.ListenAndServe(addr, nil); err != nil {
slog.Error("server stopped", "err", err)
os.Exit(1)
}
2026-05-06 00:11:40 +02:00
}
// clientIP returns the original client address, trusting X-Forwarded-For
// because this service runs behind Traefik. Do not expose directly.
func clientIP(r *http.Request) string {
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
if i := strings.IndexByte(xff, ','); i >= 0 {
return strings.TrimSpace(xff[:i])
}
return strings.TrimSpace(xff)
}
return r.RemoteAddr
}
2026-05-06 00:11:40 +02:00
func mustEnv(key string) string {
v := os.Getenv(key)
if v == "" {
2026-05-06 01:45:38 +02:00
slog.Error("missing required env var", "name", key)
os.Exit(1)
2026-05-06 00:11:40 +02:00
}
return v
}