Skip to content

Commit

Permalink
Add proxy protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
emilevauge authored and traefiker committed Aug 25, 2017
1 parent 89b0037 commit c8c31ae
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 29 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ Run it and forget it!
- Websocket, HTTP/2, GRPC ready
- Access Logs (JSON, CLF)
- [Let's Encrypt](https://letsencrypt.org) support (Automatic HTTPS with renewal)
- High Availability with cluster mode
- [Proxy Protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt) support
- High Availability with cluster mode (beta)

## Supported backends

Expand Down
11 changes: 4 additions & 7 deletions build.Dockerfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
FROM golang:1.8
FROM golang:1.9-alpine

# Install a more recent version of mercurial to avoid mismatching results
# between glide run on a decently updated host system and the build container.
RUN awk '$1 ~ "^deb" { $3 = $3 "-backports"; print; exit }' /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list && \
DEBIAN_FRONTEND=noninteractive apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -t jessie-backports --yes --no-install-recommends mercurial=3.9.1-1~bpo8+1 && \
rm -fr /var/lib/apt/lists/
RUN apk --update upgrade \
&& apk --no-cache --no-progress add git mercurial bash gcc musl-dev curl tar \
&& rm -rf /var/cache/apk/*

RUN go get github.com/jteeuwen/go-bindata/... \
&& go get github.com/golang/lint/golint \
Expand Down
15 changes: 13 additions & 2 deletions configuration/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ func (ep *EntryPoints) String() string {
// Set's argument is a string to be parsed to set the flag.
// It's a comma-separated list, so we split it.
func (ep *EntryPoints) Set(value string) error {
regex := regexp.MustCompile(`(?:Name:(?P<Name>\S*))\s*(?:Address:(?P<Address>\S*))?\s*(?:TLS:(?P<TLS>\S*))?\s*((?P<TLSACME>TLS))?\s*(?:CA:(?P<CA>\S*))?\s*(?:Redirect.EntryPoint:(?P<RedirectEntryPoint>\S*))?\s*(?:Redirect.Regex:(?P<RedirectRegex>\\S*))?\s*(?:Redirect.Replacement:(?P<RedirectReplacement>\S*))?\s*(?:Compress:(?P<Compress>\S*))?\s*(?:WhiteListSourceRange:(?P<WhiteListSourceRange>\S*))?`)
regex := regexp.MustCompile(`(?:Name:(?P<Name>\S*))\s*(?:Address:(?P<Address>\S*))?\s*(?:TLS:(?P<TLS>\S*))?\s*((?P<TLSACME>TLS))?\s*(?:CA:(?P<CA>\S*))?\s*(?:Redirect.EntryPoint:(?P<RedirectEntryPoint>\S*))?\s*(?:Redirect.Regex:(?P<RedirectRegex>\\S*))?\s*(?:Redirect.Replacement:(?P<RedirectReplacement>\S*))?\s*(?:Compress:(?P<Compress>\S*))?\s*(?:WhiteListSourceRange:(?P<WhiteListSourceRange>\S*))?\s*(?:ProxyProtocol:(?P<ProxyProtocol>\S*))?`)
match := regex.FindAllStringSubmatch(value, -1)
if match == nil {
return fmt.Errorf("bad EntryPoints format: %s", value)
Expand Down Expand Up @@ -234,20 +234,30 @@ func (ep *EntryPoints) Set(value string) error {

compress := false
if len(result["Compress"]) > 0 {
compress = strings.EqualFold(result["Compress"], "enable") || strings.EqualFold(result["Compress"], "on")
compress = strings.EqualFold(result["Compress"], "true") ||
strings.EqualFold(result["Compress"], "enable") ||
strings.EqualFold(result["Compress"], "on")
}

whiteListSourceRange := []string{}
if len(result["WhiteListSourceRange"]) > 0 {
whiteListSourceRange = strings.Split(result["WhiteListSourceRange"], ",")
}

proxyprotocol := false
if len(result["ProxyProtocol"]) > 0 {
proxyprotocol = strings.EqualFold(result["ProxyProtocol"], "true") ||
strings.EqualFold(result["ProxyProtocol"], "enable") ||
strings.EqualFold(result["ProxyProtocol"], "on")
}

(*ep)[result["Name"]] = &EntryPoint{
Address: result["Address"],
TLS: configTLS,
Redirect: redirect,
Compress: compress,
WhitelistSourceRange: whiteListSourceRange,
ProxyProtocol: proxyprotocol,
}

return nil
Expand Down Expand Up @@ -277,6 +287,7 @@ type EntryPoint struct {
Auth *types.Auth
WhitelistSourceRange []string
Compress bool
ProxyProtocol bool
}

// Redirect configures a redirection of an entry point to another, or to an URL
Expand Down
6 changes: 6 additions & 0 deletions docs/toml.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ To write JSON format logs, specify `json` as the format:
# address = ":80"
# whiteListSourceRange = ["127.0.0.1/32"]

# To enable ProxyProtocol support (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt):
# [entryPoints]
# [entryPoints.http]
# address = ":80"
# proxyprotocol = true

[entryPoints]
[entryPoints.http]
address = ":80"
Expand Down
6 changes: 4 additions & 2 deletions glide.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions glide.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,8 @@ import:
- spew
- package: github.com/Masterminds/sprig
version: e039e20e500c2c025d9145be375e27cf42a94174
- package: github.com/armon/go-proxyproto
version: 48572f11356f1843b694f21a290d4f1006bc5e47
testImport:
- package: github.com/stvp/go-udp-testing
- package: github.com/docker/libcompose
Expand Down
46 changes: 30 additions & 16 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"sync"
"time"

"github.com/armon/go-proxyproto"
"github.com/containous/mux"
"github.com/containous/traefik/cluster"
"github.com/containous/traefik/configuration"
Expand Down Expand Up @@ -65,6 +66,7 @@ type serverEntryPoints map[string]*serverEntryPoint

type serverEntryPoint struct {
httpServer *http.Server
listener net.Listener
httpRouter *middlewares.HandlerSwitcher
}

Expand Down Expand Up @@ -259,7 +261,7 @@ func (server *Server) startHTTPServers() {

for newServerEntryPointName, newServerEntryPoint := range server.serverEntryPoints {
serverEntryPoint := server.setupServerEntryPoint(newServerEntryPointName, newServerEntryPoint)
go server.startServer(serverEntryPoint.httpServer, server.globalConfiguration)
go server.startServer(serverEntryPoint, server.globalConfiguration)
}
}

Expand Down Expand Up @@ -296,12 +298,13 @@ func (server *Server) setupServerEntryPoint(newServerEntryPointName string, newS
}
serverMiddlewares = append(serverMiddlewares, ipWhitelistMiddleware)
}
newSrv, err := server.prepareServer(newServerEntryPointName, server.globalConfiguration.EntryPoints[newServerEntryPointName], newServerEntryPoint.httpRouter, serverMiddlewares...)
newSrv, listener, err := server.prepareServer(newServerEntryPointName, server.globalConfiguration.EntryPoints[newServerEntryPointName], newServerEntryPoint.httpRouter, serverMiddlewares...)
if err != nil {
log.Fatal("Error preparing server: ", err)
}
serverEntryPoint := server.serverEntryPoints[newServerEntryPointName]
serverEntryPoint.httpServer = newSrv
serverEntryPoint.listener = listener

return serverEntryPoint
}
Expand Down Expand Up @@ -611,20 +614,20 @@ func (server *Server) createTLSConfig(entryPointName string, tlsOption *configur
return config, nil
}

func (server *Server) startServer(srv *http.Server, globalConfiguration configuration.GlobalConfiguration) {
log.Infof("Starting server on %s", srv.Addr)
func (server *Server) startServer(serverEntryPoint *serverEntryPoint, globalConfiguration configuration.GlobalConfiguration) {
log.Infof("Starting server on %s", serverEntryPoint.httpServer.Addr)
var err error
if srv.TLSConfig != nil {
err = srv.ListenAndServeTLS("", "")
if serverEntryPoint.httpServer.TLSConfig != nil {
err = serverEntryPoint.httpServer.ServeTLS(serverEntryPoint.listener, "", "")
} else {
err = srv.ListenAndServe()
err = serverEntryPoint.httpServer.Serve(serverEntryPoint.listener)
}
if err != nil {
log.Error("Error creating server: ", err)
}
}

func (server *Server) prepareServer(entryPointName string, entryPoint *configuration.EntryPoint, router *middlewares.HandlerSwitcher, middlewares ...negroni.Handler) (*http.Server, error) {
func (server *Server) prepareServer(entryPointName string, entryPoint *configuration.EntryPoint, router *middlewares.HandlerSwitcher, middlewares ...negroni.Handler) (*http.Server, net.Listener, error) {
readTimeout, writeTimeout, idleTimeout := buildServerTimeouts(server.globalConfiguration)
log.Infof("Preparing server %s %+v with readTimeout=%s writeTimeout=%s idleTimeout=%s", entryPointName, entryPoint, readTimeout, writeTimeout, idleTimeout)

Expand All @@ -638,17 +641,28 @@ func (server *Server) prepareServer(entryPointName string, entryPoint *configura
tlsConfig, err := server.createTLSConfig(entryPointName, entryPoint.TLS, router)
if err != nil {
log.Errorf("Error creating TLS config: %s", err)
return nil, err
return nil, nil, err
}

listener, err := net.Listen("tcp", entryPoint.Address)
if err != nil {
log.Error("Error opening listener ", err)
}

if entryPoint.ProxyProtocol {
listener = &proxyproto.Listener{Listener: listener}
}

return &http.Server{
Addr: entryPoint.Address,
Handler: n,
TLSConfig: tlsConfig,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
IdleTimeout: idleTimeout,
}, nil
Addr: entryPoint.Address,
Handler: n,
TLSConfig: tlsConfig,
ReadTimeout: readTimeout,
WriteTimeout: writeTimeout,
IdleTimeout: idleTimeout,
},
listener,
nil
}

func buildServerTimeouts(globalConfig configuration.GlobalConfiguration) (readTimeout, writeTimeout, idleTimeout time.Duration) {
Expand Down
2 changes: 1 addition & 1 deletion server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestPrepareServerTimeouts(t *testing.T) {
router := middlewares.NewHandlerSwitcher(mux.NewRouter())

srv := NewServer(test.globalConfig)
httpServer, err := srv.prepareServer(entryPointName, entryPoint, router)
httpServer, _, err := srv.prepareServer(entryPointName, entryPoint, router)
if err != nil {
t.Fatalf("Unexpected error when preparing srv: %s", err)
}
Expand Down
6 changes: 6 additions & 0 deletions traefik.sample.toml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,12 @@
# address = ":80"
# whiteListSourceRange = ["127.0.0.1/32"]

# To enable ProxyProtocol support (https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt):
# [entryPoints]
# [entryPoints.http]
# address = ":80"
# proxyprotocol = true

# Enable retry sending request if network error
#
# Optional
Expand Down
21 changes: 21 additions & 0 deletions vendor/github.com/armon/go-proxyproto/LICENSE

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit c8c31ae

Please sign in to comment.