SFTPGo — the vsftpd on steroids

Mike R
5 min readMar 5, 2021

For anyone that ever had to setup a secure sFTP server, you’ve undoubtedly had some pains setting up vsftpd service.

This article shows a very nice alternative that may make your life much easier.

vsftpd

Vsftpd is a well known “very secure FTP daemon” application and does its job well when properly configured.

The problem I’ve always had with this application is the sheer amount of config options, the messy integration with SSH daemon, and a myriad of parameters that often contradict each other, making a secure configuration tough to fully understand, especially for a beginner.

One of my biggest problems with vsftpd is that you have create system accounts for users to login. Although there is an alias option (create a user alias instead of actual uid, it never worked properly when I tried setting this up)

Another config parameter that didnt make any sense to me was the “ftpusers” file that blocks access attempts from following users

etting up the service is easysimply run setup command# Users that are not allowed to login via ftp
root
bin
daemon
adm
lp
sync
shutdown
halt
mail
news
uucp
operator
games
nobody

the file must be named “ftpusers”, yet these users arent using FTP, theyre blocked from using it. The naming of parameters isnt obvious and counter intuitive.

I always found vsftpd to be a pain in the ass to configure properly, especially with high degree of trust in its security to secure our customer’s data.

sFTPGo

sFTPGo is a new open source secure FTP application that dramatically eases the deployment and configuration of a secure FTP server.

Installation

sftpgo can be installed by downloading a release from the github repo

In this example, Im using Centos 7 so I installed the RPM version of the software

root@dev:~ $ sudo rpm -i sftpgo-2.0.2-1.x86_64.rpm 
2021-03-05T12:32:31.000 INF Initializing provider: "sqlite" config file: "/etc/sftpgo/sftpgo.json"
2021-03-05T12:32:31.000 INF updating database version: 1 -> 2
2021-03-05T12:32:31.000 INF updating database version: 2 -> 3
2021-03-05T12:32:31.000 INF updating database version: 3 -> 4
2021-03-05T12:32:31.000 INF updating database version: 4 -> 5
2021-03-05T12:32:31.000 INF updating database version: 5 -> 6
2021-03-05T12:32:31.000 INF updating database version: 6 -> 7
2021-03-05T12:32:31.000 INF updating database version: 7 -> 8
2021-03-05T12:32:31.000 INF Data provider successfully initialized/updated

on install, the binary creates a folder and config file in /etc/sftpgo

by default it uses SQLite to manage users and other settings, but also supports Postgres

Config

once installed, sftpgo creates a config file in JSON form

