package module
Version: v0.0.0-...-f64f7c2 Latest Latest

This package is not in the latest version of its module.

Go to latest
Published: Jul 8, 2020 License: MIT Imports: 23 Imported by: 24



Moved to

CircleCI codecov

A FTP server framework forked from and changed a lot.

Full documentation for the package is available on godoc




go get


To boot a FTP server you will need to provide a driver that speaks to your persistence layer - the required driver contract is in the documentation.

Look at the file driver to see an example of how to build a backend.

There is a sample ftp server as a demo. You can build it with this command:

go install

Then run it if you have add $GOPATH to your $PATH:

exampleftpd -root /tmp

And finally, connect to the server with any FTP client and the following details:

port: 2121
username: admin
password: 123456

This uses the file driver mentioned above to serve files.




FTP is an incredibly insecure protocol. Be careful about forcing users to authenticate with an username or password that are important.


This library is distributed under the terms of the MIT License. See the included file for more detail.


All suggestions and patches welcome, preferably via a git repository I can pull from. If this library proves useful to you, please let me know.

Further Reading

There are a range of RFCs that together specify the FTP protocol. In chronological order, the more useful ones are:

For an english summary that's somewhat more legible than the RFCs, and provides some commentary on what features are actually useful or relevant 24 years after RFC959 was published:

For a history lesson, check out Appendix III of RCF959. It lists the preceding (obsolete) RFC documents that relate to file transfers, including the ye old RFC114 from 1971, "A File Transfer Protocol"

This library is heavily based on em-ftpd, an FTPd framework with similar design goals within the ruby and EventMachine ecosystems. It worked well enough, but you know, callbacks and event loops make me something something.




This section is empty.


View Source
var ErrServerClosed = errors.New("ftp: Server closed")

ErrServerClosed is returned by ListenAndServe() or Serve() when a shutdown was requested.


func Version

func Version() string

Version returns the library version


type Auth

