From 156feff9f2fbe5e199b795c99ff543a65d6622b8 Mon Sep 17 00:00:00 2001 From: Florian Klink Date: Thu, 25 Apr 2024 00:14:42 +0300 Subject: [PATCH] sftp: support listening on passed FDs --- cmd/serve/sftp/server.go | 22 ++++++++++++++++++++-- cmd/serve/sftp/sftp.go | 11 +++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/cmd/serve/sftp/server.go b/cmd/serve/sftp/server.go index 96ab94aa0..0b89e03cc 100644 --- a/cmd/serve/sftp/server.go +++ b/cmd/serve/sftp/server.go @@ -21,6 +21,7 @@ import ( "path/filepath" "strings" + sdActivation "github.com/coreos/go-systemd/v22/activation" "github.com/rclone/rclone/cmd/serve/proxy" "github.com/rclone/rclone/cmd/serve/proxy/proxyflags" "github.com/rclone/rclone/fs" @@ -266,10 +267,27 @@ func (s *server) serve() (err error) { // Once a ServerConfig has been configured, connections can be // accepted. - s.listener, err = net.Listen("tcp", s.opt.ListenAddr) + var listener net.Listener + + // In case we run in a socket-activated environment, listen on (the first) + // passed FD. + sdListeners, err := sdActivation.Listeners() if err != nil { - return fmt.Errorf("failed to listen for connection: %w", err) + return fmt.Errorf("unable to acquire listeners: %w", err) } + + if len(sdListeners) > 0 { + if len(sdListeners) > 1 { + fs.LogPrintf(fs.LogLevelWarning, nil, "more than one listener passed, ignoring all but the first.\n") + } + listener = sdListeners[0] + } else { + listener, err = net.Listen("tcp", s.opt.ListenAddr) + if err != nil { + return fmt.Errorf("failed to listen for connection: %w", err) + } + } + s.listener = listener fs.Logf(nil, "SFTP server listening on %v\n", s.listener.Addr()) go s.acceptConnections() diff --git a/cmd/serve/sftp/sftp.go b/cmd/serve/sftp/sftp.go index 238e4c31e..328e7b561 100644 --- a/cmd/serve/sftp/sftp.go +++ b/cmd/serve/sftp/sftp.go @@ -115,6 +115,17 @@ directory. By default the server binds to localhost:2022 - if you want it to be reachable externally then supply ` + "`--addr :2022`" + ` for example. +This also supports being run with socket activation, in which case it will +listen on the first passed FD. +It can be configured with .socket and .service unit files as described in +https://www.freedesktop.org/software/systemd/man/latest/systemd.socket.html + +Socket activation can be tested ad-hoc with the ` + "`systemd-socket-activate`" + `command: + + systemd-socket-activate -l 2222 -- rclone serve sftp :local:vfs/ + +This will socket-activate rclone on the first connection to port 2222 over TCP. + Note that the default of ` + "`--vfs-cache-mode off`" + ` is fine for the rclone sftp backend, but it may not be with other SFTP clients.