One of the benefits of using Golang is its http package that provides an easy way to build robust REST APIs.

Unfortunately, it does not provide out of the box away to build FTP server or connect to FTP server.

In this article, we will explore that by demonstrating the usage of two third party packages that allow that.

Connecting to FTP server

The most robust and broadly used package that provides an FTP client build by Julien.

go get -u

You can connect the targeted FTP server as it’s shown in the following code snippet:

client, err := fto.Dial("localhost:21")
if err != nil {
  return err

if err := client.Login("root", "password"); err != nil {
  return err

The following code snippet lists, download and delete all files that matches the wild card.

entries, _ := client.List(wildcard)

for _, entry := range entries {
  name := entry.Name
  reader, err := client.Retr(name)
  if err != nil {

For more advanced use cases, you can read the documentation.

Building an FTP Server

It’s very easy to build an FTP Server by using goftp/server package that provides a framework for building FTP server with any kind of data store (file system, AWS3 and so on).

go get

In order to run the server, you have to develop or use a driver that implements an interface that acts as bridge between the FTP protocol and your desired backing store:

type Driver interface {
    Stat(string) (FileInfo, error)
    ChangeDir(string) error
    ListDir(string, func(FileInfo) error) error
    DeleteDir(string) error
    DeleteFile(string) error
    Rename(string, string) error
    MakeDir(string) error
    GetFile(string, int64) (int64, io.ReadCloser, error)
    PutFile(string, io.Reader, bool) (int64, error)

Presently, the following drivers are available:

Let’s see how we can use the file system driver to build our own ftp server. We should install the package:

go get

Then we have to initialise and start the ftp server with the following code snippet:

factory := &filedriver.FileDriverFactory{
  RootPath: "path_to_directory_that_will_store_all_files",
  Perm: server.NewSimplePerm("root", "root")

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

The RootPath defines where the files will be stored, while the Perm field defines how the user are going to be authenticated. Presently, the package support single user authentication by using SimplePerm or you can use more advanced LevelDB authentication.

It’s so easy, right?