SFTPGo -- 急我所急的SFTP server

在很多场景下,我们有来自不同的用户上传文件的需求。并且在文件上传到服务器后,该目录还需以NFS方式共享给其他服务器、应用使用。
很久之前,我们一直通过vsftp等FTP软件来实现文件的上传、下载,性能很好,功能、配置也很丰富。
后来,安全问题造成了sftp的崛起。单端口和便利的传输加密使sftp获得了更多人的青睐。
但是vsftp和sftp都有各自的优势和缺点。

对比 vsftp (passive mode) sftp
端口加固 1个通讯端口,很多个数据端口 单端口
传输加密 支持ssl加密,配置麻烦 原生支持ssl传输加密,无需配置
虚拟账户 支持virtual user 不支持虚拟账户

我们希望结合sftp端口加固和传输加密的优势和vsftp虚拟账户的优势。

SFTPGo

sftpgo git 地址 https://github.com/drakkan/sftpgo

SFTPGo 基于 Linux 开发和测试。

安装需求
  • Go 1.13 或更高版本。
  • 数据库服务器:PostreSQL 9.4+ ,MySQL 5.6+ , SQLite 3.x , bbolt 1.3.x。用于作为data provider.
安装
[sysadmin@VM_201_18_centos opt]$ sudo tar xvJf sftpgo_0.9.5_linux_x86_64.tar.xz  -C sftpgo/
[sysadmin@VM_201_18_centos opt]$ ls sftpgo
init  LICENSE  README.pdf  scripts  sftpgo  sftpgo.json  sql  static  templates
配置

sftpgo的用法如下:

[sysadmin@VM_201_18_centos sftpgo]$ ls
init  LICENSE  README.pdf  scripts  sftpgo  sftpgo.json  sql  static  templates
[sysadmin@VM_201_18_centos sftpgo]$ 
[sysadmin@VM_201_18_centos sftpgo]$ 
[sysadmin@VM_201_18_centos sftpgo]$ ./sftpgo -h
Full featured and highly configurable SFTP server

Usage:
  sftpgo [command]

Available Commands:
  help        Help about any command
  portable    Serve a single directory
  serve       Start the SFTP Server

Flags:
  -h, --help      help for sftpgo
  -v, --version

Use "sftpgo [command] --help" for more information about a command.

serve命令支持如下flags:

  • --config-dir 字符串。指定config目录。目录应该包含sftpgo的配置文件,并且作为一些使用相对路径文件的base目录(比如:SFTP server的私钥, SQLite or bblot 数据库)。 默认值是 "." ,或者由环境变量SFTPGO_CONFIG_DIR定义。
  • --config-file 字符串。 配置文件名。它应该是保存在config-dir的一个文件名,而不是配置文件的绝对路径。指定的文件名不含扩展名,自动加载JSON, YAML, TOML, HCL and Java properties。默认是 "sftpgo" (因此会检索 sftpgo.json, sftpgo.yaml 等) ,或者由环境变量SFTPGO_CONFIG_FILE定义。
  • --log-compress 布尔值。 定义被轮值切割的日志是否使用gzip压缩。默认 false,或由环境变量 SFTPGO_LOG_COMPRESS定义 (1 or true, 0 or false)。如果log-file-path留空,那么该配置无效。
  • --log-file-path 字符串。定义Log文件路径,默认 "sftpgo.log" ,或者由环境变量SFTPGO_LOG_FILE_PATH定义。留空会将Log写入到 standard error。
  • --log-max-age 整数。 日志保留的最长天数。默认 28 ,或由环境变量SFTPGO_LOG_MAX_AGE定义。如果log-file-path留空,那么该配置无效。
  • --log-max-backups 整数。日志保留的最大数量。默认 5 ,或由环境变量SFTPGO_LOG_MAX_BACKUPS定义。如果log-file-path留空,那么该配置无效。
  • --log-max-size 整数。 日志文件切割的最大尺寸。默认 10 ,或由环境变量SFTPGO_LOG_MAX_SIZE定义。如果log-file-path留空,那么该配置无效。
  • --log-verbose 布尔值。 开启详细日志。默认 true ,或由环境变量SFTPGO_LOG_VERBOSE定义 (1 or true, 0 or false)。