type Auth interface {
	CheckPasswd(string, string) (bool, error)

Auth is an interface to auth your ftp user login.

type Command

type Command interface {
	IsExtend() bool
	RequireParam() bool
	RequireAuth() bool
	Execute(*Conn, string)

type Conn

type Conn struct {
	// contains filtered or unexported fields

func (*Conn) Close

func (conn *Conn) Close()

Close will manually close this connection, even if the client isn't ready.

func (*Conn) IsLogin

func (conn *Conn) IsLogin() bool

func (*Conn) LoginUser

func (conn *Conn) LoginUser() string

func (*Conn) PassivePort

func (conn *Conn) PassivePort() int

func (*Conn) PublicIp

func (conn *Conn) PublicIp() string

func (*Conn) Serve

func (conn *Conn) Serve()

Serve starts an endless loop that reads FTP commands from the client and responds appropriately. terminated is a channel that will receive a true message when the connection closes. This loop will be running inside a goroutine, so use this channel to be notified when the connection can be cleaned up.

type DataSocket

type DataSocket interface {
	Host() string

	Port() int

	// the standard io.Reader interface
	Read(p []byte) (n int, err error)

	// the standard io.ReaderFrom interface
	ReadFrom(r io.Reader) (int64, error)

	// the standard io.Writer interface
	Write(p []byte) (n int, err error)

	// the standard io.Closer interface
	Close() error

DataSocket describes a data socket is used to send non-control data between the client and server.

type DiscardLogger

type DiscardLogger struct{}

Silent logger, produces no output

func (*DiscardLogger) Print

func (logger *DiscardLogger) Print(sessionId string, message interface{})

func (*DiscardLogger) PrintCommand

func (logger *DiscardLogger) PrintCommand(sessionId string, command string, params string)

func (*DiscardLogger) PrintResponse

func (logger *DiscardLogger) PrintResponse(sessionId string, code int, message string)

func (*DiscardLogger) Printf

func (logger *DiscardLogger) Printf(sessionId string, format string, v ...interface{})

type Driver

type Driver interface {
	// Init init

	// params  - a file path
	// returns - a time indicating when the requested path was last modified
	//         - an error if the file doesn't exist or the user lacks
	//           permissions
	Stat(string) (FileInfo, error)

	// params  - path
	// returns - true if the current user is permitted to change to the
	//           requested path
	ChangeDir(string) error

	// params  - path, function on file or subdir found
	// returns - error
	//           path
	ListDir(string, func(FileInfo) error) error

	// params  - path
	// returns - nil if the directory was deleted or any error encountered
	DeleteDir(string) error

	// params  - path
	// returns - nil if the file was deleted or any error encountered
	DeleteFile(string) error

	// params  - from_path, to_path
	// returns - nil if the file was renamed or any error encountered
	Rename(string, string) error

	// params  - path
	// returns - nil if the new directory was created or any error encountered
	MakeDir(string) error

	// params  - path
	// returns - a string containing the file data to send to the client
	GetFile(string, int64) (int64, io.ReadCloser, error)

	// params  - destination path, an io.Reader containing the file data
	// returns - the number of bytes writen and the first error encountered while writing, if any.
	PutFile(string, io.Reader, bool) (int64, error)

Driver is an interface that you will create an implementation that speaks to your chosen persistence layer. graval will create a new instance of your driver for each client that connects and delegate to it as required.

type DriverFactory

type DriverFactory interface {
	NewDriver() (Driver, error)

DriverFactory is a driver factory to create driver. For each client that connects to the server, a new FTPDriver is required. Create an implementation if this interface and provide it to FTPServer.

type FileInfo

type FileInfo interface {

	Owner() string
	Group() string

type Logger

type Logger interface {
	Print(sessionId string, message interface{})
	Printf(sessionId string, format string, v ...interface{})
	PrintCommand(sessionId string, command string, params string)
	PrintResponse(sessionId string, code int, message string)

type Perm

type Perm interface {
	GetOwner(string) (string, error)
	GetGroup(string) (string, error)
	GetMode(string) (os.FileMode, error)

	ChOwner(string, string) error
	ChGroup(string, string) error
	ChMode(string, os.FileMode) error

type Server

type Server struct {
	// contains filtered or unexported fields

Server is the root of your FTP application. You should instantiate one of these and call ListenAndServe() to start accepting client connections.

Always use the NewServer() method to create a new Server.

func NewServer

func NewServer(opts *ServerOpts) *Server

NewServer initialises a new FTP server. Configuration options are provided via an instance of ServerOpts. Calling this function in your code will probably look something like this:

factory := &MyDriverFactory{}
server  := server.NewServer(&server.ServerOpts{ Factory: factory })


factory := &MyDriverFactory{}
opts    := &server.ServerOpts{
  Factory: factory,
  Port: 2000,
  Hostname: "",
server  := server.NewServer(opts)

func (*Server) ListenAndServe

func (server *Server) ListenAndServe() error

ListenAndServe asks a new Server to begin accepting client connections. It accepts no arguments - all configuration is provided via the NewServer function.

If the server fails to start for any reason, an error will be returned. Common errors are trying to bind to a privileged port or something else is already listening on the same port.

func (*Server) Serve

func (server *Server) Serve(l net.Listener) error

Serve accepts connections on a given net.Listener and handles each request in a new goroutine.

func (*Server) Shutdown

func (server *Server) Shutdown() error

Shutdown will gracefully stop a server. Already connected clients will retain their connections

type ServerOpts

type ServerOpts struct {
	// The factory that will be used to create a new FTPDriver instance for
	// each client connection. This is a mandatory option.
	Factory DriverFactory

	Auth Auth

	// Server Name, Default is Go Ftp Server
	Name string

	// The hostname that the FTP server should listen on. Optional, defaults to
	// "::", which means all hostnames on ipv4 and ipv6.
	Hostname string

	// Public IP of the server
	PublicIp string

	// Passive ports
	PassivePorts string

	// The port that the FTP should listen on. Optional, defaults to 3000. In
	// a production environment you will probably want to change this to 21.
	Port int

	// use tls, default is false
	TLS bool

	// if tls used, cert file is required
	CertFile string

	// if tls used, key file is required
	KeyFile string

	// If ture TLS is used in RFC4217 mode
	ExplicitFTPS bool

	WelcomeMessage string

	// A logger implementation, if nil the StdLogger is used
	Logger Logger

ServerOpts contains parameters for server.NewServer()

type SimpleAuth

type SimpleAuth struct {
	Name     string
	Password string

SimpleAuth implements Auth interface to provide a memory user login auth

func (*SimpleAuth) CheckPasswd

func (a *SimpleAuth) CheckPasswd(name, pass string) (bool, error)

CheckPasswd will check user's password

type SimplePerm

type SimplePerm struct {
	// contains filtered or unexported fields

func NewSimplePerm

func NewSimplePerm(owner, group string) *SimplePerm

func (*SimplePerm) ChGroup

func (s *SimplePerm) ChGroup(string, string) error

func (*SimplePerm) ChMode

func (s *SimplePerm) ChMode(string, os.FileMode) error

func (*SimplePerm) ChOwner

func (s *SimplePerm) ChOwner(string, string) error

func (*SimplePerm) GetGroup

func (s *SimplePerm) GetGroup(string) (string, error)

func (*SimplePerm) GetMode

func (s *SimplePerm) GetMode(string) (os.FileMode, error)

func (*SimplePerm) GetOwner

func (s *SimplePerm) GetOwner(string) (string, error)

type StdLogger

type StdLogger struct{}

Use an instance of this to log in a standard format

func (*StdLogger) Print

func (logger *StdLogger) Print(sessionId string, message interface{})

func (*StdLogger) PrintCommand

func (logger *StdLogger) PrintCommand(sessionId string, command string, params string)

func (*StdLogger) PrintResponse

func (logger *StdLogger) PrintResponse(sessionId string, code int, message string)

func (*StdLogger) Printf

func (logger *StdLogger) Printf(sessionId string, format string, v ...interface{})


Path Synopsis
This is a very simple ftpd server using this library as an example and as something to run tests against.
This is a very simple ftpd server using this library as an example and as something to run tests against.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL