78 lines
1.4 KiB
Go
78 lines
1.4 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"fmt"
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"net/http/httputil"
|
||
|
"net/url"
|
||
|
"os"
|
||
|
"os/signal"
|
||
|
"strings"
|
||
|
|
||
|
"tailscale.com/tsnet"
|
||
|
)
|
||
|
|
||
|
func must[T any](t T, err error) T {
|
||
|
if err != nil {
|
||
|
panic(err)
|
||
|
}
|
||
|
return t
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var servers []*http.Server
|
||
|
|
||
|
upstreamsConfig := os.Getenv("UPSTREAMS")
|
||
|
hosts := strings.Split(upstreamsConfig, ",")
|
||
|
if upstreamsConfig == "" || len(hosts) == 0 {
|
||
|
log.Fatalf("set UPSTREAMS in environment like 'dockerhost:7400,otherdocker:80'")
|
||
|
}
|
||
|
|
||
|
for _, upstream := range hosts {
|
||
|
hostname, port, ok := strings.Cut(upstream, ":")
|
||
|
if hostname == "" {
|
||
|
// parsing error, just skip it
|
||
|
continue
|
||
|
}
|
||
|
if !ok || port == "" {
|
||
|
// default to 80
|
||
|
port = "80"
|
||
|
}
|
||
|
s := &tsnet.Server{
|
||
|
Dir: "/.config/" + hostname,
|
||
|
Hostname: hostname,
|
||
|
}
|
||
|
defer s.Close()
|
||
|
|
||
|
ln, err := s.Listen("tcp", ":80")
|
||
|
if err != nil {
|
||
|
fmt.Printf("%+v\n", err)
|
||
|
return
|
||
|
}
|
||
|
defer ln.Close()
|
||
|
|
||
|
srv := &http.Server{
|
||
|
Handler: httputil.NewSingleHostReverseProxy(
|
||
|
must(url.Parse("http://" + hostname + ":" + port + "/")),
|
||
|
),
|
||
|
}
|
||
|
servers = append(servers, srv)
|
||
|
// start server
|
||
|
go func() {
|
||
|
err = srv.Serve(ln)
|
||
|
fmt.Printf("%+v\n", err)
|
||
|
}()
|
||
|
}
|
||
|
|
||
|
sigint := make(chan os.Signal, 1)
|
||
|
signal.Notify(sigint, os.Interrupt)
|
||
|
<-sigint
|
||
|
for _, server := range servers {
|
||
|
if err := server.Shutdown(context.Background()); err != nil {
|
||
|
log.Printf("HTTP server Shutdown: %v", err)
|
||
|
}
|
||
|
}
|
||
|
}
|