如果你没有配置私钥,daemon 会使用配置目录下的id_rsaid_ecdsa文件。如果文件不存在,会自动创建 (SFTPGo的运行用户需要有config-dir的写入权限)。服务器支持基于 crypto/ssh的私钥。

sftpgo 配置文件定义包含三部分:
sftpd , data provider , httpd

"sftpd", SFTP server的配置项

  • bind_port, integer。 SFTP的服务端口。默认: 2022
  • bind_address, string。留空来监听所有可用网卡接口。默认: ""
  • idle_timeout, integer。空闲client多少分钟后被中断。0 disable。默认:15。
  • max_auth_tries integer。每个连接的最大认证尝试次数。如果设置为负值,那么尝试次数不受限。如果设置为0,尝试次数限制为6。
  • umask, string。Umask值。Windows无效。 默认: "0022"。
  • banner, string。验证通过的欢迎语。留空则使用默认。 默认 SFTPGo_<version>, 范例 SSH-2.0-SFTPGo_0.9.5
  • upload_mode integer。上传模式定义。
    0 标准模式,文件会被直接上传到请求路径。
    1 原子模式,文件被上传到临时路径,然后在上传结束的时候重命名为请求路径。 原子模式避免了类似如下的情况,当文件还在上传的时候,web server 使用未上传完毕的文件(partial files)提供了服务。在原子模式下,如果上传报错,临时文件会被删除,所以请求路径下不会存在未上传完毕的文件(partial files)。
    2 带续传的原子模式,类似原子模式,但是如果有上传报错,临时文件会被重命名到请求路径而不是删除,这样客户端可以重连续传。
  • actions, struct。包含要执行的命令,提醒的HTTP URL,触发器条件。 参考 "Custom Actions" 后去更详细的信息。
    * execute_on, list of strings. 可用 download, upload, delete, rename, ssh_cmd。留空则 disable actions。
    * command, string。执行命令的绝对路径。留空则 disable。
    * http_notification_url, a valid URL。触发一个到该URL的HTTP GET 请求。留空则 disable。
  • keys, struct array。包含了daemon的私钥。如果留空或缺失,daemon会在配置目录查找或者创建 id_rsaid_ecdsa
    * private_key, 私钥的文件路径。可以是配置目录的相对路径,或绝对路径。
  • enable_scp, boolean。默认 disabled。设置为true来开启实验性的SCP支持。这个配置项不建议使用,在后面的版本会移除。请在enabled_ssh_commands清单添加 scp来开启。
  • kex_algorithms, list of strings。可用的 KEX (Key Exchange密码交换) 算法,按顺序优先。留空使用默认值。支持的算法参考: crypto/ssh
  • ciphers, list of strings。 允许的密钥密码。留空使用默认值。支持的算法参考:: crypto/ssh
  • macs, list of strings。可用的MAC (message authentication code) 算法,按顺序优先。留空使用默认值。支持的算法参考:crypto/ssh
  • login_banner_file, 登录banner文件路径。文件的内容会在认证允许前发给远程用户。可以是配置目录的相对路径,或者绝对路径。留空则 disable login banner。
  • setstat_mode, integer。
    0 - "正常模式": 变更权限,属组,访问/修改时间的需求会被执行
    1 - "忽略模式": 变更权限,属组,访问/修改时间的需求会被忽略
  • enabled_ssh_commands, 允许的SSH命令清单。如下的一些 SSH 命令默认是开启的: md5sum, sha1sum, cd, pwd* 开启所有支持的命令。有些命令在SFTPGo中实现了,还有些我们使用系统命令,需要被安装并被配置在system的'PATH'中。For system commands we have no direct control on file creation/deletion and so we cannot support remote filesystems, such as S3, and quota check is suboptimal: if quota is enabled, the number of files is checked at the command begin and not while new files are created. The allowed size is calculated as the difference between the max quota and the used one and it is checked against the bytes transferred via SSH. The command is aborted if it uploads more bytes than the remaining allowed size calculated at the command start. Anyway we see the bytes that the remote command send to the local command via SSH, these bytes contain both protocol commands and files and so the size of the files is different from the size trasferred via SSH: for example a command can send compressed files or a protocol command (few bytes) could delete a big file. To mitigate this issue quotas are recalculated at the command end with a full home directory scan, this could be heavy for big directories. If you need system commands and quotas you could consider to disable quota restrictions and periodically update quota usage yourself using the REST API. We support the following SSH commands:
    * scp, SCP is an experimental feature, we have our own SCP implementation since we can't rely on "scp" system command to proper handle quotas and user's home dir restrictions. The SCP protocol is quite simple but there is no official docs about it, so we need more testing and feedbacks before enabling it by default. We may not handle some borderline cases or have sneaky bugs. Please do accurate tests yourself before enabling SCP and let us known if something does not work as expected for your use cases. SCP between two remote hosts is supported using the -3 scp option.
    * md5sum, sha1sum, sha256sum, sha384sum, sha512sum. Useful to check message digests for uploaded files. These commands are implemented inside SFTPGo so they work even if the matching system commands are not available, for example on Windows.
    * cd, pwd. Some SFTP clients does not support the SFTP SSH_FXP_REALPATH packet type and so they use cd and pwd SSH commands to get the initial directory. Currently cd does nothing and pwd always returns the / path.
    * git-receive-pack, git-upload-pack, git-upload-archive. These commands enable support for Git repositories over SSH, they need to be installed and in your system's PATH. Git commands are not allowed inside virtual folders and inside directories with file extensions filters.
    * rsync. The rsync command need to be installed and in your system's PATH. We cannot avoid that rsync creates symlinks so if the user has the permission to create symlinks we add the option --safe-links to the received rsync command, if it is not already set. This should prevent to create symlinks that point outside the home dir. If the user cannot create symlinks we add the option --munge-links, if it is not already set. This should make symlinks unusable (but manually recoverable). The rsync command interacts with the filesystem directly and it is not aware about virtual folders and file extensions filters, so it will be automatically disabled for users with these features enabled.
  • keyboard_interactive_auth_program, string。Keyboard interactive authentication使用的扩展程序的绝对路径。参考 "Keyboard Interactive Authentication" 获取更多信息。
  • proxy_protocol, integer。HAProxy PROXY protocol的支持。如果将SFTPGo运行在proxy server后面, 比如 HAProxy, AWS ELB or NGNIX,你可以开启 proxy protocol。它提供了一个简便方式来可靠的传输连接信息,比如一个客户端的地址经过多层网络(NAT or TCP proxies)来获取真实的client IP 而不是proxy IP。协议版本1 and 2 都是被支持的。如果proxy protocol在SFTPGo开启了,那么需要在proxy配置内开启protocol,比如对于 HAProxy 增加 send-proxy or send-proxy-v2对每个服务器配置。支持如下的模式:
    * 0, disabled
    * 1, enabled. Proxy header 会被使用,不带proxy header的requests会被接收。
    * 2, required. Proxy header 会被使用,不带proxy header的requests会被拒绝。
  • proxy_allowed, 允许发送proxy heard的IP地址或IP地址段。
    * 如果 proxy_protocol 设置为1,并且从没在list中的IP收到 proxy header。连接会被接收,header会被忽略。
    * 如果 proxy_protocol 设置为2,并且从没在list中的IP收到 proxy header。连接会被拒绝。

"data_provider", data provider的配置文件

  • driver, string。支持的驱动 sqlite, mysql, postgresql, bolt, memory
  • name, string。数据库库名。 For driver sqlite this can be the database name relative to the config dir or the absolute path to the SQLite database. For driver memory this is the (optional) path relative to the config dir or the absolute path to the users dump to load.
  • host, string。数据库主机。对于sqlite, bolt and memory设置为空。
  • port, integer。数据库端口。对于 sqlite, bolt and memory设置为空。
  • username, string。数据库用户名。对于 sqlite, bolt and memory设置为空。
  • password, string。数据库密码。对于 sqlite, bolt and memory设置为空。
  • sslmode, integer。适用于 mysql and postgresql
    0 disable SSL/TLS connections,
    1 require ssl
    2 对于 postgresql设置ssl mode 为 verify-ca ,对于mysql设置为skip-verify
    3 对于 postgresql设置ssl mode 为 verify-full,对于mysql设置为preferred
  • connectionstring, string. Provide a custom database connection string. If not empty this connection string will be used instead of build one using the previous parameters. Leave empty for drivers bolt and memory
  • users_table, string。SFTP users 的数据库表。
  • manage_users, integer。设置为0关闭users management, 1 开启。
  • track_quota, integer. Set the preferred mode to track users quota between the following choices:
    * 0, disable quota tracking. REST API to scan user dir and update quota will do nothing
    * 1, quota is updated each time a user upload or delete a file even if the user has no quota restrictions
    * 2, quota is updated each time a user upload or delete a file but only for users with quota restrictions. With this configuration the "quota scan" REST API can still be used to periodically update space usage for users without quota restrictions
  • pool_size, integer。设置mysql或postgresql的最大连接数。默认 0 (不限制)
  • users_base_dir, string。用户目录。如果在创建用户的时候没有定义Home目录,并且该值配置为绝对路径,那么该目录作为用户的Home目录。
  • actions, struct。包含了执行的命令,HTTP URL,触发条件。参见 "Custom Actions"获取更多详细信息。
    * execute_on, list of strings。Valid values are add, update, delete. update action will not be fired for internal updates such as the last login or the user quota fields.
    * command, string. Absolute path to the command to execute. Leave empty to disable.
    * http_notification_url, a valid URL. Leave empty to disable.
  • external_auth_program, string。外部扩展认证程序的绝对路径。参见 "External Authentication" 后去更详细信息。留空关闭。
  • external_auth_scope, integer。
    0 所有认证方式 (密码,公钥 , keyboard interactive).
    1 仅密码
    2 仅公钥
    4 仅keyboard interactive。这个可以被绑定使用。
    6 公钥和keyboard interactive
  • credentials_path, string。定义了用户提供的认证文件的目录,比如Google Cloud Storage credentials。可以是配置目录的相对路径,或者绝对路径。
  • pre_login_program, string。 Absolute path to an external program to use to modify user details just before the login. See the "Dynamic user modification" paragraph for more details. Leave empty to disable.

