diff --git a/cmd/serve/http/http.go b/cmd/serve/http/http.go
index e29fb2c7b..b0454b867 100644
--- a/cmd/serve/http/http.go
+++ b/cmd/serve/http/http.go
@@ -3,7 +3,6 @@ package http
 import (
 	"fmt"
 	"html/template"
-	"log"
 	"net/http"
 	"os"
 	"path"
@@ -11,6 +10,7 @@ import (
 	"strings"
 
 	"github.com/ncw/rclone/cmd"
+	"github.com/ncw/rclone/cmd/serve/httplib"
 	"github.com/ncw/rclone/fs"
 	"github.com/ncw/rclone/fs/accounting"
 	"github.com/ncw/rclone/lib/rest"
@@ -19,13 +19,8 @@ import (
 	"github.com/spf13/cobra"
 )
 
-// Globals
-var (
-	bindAddress = "localhost:8080"
-)
-
 func init() {
-	Command.Flags().StringVarP(&bindAddress, "addr", "", bindAddress, "IPaddress:Port to bind server to.")
+	httplib.AddFlags(Command.Flags())
 	vfsflags.AddFlags(Command.Flags())
 }
 
@@ -37,10 +32,6 @@ var Command = &cobra.Command{
 over HTTP.  This can be viewed in a web browser or you can make a
 remote of type http read from it.
 
-Use --addr to specify which IP address and port the server should
-listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all
-IPs.  By default it only listens on localhost.
-
 You can use the filter flags (eg --include, --exclude) to control what
 is served.
 
@@ -48,12 +39,12 @@ The server will log errors.  Use -v to see access logs.
 
 --bwlimit will be respected for file transfers.  Use --stats to
 control the stats printing.
-` + vfs.Help,
+` + httplib.Help + vfs.Help,
 	Run: func(command *cobra.Command, args []string) {
 		cmd.CheckArgs(1, 1, command, args)
 		f := cmd.NewFsSrc(args)
 		cmd.Run(false, true, command, func() error {
-			s := newServer(f, bindAddress)
+			s := newServer(f)
 			s.serve()
 			return nil
 		})
@@ -62,33 +53,26 @@ control the stats printing.
 
 // server contains everything to run the server
 type server struct {
-	f           fs.Fs
-	bindAddress string
-	vfs         *vfs.VFS
+	f   fs.Fs
+	vfs *vfs.VFS
+	srv *httplib.Server
 }
 
-func newServer(f fs.Fs, bindAddress string) *server {
+func newServer(f fs.Fs) *server {
+	mux := http.NewServeMux()
 	s := &server{
-		f:           f,
-		bindAddress: bindAddress,
-		vfs:         vfs.New(f, &vfsflags.Opt),
+		f:   f,
+		vfs: vfs.New(f, &vfsflags.Opt),
+		srv: httplib.NewServer(mux),
 	}
+	mux.HandleFunc("/", s.handler)
 	return s
 }
 
-// serve creates the http server
+// serve runs the http server - doesn't return
 func (s *server) serve() {
-	mux := http.NewServeMux()
-	mux.HandleFunc("/", s.handler)
-	// FIXME make a transport?
-	httpServer := &http.Server{
-		Addr:           s.bindAddress,
-		Handler:        mux,
-		MaxHeaderBytes: 1 << 20,
-	}
-	initServer(httpServer)
-	fs.Logf(s.f, "Serving on http://%s/", bindAddress)
-	log.Fatal(httpServer.ListenAndServe())
+	fs.Logf(s.f, "Serving on %s", s.srv.URL())
+	s.srv.Serve()
 }
 
 // handler reads incoming requests and dispatches them
diff --git a/cmd/serve/http/http_test.go b/cmd/serve/http/http_test.go
index 5647347b7..05da842db 100644
--- a/cmd/serve/http/http_test.go
+++ b/cmd/serve/http/http_test.go
@@ -28,7 +28,8 @@ const (
 )
 
 func startServer(t *testing.T, f fs.Fs) {
-	s := newServer(f, testBindAddress)
+	s := newServer(f)
+	s.srv.SetBindAddress(testBindAddress)
 	go s.serve()
 
 	// try to connect to the test server
diff --git a/cmd/serve/http/http_new.go b/cmd/serve/httplib/http_new.go
similarity index 80%
rename from cmd/serve/http/http_new.go
rename to cmd/serve/httplib/http_new.go
index 8b15933f1..21cce8832 100644
--- a/cmd/serve/http/http_new.go
+++ b/cmd/serve/httplib/http_new.go
@@ -2,14 +2,14 @@
 
 //+build go1.8
 
-package http
+package httplib
 
 import (
 	"net/http"
 	"time"
 )
 
-// Initialise the http.Server for pre go1.8
+// Initialise the http.Server for post go1.8
 func initServer(s *http.Server) {
 	s.ReadHeaderTimeout = 10 * time.Second // time to send the headers
 	s.IdleTimeout = 60 * time.Second       // time to keep idle connections open
diff --git a/cmd/serve/http/http_old.go b/cmd/serve/httplib/http_old.go
similarity index 90%
rename from cmd/serve/http/http_old.go
rename to cmd/serve/httplib/http_old.go
index 92f570392..ddc37a1fd 100644
--- a/cmd/serve/http/http_old.go
+++ b/cmd/serve/httplib/http_old.go
@@ -2,7 +2,7 @@
 
 //+build !go1.8
 
-package http
+package httplib
 
 import (
 	"net/http"
diff --git a/cmd/serve/httplib/httplib.go b/cmd/serve/httplib/httplib.go
new file mode 100644
index 000000000..ea84b8eb9
--- /dev/null
+++ b/cmd/serve/httplib/httplib.go
@@ -0,0 +1,68 @@
+// Package httplib provides common functionality for http servers
+package httplib
+
+import (
+	"fmt"
+	"log"
+	"net/http"
+
+	"github.com/spf13/pflag"
+)
+
+// Globals
+var (
+	bindAddress = "localhost:8080"
+)
+
+// AddFlags adds the http server specific flags
+func AddFlags(flagSet *pflag.FlagSet) {
+	flagSet.StringVarP(&bindAddress, "addr", "", bindAddress, "IPaddress:Port to bind server to.")
+}
+
+// Help contains text describing the http server to add to the command
+// help.
+var Help = `
+### Server options
+
+Use --addr to specify which IP address and port the server should
+listen on, eg --addr 1.2.3.4:8000 or --addr :8080 to listen to all
+IPs.  By default it only listens on localhost.
+`
+
+// Server contains info about the running http server
+type Server struct {
+	bindAddress string
+	httpServer  *http.Server
+}
+
+// NewServer creates an http server
+func NewServer(handler http.Handler) *Server {
+	s := &Server{
+		bindAddress: bindAddress,
+	}
+	// FIXME make a transport?
+	s.httpServer = &http.Server{
+		Addr:           s.bindAddress,
+		Handler:        handler,
+		MaxHeaderBytes: 1 << 20,
+	}
+	// go version specific initialisation
+	initServer(s.httpServer)
+	return s
+}
+
+// SetBindAddress overrides the config flag
+func (s *Server) SetBindAddress(addr string) {
+	s.bindAddress = addr
+	s.httpServer.Addr = addr
+}
+
+// Serve runs the server - doesn't return
+func (s *Server) Serve() {
+	log.Fatal(s.httpServer.ListenAndServe())
+}
+
+// URL returns the serving address of this server
+func (s *Server) URL() string {
+	return fmt.Sprintf("http://%s/", s.bindAddress)
+}
diff --git a/cmd/serve/webdav/webdav.go b/cmd/serve/webdav/webdav.go
index 5f9945814..615322025 100644
--- a/cmd/serve/webdav/webdav.go
+++ b/cmd/serve/webdav/webdav.go
@@ -8,6 +8,8 @@ import (
 	"os"
 
 	"github.com/ncw/rclone/cmd"
+	"github.com/ncw/rclone/cmd/serve/httplib"
+	"github.com/ncw/rclone/cmd/serve/httplib/httpflags"
 	"github.com/ncw/rclone/fs"
 	"github.com/ncw/rclone/fs/log"
 	"github.com/ncw/rclone/vfs"
@@ -17,13 +19,8 @@ import (
 	"golang.org/x/net/webdav"
 )
 
-// Globals
-var (
-	bindAddress = "localhost:8081"
-)
-
 func init() {
-	Command.Flags().StringVarP(&bindAddress, "addr", "", bindAddress, "IPaddress:Port to bind server to.")
+	httpflags.AddFlags(Command.Flags())
 	vfsflags.AddFlags(Command.Flags())
 }
 
@@ -39,37 +36,18 @@ write it.
 
 NB at the moment each directory listing reads the start of each file
 which is undesirable: see https://github.com/golang/go/issues/22577
-
-` + vfs.Help,
+` + httplib.Help + vfs.Help,
 	Run: func(command *cobra.Command, args []string) {
 		cmd.CheckArgs(1, 1, command, args)
-		fsrc := cmd.NewFsSrc(args)
+		f := cmd.NewFsSrc(args)
 		cmd.Run(false, false, command, func() error {
-			return serveWebDav(fsrc)
+			w := newWebDAV(f, &httpflags.Opt)
+			w.serve()
+			return nil
 		})
 	},
 }
 
-// serve the remote
-func serveWebDav(f fs.Fs) error {
-	fs.Logf(f, "WebDav Server started on %v", bindAddress)
-
-	webdavFS := &WebDAV{
-		f:   f,
-		vfs: vfs.New(f, &vfsflags.Opt),
-	}
-
-	handler := &webdav.Handler{
-		FileSystem: webdavFS,
-		LockSystem: webdav.NewMemLS(),
-		Logger:     webdavFS.logRequest, // FIXME
-	}
-
-	// FIXME use our HTTP transport
-	http.Handle("/", handler)
-	return http.ListenAndServe(bindAddress, nil)
-}
-
 // WebDAV is a webdav.FileSystem interface
 //
 // A FileSystem implements access to a collection of named files. The elements
@@ -85,11 +63,35 @@ func serveWebDav(f fs.Fs) error {
 type WebDAV struct {
 	f   fs.Fs
 	vfs *vfs.VFS
+	srv *httplib.Server
 }
 
 // check interface
 var _ webdav.FileSystem = (*WebDAV)(nil)
 
+// Make a new WebDAV to serve the remote
+func newWebDAV(f fs.Fs, opt *httplib.Options) *WebDAV {
+	w := &WebDAV{
+		f:   f,
+		vfs: vfs.New(f, &vfsflags.Opt),
+	}
+
+	handler := &webdav.Handler{
+		FileSystem: w,
+		LockSystem: webdav.NewMemLS(),
+		Logger:     w.logRequest, // FIXME
+	}
+
+	w.srv = httplib.NewServer(handler, opt)
+	return w
+}
+
+// serve runs the http server - doesn't return
+func (w *WebDAV) serve() {
+	fs.Logf(w.f, "WebDav Server started on %s", w.srv.URL())
+	w.srv.Serve()
+}
+
 // logRequest is called by the webdav module on every request
 func (w *WebDAV) logRequest(r *http.Request, err error) {
 	fs.Infof(r.URL.Path, "%s from %s", r.Method, r.RemoteAddr)
diff --git a/cmd/serve/webdav/webdav_test.go b/cmd/serve/webdav/webdav_test.go
index 616078924..37d67eeff 100644
--- a/cmd/serve/webdav/webdav_test.go
+++ b/cmd/serve/webdav/webdav_test.go
@@ -13,13 +13,22 @@ import (
 	"testing"
 
 	_ "github.com/ncw/rclone/backend/local"
+	"github.com/ncw/rclone/cmd/serve/httplib"
 	"github.com/ncw/rclone/fstest"
 	"github.com/stretchr/testify/assert"
 )
 
+const (
+	testBindAddress = "localhost:51778"
+	testURL         = "http://" + testBindAddress + "/"
+)
+
 // TestWebDav runs the webdav server then runs the unit tests for the
 // webdav remote against it.
 func TestWebDav(t *testing.T) {
+	opt := httplib.DefaultOpt
+	opt.ListenAddr = testBindAddress
+
 	fstest.Initialise()
 
 	fremote, _, clean, err := fstest.RandomRemote(*fstest.RemoteName, *fstest.SubDir)
@@ -31,8 +40,8 @@ func TestWebDav(t *testing.T) {
 
 	// Start the server
 	go func() {
-		err := serveWebDav(fremote)
-		assert.NoError(t, err)
+		w := newWebDAV(fremote, &opt)
+		w.serve()
 	}()
 	// FIXME shut it down somehow?
 
@@ -52,7 +61,7 @@ func TestWebDav(t *testing.T) {
 	cmd := exec.Command("go", args...)
 	cmd.Env = append(os.Environ(),
 		"RCLONE_CONFIG_WEBDAVTEST_TYPE=webdav",
-		"RCLONE_CONFIG_WEBDAVTEST_URL=http://localhost:8081/",
+		"RCLONE_CONFIG_WEBDAVTEST_URL="+testURL,
 		"RCLONE_CONFIG_WEBDAVTEST_VENDOR=other",
 	)
 	out, err := cmd.CombinedOutput()