This FTP server is a gateway between old-school FTP devices and modern cloud based file systems, using the afero's Fs interface and acting as a reference implementation of the ftpserverlib.
At the current stage, supported backend are:
- Local disk
- S3 through afero-s3
- Dropbox (see doc) through afero-dropbox
- Google Drive (see doc) through afero-gdrive
- SFTP through afero's sftpfs
- Email through go-mail thanks to @x-way
- Telegram through telebot by @slayer, see doc
And with those are supported common parameters to switch them to read-only, enable login access, or use a temporary directory file (see doc).
These features are brought by ftpserverlib itself:
- Uploading and downloading files
- Directory listing (LIST + MLST)
- File and directory deletion and renaming
- TLS support (AUTH + PROT)
- File download/upload resume support (REST)
- Complete driver for all the above features
- Passive socket connections (EPSV and PASV commands)
- Active socket connections (PORT command)
- Small memory footprint
- Only relies on the standard library except for:
- go-kit log for logging
- afero for generic file systems handling
- Supported extensions:
Fetch a binary from the latest release and run it.
go install github.com/fclairamb/ftpserver@main
ftpserver &
There's also a containerized version of the server (31MB, based on alpine).
# Creating a directory
mkdir -p files
# Starting the sample FTP server
docker run --rm -d -p 2121-2130:2121-2130 -v $(pwd)/files:/tmp -v $(pwd):/app fclairamb/ftpserver
# docker-compose.yml
version: '3.3'
services:
ftpserver:
ports:
- '2121-2130:2121-2130'
volumes:
- ./files:/tmp
- .:/app
image: fclairamb/ftpserver
docker-compose up -d
This is a quick way to see if it's working correctly:
# Download some file
[ -f kitty.jpg ] || (curl -o kitty.jpg.tmp https://placekitten.com/2048/2048 && mv kitty.jpg.tmp kitty.jpg)
# Upload it to the server
curl -v -T kitty.jpg ftp://test:test@localhost:2121/
# Download it back
curl ftp://test:test@localhost:2121/kitty.jpg -o kitty2.jpg
# Compare it
diff kitty.jpg kitty2.jpg
If you don't create a ftpserver.json
file, one will be created for you.
Here is a sample config file:
{
"version": 1,
"passive_transfer_port_range": {
"start": 2122,
"end": 2130
},
"tls": {
"server_cert": {
"cert": "cert.pem",
"key": "key.pem"
}
},
"accesses": [
{
"user": "test",
"pass": "test",
"fs": "os",
"params": {
"basePath": "/tmp"
}
},
{
"user": "test",
"pass": "test",
"fs": "os",
"params": {
"basePath": "/tmp"
}
},
{
"user": "dropbox",
"pass": "dropbox",
"fs": "dropbox",
"params": {
"token": "..."
}
},
{
"user": "gdrive",
"pass": "gdrive",
"fs": "gdrive",
"params": {
"google_client_id": "***.apps.googleusercontent.com",
"google_client_secret": "****",
"base_path": "ftp"
}
},
{
"user": "s3",
"pass": "s3",
"fs": "s3",
"params": {
"endpoint": "https://s3.amazonaws.com",
"region": "eu-west-1",
"bucket": "my-bucket",
"access_key_id": "AKIA....",
"secret_access_key": "IDxd....",
"disable_ssl": "false",
"path_style": "false"
}
},
{
"user": "sftp",
"pass": "sftp",
"fs": "sftp",
"params": {
"username": "user",
"password": "password",
"hostname": "192.168.168.11:22"
}
},
{
"user": "telegram",
"pass": "telegram",
"fs": "telegram",
"shared": true,
"params": {
"Token": "<OBTAIN_TOKEN_FROM_BOTFATHER>",
"ChatID": "<INSERT_CHAT_ID_HERE>"
}
}
]
}
You can generate the TLS key pair files with the following command:
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out cert.pem -keyout key.pem