"httpd", 提供REST API的HTTP server的配置
* bind_port, integer。提供HTTP请求的端口。设置为 0 禁用HTTP server。默认t: 8080
* bind_address, string。留空以监听所有网络接口。默认: "127.0.0.1"
* templates_path, string。 HTML web templates路径。 可以设置为config dir的相对路径或者绝对路径。
* static_files_path, string。静态文件路径。可以设置为config dir的相对路径或者绝对路径。
* backups_path, string。Backup 目录路径。可以设置为config dir的相对路径或者绝对路径。基于安全考虑,不允许备份在arbitrary paths(任意路径?)。
* auth_user_file, string。认证文件路径。可以设置为config dir的相对路径或者绝对路径。支持HTTP认证,文件格式匹配Apache htpasswd工具创建的格式。密码格式支持bcrypt ($2y$ prefix) 和md5 crypt ($apr1$ prefix)。留空则关闭HTTP认证。
* certificate_file, string。HTTPS证书。 可以设置为config dir的相对路径或者绝对路径。
* certificate_key_file, string。适配如上证书的私钥。可以设置为config dir的相对路径或者绝对路径。如果证书和私钥文件都已经确认,那么服务器可以接收HTTPS连接了。证书和私钥文件可以根据需要被重新加载,在基于Unix的系统上发送SIGHUP信号,windows上则是paramchange请求。

Data provider 初始化

在启动SFTPGo server前,请确认配置的data provider已经被初始化。

基于SQL的 data providers (SQLite, MySQL, PostgreSQL) 需要创建数据库、表。基于Memory 和bolt的 data providers不需要初始化。

在配置文件配置完毕 data provider 后,你可以使用initprovider命令创建需要的数据库结构了。如果是SQLite provider,initprovider命令会自动创建数据库文件和表。对于PostgreSQL 和MySQL,你需要先创建数据库,然后initprovider命令会创建表。

范例,在配置目录执行如下命令:

sftpgo initprovider

查看命令行帮助

sftpgo initprovider --help

对于新安装系统, initprovider命令可以很好的完成初始化任务。从现在起,数据库结构可以在启动的时候自动的检查和升级了。

Upgrading

