diff --git a/README.md b/README.md index 3e2ea35..94f9e91 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ Works with mobile versions too. * Results sharing (optional) * Multiple Points of Test (optional) * Compatible with PHP frontend predefined endpoints (with `.php` suffixes) +* Supports [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) ![Screencast](https://speedtest.zzz.cat/speedtest.webp) @@ -88,6 +89,8 @@ manually, you can install newer version of Go into your `GOPATH`: bind_address="127.0.0.1" # backend listen port, default is 8989 listen_port=8989 + # proxy protocol port, use 0 to disable + proxyprotocol_port=0 # Server location, use zeroes to fetch from API automatically server_lat=0 server_lng=0 diff --git a/config/config.go b/config/config.go index 8eda2da..8280481 100644 --- a/config/config.go +++ b/config/config.go @@ -8,11 +8,12 @@ import ( ) type Config struct { - BindAddress string `mapstructure:"bind_address"` - Port string `mapstructure:"listen_port"` - ServerLat float64 `mapstructure:"server_lat"` - ServerLng float64 `mapstructure:"server_lng"` - IPInfoAPIKey string `mapstructure:"ipinfo_api_key"` + BindAddress string `mapstructure:"bind_address"` + Port string `mapstructure:"listen_port"` + ProxyProtocolPort string `mapstructure:"proxyprotocol_port"` + ServerLat float64 `mapstructure:"server_lat"` + ServerLng float64 `mapstructure:"server_lng"` + IPInfoAPIKey string `mapstructure:"ipinfo_api_key"` StatsPassword string `mapstructure:"statistics_password"` RedactIP bool `mapstructure:"redact_ip_addresses"` @@ -34,6 +35,7 @@ var ( func init() { viper.SetDefault("listen_port", "8989") + viper.SetDefault("proxyprotocol_port", "0") viper.SetDefault("download_chunks", 4) viper.SetDefault("distance_unit", "K") viper.SetDefault("enable_cors", false) diff --git a/go.mod b/go.mod index 2a97ac5..de57f48 100644 --- a/go.mod +++ b/go.mod @@ -8,9 +8,9 @@ require ( github.com/go-chi/render v1.0.1 github.com/go-sql-driver/mysql v1.5.0 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 - github.com/gorilla/websocket v1.4.2 github.com/lib/pq v1.3.0 github.com/oklog/ulid/v2 v2.0.2 + github.com/pires/go-proxyproto v0.1.3 github.com/sirupsen/logrus v1.4.2 github.com/spf13/viper v1.6.2 go.etcd.io/bbolt v1.3.3 diff --git a/go.sum b/go.sum index 23c76e2..d25afa9 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,6 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= @@ -83,6 +81,8 @@ github.com/oklog/ulid/v2 v2.0.2/go.mod h1:mtBL0Qe/0HAx6/a4Z30qxVIAL1eQDweXq5lxOE github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o= github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pires/go-proxyproto v0.1.3 h1:2XEuhsQluSNA5QIQkiUv8PfgZ51sNYIQkq/yFquiSQM= +github.com/pires/go-proxyproto v0.1.3/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= diff --git a/main.go b/main.go index 04ac507..eda793a 100644 --- a/main.go +++ b/main.go @@ -7,7 +7,6 @@ import ( "github.com/librespeed/speedtest/database" "github.com/librespeed/speedtest/results" "github.com/librespeed/speedtest/web" - log "github.com/sirupsen/logrus" ) diff --git a/settings.toml b/settings.toml index a48dce8..8e04b4a 100644 --- a/settings.toml +++ b/settings.toml @@ -2,6 +2,8 @@ bind_address="" # backend listen port listen_port=8989 +# proxy protocol port, use 0 to disable +proxyprotocol_port=0 # Server location server_lat=0 server_lng=0 diff --git a/web/web.go b/web/web.go index fa548b6..845d049 100644 --- a/web/web.go +++ b/web/web.go @@ -14,6 +14,7 @@ import ( "github.com/go-chi/chi/middleware" "github.com/go-chi/cors" "github.com/go-chi/render" + "github.com/pires/go-proxyproto" log "github.com/sirupsen/logrus" "github.com/librespeed/speedtest/config" @@ -46,7 +47,8 @@ func ListenAndServe(conf *config.Config) error { r.Use(middleware.Logger) r.Use(middleware.Recoverer) - log.Infof("Starting backend server on %s", net.JoinHostPort(conf.BindAddress, conf.Port)) + addr := net.JoinHostPort(conf.BindAddress, conf.Port) + log.Infof("Starting backend server on %s", addr) r.Get("/*", pages) r.HandleFunc("/empty", empty) r.HandleFunc("/backend/empty", empty) @@ -75,7 +77,24 @@ func ListenAndServe(conf *config.Config) error { r.HandleFunc("/stats.php", results.Stats) r.HandleFunc("/backend/stats.php", results.Stats) - return http.ListenAndServe(net.JoinHostPort(conf.BindAddress, conf.Port), r) + go listenProxyProtocol(conf, r) + return http.ListenAndServe(addr, r) +} + +func listenProxyProtocol(conf *config.Config, r *chi.Mux) { + if conf.ProxyProtocolPort != "0" { + addr := net.JoinHostPort(conf.BindAddress, conf.ProxyProtocolPort) + l, err := net.Listen("tcp", addr) + if err != nil { + log.Fatal("Cannot listen on proxy protocol port %s: %s", conf.ProxyProtocolPort, err) + } + + pl := &proxyproto.Listener{Listener: l} + defer pl.Close() + + log.Infof("Starting proxy protocol listener on %s", addr) + log.Fatal(http.Serve(pl, r)) + } } func pages(w http.ResponseWriter, r *http.Request) {