{
"common": {
"idle_timeout": 15,
"upload_mode": 0,
"actions": {
"execute_on": [],
"hook": ""
},
"setstat_mode": 0,
"proxy_protocol": 0,
"proxy_allowed": [],
"post_connect_hook": "",
"max_total_connections": 0,
"defender": {
"enabled": false,
"ban_time": 30,
"ban_time_increment": 50,
"threshold": 15,
"score_invalid": 2,
"score_valid": 1,
"observation_time": 30,
"entries_soft_limit": 100,
"entries_hard_limit": 150,
"safelist_file": "",
"blocklist_file": ""
}
},
"sftpd": {
"bindings": [
{
"port": 2022,
"address": "",
"apply_proxy_config": true
}
],
"max_auth_tries": 0,
"banner": "",
"host_keys": [],
"kex_algorithms": [],
"ciphers": [],
"macs": [],
"trusted_user_ca_keys": [],
"login_banner_file": "",
"enabled_ssh_commands": [
"md5sum",
"sha1sum",
"cd",
"pwd",
"scp"
],
"keyboard_interactive_auth_hook": "",
"password_authentication": true
},
"ftpd": {
"bindings": [
{
"port": 0,
"address": "",
"apply_proxy_config": true,
"tls_mode": 0,
"force_passive_ip": "",
"client_auth_type": 0
}
],
"banner": "",
"banner_file": "",
"active_transfers_port_non_20": true,
"passive_port_range": {
"start": 50000,
"end": 50100
},
"disable_active_mode": false,
"enable_site": false,
"hash_support": 0,
"combine_support": 0,
"certificate_file": "",
"certificate_key_file": "",
"ca_certificates": [],
"ca_revocation_lists": []
},
"webdavd": {
"bindings": [
{
"port": 0,
"address": "",
"enable_https": false,
"client_auth_type": 0
}
],
"certificate_file": "",
"certificate_key_file": "",
"ca_certificates": [],
"ca_revocation_lists": [],
"cors": {
"enabled": false,
"allowed_origins": [],
"allowed_methods": [],
"allowed_headers": [],
"exposed_headers": [],
"allow_credentials": false,
"max_age": 0
},
"cache": {
"users": {
"expiration_time": 0,
"max_size": 50
},
"mime_types": {
"enabled": true,
"max_size": 1000
}
}
},
"data_provider": {
"driver": "sqlite",
"name": "/var/lib/sftpgo/sftpgo.db",
"host": "",
"port": 0,
"username": "",
"password": "",
"sslmode": 0,
"connection_string": "",
"sql_tables_prefix": "",
"track_quota": 2,
"pool_size": 0,
"users_base_dir": "/srv/sftpgo/data",
"actions": {
"execute_on": [],
"hook": ""
},
"external_auth_hook": "",
"external_auth_scope": 0,
"credentials_path": "/var/lib/sftpgo/credentials",
"prefer_database_credentials": false,
"pre_login_hook": "",
"post_login_hook": "",
"post_login_scope": 0,
"check_password_hook": "",
"check_password_scope": 0,
"password_hashing": {
"argon2_options": {
"memory": 65536,
"iterations": 1,
"parallelism": 2
}
},
"update_mode": 0
},
"httpd": {
"bindings": [
{
"port": 8080,
"address": "127.0.0.1",

"enable_web_admin": true,
"enable_https": false,
"client_auth_type": 0
}
],
"templates_path": "/usr/share/sftpgo/templates",
"static_files_path": "/usr/share/sftpgo/static",
"backups_path": "/srv/sftpgo/backups",
"certificate_file": "",
"certificate_key_file": "",
"ca_certificates": [],
"ca_revocation_lists": []
},
"telemetry": {
"bind_port": 10000,
"bind_address": "127.0.0.1",
"enable_profiler": false,
"auth_user_file": "",
"certificate_file": "",
"certificate_key_file": ""
},
"http": {
"timeout": 20,
"retry_wait_min": 2,
"retry_wait_max": 30,
"retry_max": 3,
"ca_certificates": [],
"certificates": [],
"skip_tls_verify": false
},
"kms": {
"secrets": {
"url": "",
"master_key_path": ""
}
}
}

Dont worry about all the optoins, the only 2 we care about are the FTP listen port (set to 2022) and the Console web port (set to 127.0.0.1:8080)

if you need to run your FTP service on different ports, or access the console from another server, update the ports and web IP (ie, 0.0.0.0:8080)

once updated, run

sftpgo server

sftpgo will start FTP process and generate SSH keys

sftpgo serve
2021-03-05T12:43:36.114 INF No host keys configured and "id_rsa" does not exist; try to create a new host key
2021-03-05T12:43:37.690 INF No host keys configured and "id_ecdsa" does not exist; try to create a new host key
2021-03-05T12:43:37.701 INF No host keys configured and "id_ed25519" does not exist; try to create a new host key

You can also run it as a systemd service

sytemctl restart sftpgo

Admin Console

you can now access your FTP admin console and create users

https://your-IP-or-hostname:<port defined in config>

default creds:
admin
password

obviously change them once you log in

From here you can create users, shared folders and other settings, the options to control how your users access your FTP server are huge and easy to configure

admin console

You can control how the user can authenticate to your FTP server (which protocol, password or ssh key, or some other combination)

You can also define what action the user can take on the files inside their FTP directory, file quotas, and which directory the user will be routed to (in this example I’m using an S3 bucket as FTP home dir)

Client connections

Clients can connect to your SFTP server by running a basic sftp connection command

sftp -P 2022 username@your-IP-or-hostname

you can also see any connected clients on the admin console

SFTPGO is a fantastic modern alternative to vsftpd, written in Golang. Give it a try.

--

--