如果你从0.9.5版本或者之前的版本升级,你需要手动执行SQL脚本来创建数据库结构。脚本位于源码 sql 目录。 脚本的名字是以日期YYYYMMDD和后缀 .sql命名的。执行需要按照时间顺序。比如, 20190828.sql 需要在20191112.sql之前执行。
对于 SQLite: find sql/sqlite/ -type f -iname '*.sql' -print | sort -n | xargs cat | sqlite3 sftpgo.db
在升级完毕后,你的数据库结构就和使用 initprovider命令初始化的结构一样了,以后就不需要再手动升级了。

以sqlite为范例运行一个SFTPGo Demo

如下是范例 sftogo.json配置文件,相对于默认配置文件仅修改了http bind-address为留空:

[sysadmin@VM_201_18_centos sftpgo]$ cat sftpgo.json 
{
  "sftpd": {
    "bind_port": 2022,
    "bind_address": "",
    "idle_timeout": 15,
    "max_auth_tries": 0,
    "umask": "0022",
    "banner": "",
    "upload_mode": 0,
    "actions": {
      "execute_on": [],
      "command": "",
      "http_notification_url": ""
    },
    "keys": [],
    "enable_scp": false,
    "kex_algorithms": [],
    "ciphers": [],
    "macs": [],
    "login_banner_file": "",
    "setstat_mode": 0,
    "enabled_ssh_commands": ["md5sum", "sha1sum", "cd", "pwd"]
  },
  "data_provider": {
    "driver": "sqlite",
    "name": "sftpgo.db",
    "host": "",
    "port": 5432,
    "username": "",
    "password": "",
    "sslmode": 0,
    "connection_string": "",
    "users_table": "users",
    "manage_users": 1,
    "track_quota": 2,
    "pool_size": 0,
    "users_base_dir": "",
    "actions": {
      "execute_on": [],
      "command": "",
      "http_notification_url": ""
    },
    "external_auth_program": "",
    "external_auth_scope": 0
  },
  "httpd": {
    "bind_port": 8080,
    "bind_address": "",
    "templates_path": "templates",
    "static_files_path": "static",
    "backups_path": "backups"
  }
}

初始化data provider

[sysadmin@VM_201_18_centos sftpgo]$ ls
init  LICENSE  README.pdf  scripts  sftpgo  sftpgo.json  sftpgo.log  sql  static  templates
[sysadmin@VM_201_18_centos sftpgo]$ find sql/sqlite/ -type f -iname '*.sql' -print | sort -n | xargs cat | sqlite3 sftpgo.db
[sysadmin@VM_201_18_centos sftpgo]$ ls
init  LICENSE  README.pdf  scripts  sftpgo  sftpgo.db  sftpgo.json  sftpgo.log  sql  static  templates
[sysadmin@VM_201_18_centos sftpgo]$ 

开启服务

[sysadmin@VM_201_18_centos sftpgo]$ ./sftpgo serve
2020-03-05T10:48:10.454 INF No host keys configured and "id_rsa" does not exist; creating new private key for server

新开一个窗口,查看目录结构,会发现多了id_rsa和sftpgo.log文件

[sysadmin@VM_201_18_centos sftpgo]$ ls
id_rsa  init  LICENSE  README.pdf  scripts  sftpgo  sftpgo.db  sftpgo.json  sftpgo.log  sql  static  templates

查看端口

[sysadmin@VM_201_18_centos sftpgo]$ ps axu |grep sftpgo
sysadmin 22506  1.6  1.2 300436 12664 pts/1    Sl+  10:48   0:03 ./sftpgo serve
sysadmin 23037  0.0  0.0 112660   972 pts/0    R+   10:51   0:00 grep --color=auto sftpgo
[sysadmin@VM_201_18_centos sftpgo]$ 
[sysadmin@VM_201_18_centos sftpgo]$ 
[sysadmin@VM_201_18_centos sftpgo]$ sudo netstat -anpl |grep 22506
[sudo] password for sysadmin: 
tcp6       0      0 :::8080                 :::*                    LISTEN      22506/./sftpgo      
tcp6       0      0 :::2022                 :::*                    LISTEN      22506/./sftpgo      
[sysadmin@VM_201_18_centos sftpgo]$ 

访问web


微信截图_20200305105311.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,393评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,790评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,391评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,703评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,613评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,003评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,507评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,158评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,300评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,256评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,274评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,984评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,569评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,662评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,899评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,268评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,840评论 2 339

推荐阅读更多精彩内容