文章难免存在错误、疏漏,如果愿意,欢迎指出勘误。

1. 前言

关于文件传输协议/文件共享协议,可以拿出来介绍的可以有很多,本文列举了一些通用的基础的发展较早的协议详细的介绍(当然了,没有深入的原理,咱也不会啊 :笑),一些较新的作了简单陈述,没有深究原理和实现。

本文主要分为三个部分

  1. 基础的文件传输/共享协议,更加推荐在内网使用的,不允许也不推荐暴露到公网。使用建议 点我
  2. 个人公网文件管理方案
  3. 实践: 在内网自建一个 seafile server, 并通过 frp 暴露在公网 serving,实现内外网都可以上传、下载、同步、分享。如何食用?点我

2. 协议总览

  1. SMB/CIFS/SAMBA
  2. FTP/FTPS/TFTP
  3. SCP/SFTP
  4. WebDAV/WebDAVS
  5. NFS
  6. DLNA+UPnP
  7. HTTP/HTTPS
  8. rsync
  9. AFP
  10. MTP
  11. others (列举了一些非常规的协议)

3. 正片

3.1 SMB/CIFS/SAMBA

SMB(Server Message Block) 通信协议是微软和英特尔在 1987 年制定的协议,主要是作为 Microsoft 网络的通讯协议,它是当今世上网络文件系统协议两极之一的存在。

SMB 使用了 NetBIOS 的 API。另外,它是一个开放性的协议,允许了协议扩展,这使得它可以变得更大而且复杂;大约有 65 个最上层的作业,而每个作业都超过 120 个函数,甚至 Windows NT 自己也没有全部支持到,后来著名的微软改名部门又把 SMB 重新设计了一套新的实现: CIFS(Common Internet File System) 协议,并且加入了许多新的特色功能。

一开始微软设计的 SMB 不支持在 Linux 上运行,著名黑客、技术大牛安德鲁·垂鸠 (Andrew Tridgell) 通过逆向工程,于 1992 年在澳洲国立大学(ANU)开发了第一版的 Samba Unix 软件,实现了 SMB/CIFS 兼容协议,并命名为 Samba,通过该程序实现了 Windows 和 Linux 之间的文件共享。 Debian 上的软件包名称就是 samba,OpenWrt 中一般有 samba36-serversamba4-server (版本 4,性能更强,更新的一个版本)。

SMB 是 C/S (Client and Server) 类型协议,客户机可以访问服务器上的共享文件系统、打印机及其他资源。更进阶一点,通过设置 "NetBIOS over TCP/IP",Samba 不但能与局域网络主机分享资源,还能与全世界的电脑分享资源,但一般很少这样使用。

SMB 的优点之一是兼容性特别好,在各平台都获得了广泛支持,包括 Windows、Linux、macOS、Android、iOS、iPadOS,甚至一些嵌入式系统比如 OpenWrt,挂载访问都很方便。另外 SMB 也是各种电视、电视盒子默认支持的协议,这些电视和盒子通过 SMB 访问服务器端的资源可以达到播放电影、音乐、访问图片和预览普通文件的目的。

另外 SMB 提供端到端加密、安全性高,配置选项丰富,支持 ACL(Access Control List) 并支持多种用户认证方式。

不过 SMB 的缺点也是最令极客们诟病的,是传输效率稍低,速度不太稳定,受机器网络和硬件资源波动较大。

简而言之,SMB 协议是在局域网上用于服务器文件访问和打印的协议。CIFS 可以看做是应用程序协议如文件传输协议和超文本传输协议的一个实现。

关于传输端口, SMB/CIFS 传输端口是 139 或 445,具体是 TCP port 139 over NetBIOS,TCP port 445 over IP。TCP 445 是基于 IP 的 SMB,这是较新的版本,可以在 IP 网络上正常使用 SMB,也就是公网使用 SMB。

ps: samba 最新稳定版是 version 4.x.x

3.2 FTP/TFTP/FTPS

FTP(File Transfer Protocol) 我们都很熟悉,它是 TCP/IP 协议簇中的一员,是 1971 年发展起来的文件传输协议,作为标准网络协议出现它包含两个部分实现,一个是 FTP Server,一个是 FTP Client,其中 Server 用来存储文件,Client 供客户机使用以访问远程资源。

现在暴露在公网的 FTP 站点已经越来越少,找了半天只发现 GNU 的 FTP 站点 ftp://ftp.gnu.org/ 目前还能匿名访问。Windows 可在 Windows Explorer 的 address bar 上直接键入地址然后回车即可以匿名身份访问。

默认情况下,FTP 使用 TCP 20 和 TCP 21 两个端口传输数据,TCP 20 用于数据传输,TCP 21 用于控制信息传输。而是否使用 20 端口传输数据与 FTP 传输模式有关,如果 FTP 主动模式,那么数据传输端口就是 20,如果采用的被动模式,那最终传输数据的端口由 FTP 的服务器和客户机协商决定。

FTP 的两种数据传输模式: Standard(主动) 和 Passive(被动)。

  1. Standard 模式

    FTP 客户端首先和服务器的 TCP 21 建立连接并发送指令,客户端需要接收数据的时候在这个通道上发送 PORT 命令。 PORT 命令包含了客户端用什么端口接收数据。在传输数据的时候,服务器通过自己的 TCP 20 连接到客户端的指定端口发送数据。FTP Server 必须和 Client 建立一个新的连接用来传输数据。

  2. Passive 模式

    建立控制通道和 Standard 模式类似,但建立连接后发送的是 PASV 命令,服务端收到 PASV 命令后打开一个临时端口 tempPort (1023 < tempPort < 65535) 并且通知客户端在这个端口上传送数据,客户端连接 FTP 服务端的此端口,然后服务端将会通过此端口 serving.

    很多防火墙在设置的时候都是不允许接受外部发起的连接的,所以许多位于防火墙后或内网的 FTP 服务器不支持 Passive 模式,因为客户端无法穿过防火墙打开 FTP 服务器的高端端口;而许多内网的客户端不能用 Standard 模式登陆 FTP 服务器,因为从服务器的 TCP 20 无法和内部网络的客户端建立一个新的连接,造成无法工作。

FTP 传输数据也有两种方式:ASCII 和 二进制。

  1. ASCII 传输方式

    假定用户正在拷贝的文件包含的简单 ASCII 码文本(plain text),如果在远程机器上运行的不是 UNIX,当文件传输时 FTP 通常会自动地调整文件的内容以便于把文件解释成另外那台计算机存储文本文件的格式。

    但是常常有一些“特殊”情况,用户正在传输的文件包含的不是文本文件,它们可能是可执行程序、电影、音乐、数据库或者压缩文件。在拷贝任何非文本文件之前,用 binary 命令告诉 FTP 逐字拷贝。

  2. 二进制传输方式

    在二进制传输中,保存文件的位序,以便原始和拷贝的是逐位一一对应的。即使目的机器上包含位序列的文件是没意义的。例如,macintosh (早期的 macOS 叫法) 以二进制方式传送可执行文件到 Windows 系统,在对方系统上,此文件不能执行。

时间已经来到了 2022 年,FTP 已经很少被应用在生产环境下,通过 http 传输文件的高效更能替代这个使用场景。它的优点不足以掩盖众多缺点,优点比如说能同时传输多个目录,自动备份等等,但是缺点众多,其他协议也支持它的优点,所以必然会被时代淘汰。

FTP 的缺点:数据传输模式不够合理,工作方式设计不合理,与防火墙工作不协调,安全认证策略不完善,相对而言整个传输过程效率也低下。此部分就不展开了,详情可见下面文章

通过上面的描述,可以感受到 FTP 的复杂性,1981 年在 RFC 783 中定义了一个简化的文件传输协议 TFTP(Trivial File Transfer Protocol),称作简单文件传输协议,也称小型/琐碎文件传输协议。TFTP 比 FTP 简单得多,并且执行客户端和服务器进程之间的文件传输。但是,它不提供 FTP 所支持的用户身份验证和其他有用的功能。FTP 使用 TCP 时,TFTP 使用 UDP,这使得它成为了不可靠的文件传输协议。由于简单,透过少量存储器就能轻松实现,在计算机发展早期还是有用处的,例如从一台网络主机或服务器引导一个远程 X Window System 终端或其他的瘦客户端。由于小型文件传输协议缺少安全性,在公网传输非常危险,所以普遍仅仅用于私有网络。

对于 FTP 在安全上的不足,后面发展了 FTPS。

FTPS(FTP over SSL/TLS),是一种安全的 FTP,添加了传输层安全(TLS)和安全套接层(SSL)的加密协议。尽管在数据传输方面加固了安全,但 FTP 的底层设计依然还是没有改变,所以直到现在应用也不够广泛。偶尔在内网中会有部署的 FTP 服务,但大家也更倾向于使用 samba, nfs, http, webdav 这些协议共享文件。

3.3 SCP/SFTP

SCP(Secure CoPy) 和 SFTP(Secure File Transfer Protocol) 都基于 SSH(Secure SHell) 协议,OpenSSH 是 SSH 协议的一个开源实现,一些嵌入式设备可以通过 dropbear 建立 ssh 连接,dropbear 也实现了 SSH 协议的基础功能。

SCP 用来进行远程文件复制,并且整个复制过程是加密的。数据传输使用 ssh tunnel,并且使用和 ssh 相同的认证方式,提供相同的安全保证。密码认证或密钥对 (key-pair)验证。

SFTP 与 FTP 有着几乎一样的语法和功能。SFTP 为 SSH 的一部分,是一种传输文件到服务器的安全方式。在 SSH 软件包中,已经包含了一个叫作 SFTP 的安全文件传输子系统,SFTP 本身没有单独的守护进程,它必须使用 sshd 守护进程(端口号默认是22)来完成相应的连接操作,所以从某种意义上来说,SFTP 并不像一个服务器程序,而更像是一个客户端程序。SFTP 同样是使用加密传输认证信息和传输的数据,所以,使用 SFTP 是安全的。但是,正由于这种传输方式使用了加密/解密技术,所以比起普通 FTP,开销大得多,传输效率低得多。如果用户对网络安全性要求更高,则可以使用 SFTP 代替 FTP。

目前最新的 OpenSSH 稳定版本是 9.0,OpenSSH 9.0 released April 8, 2022,服务端配置文件 /etc/ssh/sshd_config 中有一行 sftp 配置就是配置这个文件传输子系统的。

# override default of no subsystems
Subsystem       sftp    /usr/lib/openssh/sftp-server

SCP 和 SFTP 的比较

两者都基于 SSH,但是传输效率和安全性上也有区别。

  • SCP 不支持断点续传,一次 timeout 就得重来,而 SFTP 支持
  • SCP 单次传输不支持 4Gib 以上文件,SFTP 支持
  • SCP 不检查传输的数据包,效率更高但安全性更低

简单总结:SCP 适合小文件传输,速度更快。SFTP 适合更大文件,安全性更高的传输场景。

另外上文所述的 FTPS 不应与基于 SSH 的 SCP 和 SFTP 混淆。

Windows 端经典强大的开源程序 WinSCP 就实现了 SSH 的 SCP 和 SFTP 功能,界面直观非常易于使用。

3.4 WebDAV/WebDAVS

WebDAV(WEb-Based Distributed Authoring and Versioning) 一种基于 HTTP 1.1 协议的通信协议。它扩展了 HTTP 1.1,在 GET、POST、HEAD、PUT、DELETE、PATCH 等 HTTP 标准方法以外添加了一些新的方法,使应用程序可对 Web Server 直接读写,并支持写文件锁定 (Locking) 及解锁 (Unlock),还支持文件的版本控制。

简单而言,WebDAV 就是在服务器上划出一块存储空间,使用它扩展的一套 HTTP method 来管理文件,可以将磁盘映射到本地磁盘使用,对文件的每次改动都是一个 HTTP 请求。遗憾的是,目前只有用户名和密码的认证方式,安全性上有所欠缺。

WebDAV 为实现远程文件管理,向 HTTP/1.1 中追加了以下这些方法

  • PROPFIND:获取属性
  • PROPPATCH:修改属性
  • MKCOL:创建集合
  • COPY:复制资源及属性
  • MOVE:移动资源
  • LOCK:资源加锁
  • UNLOCK:资源解锁

HTTP status code 也随之扩展

  • 102 Processing:可正常处理请求, 但目前是处理中状态
  • 207 Multi-Status:存在多种状态
  • 422 Unprocessible Entity:格式正确, 内容有误
  • 423 Locked:资源已被加锁
  • 424 Failed Dependency:处理与某请求关联的请求失败, 因此不再维持依赖关系
  • 507 Insufficient Storage:保存空间不足

由于 WebDAV 是基于 HTTP 的,所以具有 HTTP 的所有优点,包括容易穿越防火墙、使用 HTTPS 来传输数据,因此在很多方面可以替代 FTP。通过 Nginx 或 Apache 或 Caddy 等 web server(也有其他实现,比如 Golang 实现的 webdav https://github.com/hacdias/webdav ) 非常容易就能搭建一个 WebDAV 服务。

WebDAVS(WebDAV over SSL/TLS) 就是加了一层 SSL/TLS ,数据安全更能得到保障,不过一般的使用场景多是 WebDAV + 配合 SSL 的 web server 实现 http 流量的加密,这样反而开销更小。

3.5 NFS

NFS(Network File System),即网络文件系统,是 FreeBSD 支持的文件系统中的一种。NFS 允许一个系统在网络上与它人共享目录和文件。通过使用 NFS,用户和程序可以像访问本地文件一样访问远端系统上的文件。它由 Sun 公司(已被 Oracle 收购)开发,于 1984 年发布,最新版本 NFSv4.2 于 2016 年发布。NFS 基于开放网络运算远程过程调用(ONC RPC)协议:一个开放、标准的 RFC 协议,任何人或组织都可以依据标准实现它。

NFS 通常使用在 Unix 操作系统上(比如 Solaris、AIX 及 HP-UX)和其他类 Unix 操作系统(例如 Linux 及 FreeBSD),同时在 macOS 和 Windows 系统也提供了 NFS 实现。不过在 Windows 系统上挂载 NFS 共享目录时,由于 Windows 自带的 NFS 客户端长久以来不支持 UTF-8,会致中文文件和目录显示为乱码。有解决方法但有代价,请见 一个小设置,让Win10 NFS正常显示中文UTF-8

NFS 的优点是 kernel 直接支持,部署简单、运行稳定,协议简单、传输效率高。

NFS 的缺点是没有加密授权等功能,仅依靠 IP 地址或主机名来决定用户能否挂载共享目录,对具体目录和文件无法进行 ACL 控制(NFSv4 以前)。通常的做法是通过 Kerberos 对 NFS 进行认证及加密,不过部署配置比较麻烦。

3.6 DLNA+UPnP

DLNA(Digital Living Network Alliance, 数字生活网络联盟),其前身是 DHWG(Digital Home Working Group,数字家庭工作组),成立于 2003 年 6 月 24 日, 是由索尼、英特尔、微软等发起成立的一个非营利性的、合作性质的商业组织。

DLNA 旨在解决个人 PC,消费电器,移动设备在内的无线网络和有线网络的互联互通,使得数字媒体和内容服务的无限制的共享和增长成为可能。DLNA 的口号是 Enjoy your music, photos and videos, anywhere anytime。

DLNA 将其整个应用规定成 5 个功能组件。从下到上依次为:网络互连,网络协议,媒体传输,设备的发现控制和管理,媒体格式。

DLNA

DLNA 架构图 image source

UPnP(Universal Plug and Play) 通用即插即用协议,官方的解释太过理论。微软的说法是

通用即插即用 (UPnP) 是一种用于 PC 机和智能设备(或仪器)的常见对等网络连接的体系结构,尤其是在家庭中。UPnP 以 Internet 标准和技术(例如 TCP/IP、HTTP 和 XML)为基础,使这样的设备彼此可自动连接和协同工作,从而使网络(尤其是家庭网络)对更多的人成为可能。

实际上,普通用户理解 UPnP 可以理解为基于 TCP/IP 上的自动端口映射,一般路由器在 NAT 的工作模式下可以打开此功能,自动处理局域网内设备中的各个软件的 UPnP 请求。

DLNA 可以高效的访问服务器中的各种类型资源,由 DLNA 服务器帮用户索引好离线文件。比如图片,音乐专辑,电影,电视剧集,适合多媒体的场景使用。

3.7 HTTP/HTTPS

HTTP(HyperText Transfer Protocol)即超文本传输协议,我们都不陌生了,通过 http 共享文件可以很简单,比如使用 nginx 标准模块 Auto Index 可以很快创建一个可以共享的文件服务器,效率也非常之高。

比如在 nginx 创建一个共享本地文件夹的配置文件 /etc/nginx/sites-enabled/files-sharing.conf ,内容如下

server {

    listen 82;
    server_name 192.168.10.10;
    charset gbk,utf-8;

    location / {
        root /home/xxx/nginx-static-files/; 
        index index.html index.htm;
        autoindex on;
        autoindex_exact_size on;
        autoindex_localtime on;
    }

}

访问 http://192.168.10.10:82 后的效果

20220616131149

HTTPS(HTTP over SSL/TLS),加密后的 http 流量,目前正是主流 web 交互的方式。

3.8 rsync

rsync 全称 remote synchronize,即"远程同步",是 Liunx/Unix 下的一个远程数据同步工具。它可通过 LAN/WAN 快速同步多台主机间的文件和目录,并适当利用 rsync 算法(差分编码)以减少数据的传输,即可做到增量传输/备份。严格来说,rsync 算不上底层的文件传输/共享协议,但是本文为了介绍的尽量全面还是提一下。

在常驻模式(daemon mode)下,rsync 默认监听 TCP 端口 873,以原生 rsync 传输协议或者透过远程 shell 如 RSH 或者 SSH 提供文件。SSH 模式下,rsync 客户端执行程序必须同时在本地和远程机器上安装。

rsync 首度发布于 1996 年 6 月 19 日。原始作者为安德鲁·垂鸠(Andrew Tridgell)(很巧的是,又是这个大神)与保罗·麦可拉斯(Paul Mackerras)。

rsync 现在应用广泛,使用起来也非常方便易用,效率也高,最初设计就是替代 SCP 的。既能在本地用于数据拷贝、移动(可用来替代 Linux cpmv 命令),也能做增量备份存储。通过 SSH 实现远程复制也非常好用。

关于 rsync 的基础用法和高级用法可以看看阮一峰的 rsync 用法教程 , 写得易懂且全面。

其实类似于 rsync 的工具,还有 rclonerobocopyfreefilesync 等,这里就不做过多介绍了。

3.9 AFP

AFP(Apple Filing Protocol),是一种专门为 MAC OS X(现名: macOS) 系统提供文件共享服务的协议,通过开源的 Netatalk 实现 AFP 共享。主要应用是苹果笔记本的 Time Machine 时间机器系统备份,macOS 物理接口是 type-c,并有微软的雷电 Thunderbolt 授权,协议就是 AFP 。但是这东西不够完善,复杂使用场景下都有 bug,现在连苹果自己都很少用。

3.10 MTP

MTP(Media Transfer Protocol) 媒体传输协议,是基于 PTP(Picture Transfer Protocol) 协议的扩展,主要用于传输媒体文件,其中有价值的应用就是同步 DRM 文件的 license。

MTP 既可以实现在 USB 协议上,也可以实现在 TCP/IP 协议上,它属于上层的应用协议,而不关心底层传输协议。目前大部分设备的应用都是基于 USB 协议。在 Android 设备上应用广泛,使用 USB A cable 连接 Windows PC 和 Android 设备,默认的文件传输协议就是 MTP,但除此之外,内网文件的传输很少应用到此协议。

3.11 others

我把他们归为一类,不够通用,具有一定的专用性,主要是为企业服务的。

AS2/AS3/AS4

AS2(Applicability Statement 2),下同。

AS2,AS3 和 AS4 都是用来发送和保护关键文件传输的流行协议。

AS2 用于在因特网上安全可靠地传输敏感数据。AS2 利用数字证书和加密标准来保护在系统、网络和位置之间传输的关键信息。AS2 消息可以通过安全的 SSL 隧道进行压缩、签名、加密和发送。

AS3 是一个标准,几乎可以用来传输任何文件类型。它通过数字签名和数据加密为数据传输提供了一层安全性。它最初是为了传输数据文件而创建的,如 XML 和 EDI 商业对企业数据的文件。与 AS2 不同,AS2 是一种定义的传输协议,AS3 是一种消息标准,它侧重于在从服务器发送到服务器时应该如何格式化消息。一旦 AS3 消息被合成,它就可以通过任何其他协议(FTP、SFTP、HTTPS 等)传输。只要双方能够访问已放置消息的位置。

AS4 是一种协议,允许企业与其合作伙伴安全地交换数据。它建立在最初由 AS2 设置的基础上,但与 Web 服务一起工作,并提供改进的交付通知。作为企业对企业的标准,AS4 有助于使在互联网上进行文件交换变得安全和简单。

see also What's the Difference Between AS2, AS3, and AS4?

OFTP(Odette 文件传输协议)

OFTP(Odette FTP),另一种专为 EDI 设计的文件传输协议 OFTP。OFTP 在欧洲应用非常普遍。OFTP 和 AS2 本质上都是安全的,甚至支持电子交付收据,使它们非常适合 B2B 交易。

AFTP

AFTP(Accelerated FTP),是 JSCAPE 开发的一种文件传输协议(中文:加速文件传输协议),旨在进行 WAN 环境下的文件传输,尤其是远距离下的文件传输,但很容易受到延迟和数据包丢失等不良网络条件的影响,从而导致吞吐量大幅下降。AFTP 是一种 TCP-UDP 混合体,它使文件传输几乎不受这些网络条件的影响,理想情况下能比 FTP 传输快 100 倍。属于企业级应用协议。

raysync

镭速文件传输协议 FTP 加速产品是专为企业定制开发的一款完全替代现有文件传输协议 FTP 的高效传输软件,能够在现有结构的基础上实现文件的高速传输,使用镭速文件传输协议 FTP 加速后,文件传输协议 FTP 传输速度可提升 10-100 倍。

这是国产深圳的一个公司的商业化产品。

PeSIT

PeSIT, short for Protocol d'Echanges pour un Systeme Interbancaire de Telecompensation (Protocol for data Exchange within the French Systems for Interbank Tele-clearance) 协议是一种端到端文件传输协议,由法国银行间电信系统经济利益集团 (GSIT) 开发。它在北美应用较少,主要用于满足欧洲银行标准,以及向欧洲银行和从欧洲银行转移通信。

see also What is PeSIT?

内网文件共享选择协议建议

20220616150310

image source

  • samba 对于大多数人绝对是最优最优的选择,适配日常使用的所有平台,没有各种乱码问题,兼容性极佳。目前的 samba3 samba4 性能也不错
  • 对于 Linux 用户可以优选 NFS,效能比起 samba 还是高
  • 平常使用 Linux 传送一些小文件可以直接使用 scp 命令行,或者使用 WinSCP 这些工具(或者更推荐使用 rsync)
  • 如果是内网磁盘想要暴露到公网,推荐 WebDAV + nginx + SSL,可以方便的将家里的磁盘暴露到公网(不过强烈建议使用 strong strong password)
  • DLNA 这种,偶尔使用多媒体还行,但如果是重度用户建议搭建 Plex、Emby、Jellyfin 服务端 (诶我怎么歪题了)
  • 其实内网的文件共享需求和 nas 上文件共享需求不谋而合
  • FTP, SFTP 不是很推荐
  • HTTP 配合 nginx 搭建一个存储文件的静态 public 站点还是不错的

引用一段 V2EX 网友的评论 来自帖子 https://www.v2ex.com/t/818478

奉劝一句,别瞎折腾。最完善的远程文件访问协议就是 SMB 。macOS 下 Finder 中协议语法为“SMB://”。在群晖、威联通中打开 SMB 协议访问即可。
别玩苹果自身的 AFP ,macOS 间互访都有 bug ,苹果默认都不用这个,默认用的是 SMB (我家里有 3 台苹果电脑,6 台不同的 NAS 设备,足够验证这个)。群晖启用 AFP 也有 bug ,反倒是威联通的 AFP 比较完善。
也别冲 WebDAV ,这个居然自身没搞定文件名编码方案(当然我猜测实际上应该是搞定了,我说的没搞定是默认配置下没搞定,估计需要用户各种场景测试然后通过命令行什么的指定编码方案)。我的一些小姐姐影片 NAS 间同步后文件名就变了。
FTP 这些完全是闹着玩的,首次配置好能用,过一段时间登录就有问题。
截至今日,世界上使用最广的操作系统依然是 windows ,至今依然是 windows 自己的远程文件访问协议其他厂商支持 /测试的最完善,那就是 SMB ( Samba )。其他的各种协议,不同操作系统中要么不自带需要安装第三方软件,即使带了默认可能也没启用需要用户自己启用甚至配置。考虑到家用环境的复杂性,iOS 设备、安卓设备、电视、windows 、macos 、NAS 、甚至可能还有监控摄像头存储,这些不同操作系统要同时支持 /验证某个文件互访协议,想想都能明白有多麻烦。

结合我自身的各种协议的使用经验,我的整体评价也是,samba 保你用户体验,一般情况下 samba 就够了,需要公网映射就加上 WebDAV。

4. 个人公网文件管理方案

我们可以用各种大公司的云产品,比如百度云盘,阿里云盘,夸克网盘等等,这些是面向普通用户的产品。还有一些面向开发者、企业的云产品等等不在本文讨论范围。我们想要知道的是普通用户如何建立起属于自己的公网网盘。我搜集了一些开源产品。见下表

名称 开源仓库 优缺点
NextCloud
(其前身是 OwnCloud)
https://github.com/nextcloud
  • 功能极其强大,具备丰富的 extensions
  • 后端核心程序使用 php 开发,效率并不算优
  • Seafile https://github.com/haiwen/seafile
  • 功能稍微单一,但是后端核心程序使用 C 语言编写,文件传输高效
  • Cloudreve https://github.com/cloudreve/Cloudreve
  • Material-UI 个人认为简洁美观
  • 支持本机、从机、七牛、阿里云 OSS、腾讯云 COS、又拍云、OneDrive (包括世纪互联版) 作为存储端
  • 后端原本是 php 编写,而后使用了 Golang 重构
  • ZFile https://github.com/haiwen/seafile
  • 基于 Java 的在线网盘程序,支持对接 S3、OneDrive、SharePoint、又拍云、本地存储、FTP 等存储源,支持在线浏览图片、播放音视频,文本文件等文件类型
  • KodExplorer(可道云) https://github.com/kalcaddle/KodExplorer
  • 类似于群晖桌面式 ui,适合对于计算机操作不熟悉的用户使用
  • 他们发布了新产品 kodbox https://github.com/kalcaddle/kodbox
  • 我目前几乎是 我全都要.gif,但是最终留下了 SeafileNextcloudCloudreve 三款产品。

    下文我将介绍在局域网搭建一个 Seafile Server,然后通过一台具备公网 IP 的机器将其服务暴露到公网 serving.

    5. 自建 Seafile Server 并使用 frp 暴露到公网

    我简而言之。

    5.1 使用 docker-compose 安装 Seafile Server

    compose file 参考官网的 https://docs.seafile.com/d/cb1d3f97106847abbf31/files/?p=/docker/docker-compose.yml

    也可以参考 https://cloud.seafile.com/published/seafile-manual-cn/docker/%E7%94%A8Docker%E9%83%A8%E7%BD%B2Seafile.md

    创建 /your/path/seafile-compose.yml,内容如下

    version: '2.0'
    services:
      db:
        image: mariadb:10.5
        container_name: seafile-mysql
        environment:
          - MYSQL_ROOT_PASSWORD=123456 # Requested, set the root's password of MySQL service.
          - MYSQL_LOG_CONSOLE=true
        volumes:
          - ./seafile-mysql/db:/var/lib/mysql  # Requested, specifies the path to MySQL data persistent store.
        networks:
          - seafile-net
    
      memcached:
        image: memcached:1.6
        container_name: seafile-memcached
        entrypoint: memcached -m 256
        networks:
          - seafile-net
    
      seafile:
        image: seafileltd/seafile-mc:latest
        container_name: seafile
        ports:
          - "8088:80"
    #      - "443:443"  # If https is enabled, cancel the comment.
        volumes:
          - ./seafile-data:/shared   # Requested, specifies the path to Seafile data persistent store.
        environment:
          - DB_HOST=db
          - DB_ROOT_PASSWD=123456  # Requested, the value shuold be root's password of MySQL service.
          - TIME_ZONE=Asia/Shanghai # Optional, default is UTC. Should be uncomment and set to your local time zone.
          - [email protected] # Specifies Seafile admin user, default is '[email protected]'.
          - SEAFILE_ADMIN_PASSWORD=123456     # Specifies Seafile admin password, default is 'asecret'.
          - SEAFILE_SERVER_LETSENCRYPT=false   # Whether use letsencrypt to generate cert.
          - SEAFILE_SERVER_HOSTNAME=192.168.x.x:8088 # Specifies your host name.
        depends_on:
          - db
          - memcached
        networks:
          - seafile-net
    
    networks:
      seafile-net:
    # 启动一个 docker stack, 建立三个容器
    # docker-compose -f ./seafile-compose.yml up -d

    默认 WebDAV 是关闭的,我们将它打开

    docker exec -it seafile bash 进入容器

    # 下面这是在容器中
    
    # vim /shared/seafile/conf/seafdav.conf
    
    # 将 [WEBDAV] enabled 由 false 改成 true
    
    # 然后重启 seafile 服务
    
    # cd /opt/seafile/seafile-server-9.0.4 #读者操作的时候 latest 镜像版本应该比这个更新
    
    # ./seafile.sh restart
    
    Stopping seafile server ...
    Starting seafile server, please wait ...
    ** Message: 20:02:59.972: seafile-controller.c(621): No seafevents.
    
    Seafile server started
    
    Done.

    Seafile Server 基本就部署好了。

    5.2 在公网机器上安装 frps

    FRP 是一个非常优秀的内网穿透程序,GitHub 链接: https://github.com/fatedier/frp ,其在 GitHub 上拥有 57.2k 个 star(截止 2022-06-15)。很多用户家里的网络 NAT 类型都是 Symmetric 对称型,我们一般称之为 NAT type 4,是一种最难穿透的类型。这种 nat 要想穿越成功,如果用户没法提升 nat 类型(最高 nat 1,叫做 FullCone 全锥形),那就必须要使用一台公网服务器中转,但这其实也是一种最高效的方式(花钱就行)。

    关于 nat 类型和 nat 的打洞方式也不是本文重点,此处就不多言了。

    如何搭建 frps 这一部分互联网上已经有太多教程,我简单综述一下。

    1. frp 是 go 写的,搭建 frp 环境需要一台具备公网的 VPS 或者国内叫轻量应用服务器,云服务器之类的
    2. 在公网机器上运行 frps(binary, Linux 可执行文件),需配合 frps.ini 配置文件
    3. 在内网机器(Seafile Server 所在机器)运行 frpc,需配合 frpc.ini 配置文件

    比如拉取 frp x86_64 0.39.0 版本的源程序

    # wget -O /home/xxx/temp/frp_0.39.0_linux_arm64.tar.gz https://github.com/fatedier/frp/releases/download/v0.39.0/frp_0.39.0_linux_arm64.tar.gz

    配置一下 /usr/local/frp/frps.ini 配置文件,以下所有端口都使用了 12345 代替

    # [common] is integral section
    [common]
    # A literal address or host name for IPv6 must be enclosed
    # in square brackets, as in "[::1]:80", "[ipv6-host]:http" or "[ipv6-host%zone]:80"
    bind_addr = 0.0.0.0
    bind_port = 12345
    # udp port used for kcp protocol, it can be same with 'bind_port'
    # if not set, kcp is disabled in frps
    kcp_bind_port = 12345
    # bind udp port
    bind_udp_port = 12345
    # if you want to configure or reload frps by dashboard, dashboard_port must be set
    dashboard_port = 12345
    # dashboard assets directory(only for debug mode)
    dashboard_user = YOUR_USERNAME
    dashboard_pwd = YOUR_PASSWORD
    # assets_dir = ./static
    vhost_http_port = 12345
    vhost_https_port = 12345
    # console or real logFile path like ./frps.log
    log_file = /var/log/frp/frps.log
    # debug, info, warn, error
    log_level = info
    log_max_days = 3
    # auth token
    token = A_STRONG_PASSWORD
    # only allow frpc to bind ports you list, if you set nothing, there won't be any limit
    #allow_ports = 1-65535
    # pool_count in each proxy will change to max_pool_count if they exceed the maximum value
    max_pool_count = 50
    # if tcp stream multiplexing is used, default is true
    tcp_mux = true

    Systemd 是 Linux 系统工具,用来启动守护进程,现已成为大多数发行版的标准配置。我们也用 systemd 管理 frps 和 frpc。创建文件 /lib/systemd/system/frps.service 内容如下

    [Unit]
    Description= Frps Service Daemon
    After=network.target remote-fs.target nss-lookup.target
    
    [Service]
    Type=simple
    ExecStart=/usr/local/frp/frps -c /usr/local/frp/frps.ini
    KillSignal=SIGQUIT
    TimeoutStopSec=5
    KillMode=process
    PrivateTmp=true
    StandardOutput=syslog
    StandardError=inherit
    
    [Install]
    WantedBy=multi-user.target

    启用开机自启

    # systemctl enable frps

    启动程序

    # systemctl start frps

    5.3 在内网机器上安装 frpc

    和 5.2 类似,我们需要 frpc 可执行程序和 frpc.ini 配置文件。

    创建配置文件 /etc/frp/frpc.ini,内容如下

    [common]
    log_file = /tmp/frpc.log
    log_level = info
    log_max_days = 3
    login_fail_exit = false
    protocol = tcp
    server_addr = example.com
    server_port = 12345
    tcp_mux = true
    token = A_STRONG_PASSWORD
    user = YOUR_USERNAME
    
    [second-n1-seafile]
    type = http
    custom_domains = seafile.example.com
    local_ip = x.x.x.x
    local_port = 8088
    remote_port = 12345
    use_compression = true
    use_encryption = true

    frpc 这边也使用 systemd 管理程序。创建 /lib/systemd/system/frpc.service,内容如下

    [Unit]
    Description=FRPC Client Daemon
    After=network.target
    Wants=network.target
    
    [Service]
    Type=simple
    ExecStart=/usr/bin/frpc -c /etc/frp/frpc.ini
    Restart=always
    RestartSec=20s
    User=xxx
    Group=xxx
    
    [Install]
    WantedBy=multi-user.target

    设置开机自启

    # systemctl enable frpc

    启动 frpc 程序

    # systemctl start frpc

    5.4 nginx 反代并套 SSL

    下面我们在 VPS 上使用 nginx 反代 seafile 服务,并使用 SSL/TLS 加密(在最外层套 SSL)。得先准备好申请好的证书和私钥(关于申请证书,免费的或是付费的,也不多言)。

    # 比如 nginx 配置中的证书和私钥形式如下
    
    ssl_certificate    /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key    /etc/letsencrypt/live/example.com/privkey.pem;

    创建 nginx 配置文件 /etc/nginx/sites-enabled/seafile-home.conf 内容如下

    server {
            listen       80;
            server_name  seafile.example.com;
            rewrite ^ https://$http_host$request_uri? permanent;    # Forced redirect from HTTP to HTTPS
            server_tokens off;
    }
    server {
            listen 443 ssl http2;
            ssl_certificate    /etc/letsencrypt/live/example.com/fullchain.pem;
            ssl_certificate_key    /etc/letsencrypt/live/example.com/privkey.pem;
            server_name seafile.example.com;
            server_tokens off;
    
            # HSTS for protection against man-in-the-middle-attacks
            add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
    
            ssl_protocols TLSv1.2 TLSv1.3;
            ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
            ssl_prefer_server_ciphers off;
    
            ssl_session_timeout 5m;
    
            location / {
                    proxy_pass         http://127.0.0.1:12345;
                    proxy_set_header   X-Real-IP $remote_addr;
                    proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
                    proxy_set_header   X-Forwarded-Host $server_name;
                    proxy_set_header   X-Forwarded-Proto https;
                    proxy_set_header   Host $host:$server_port;
    
                    access_log      /var/log/nginx/seahub.access.log;
                    error_log       /var/log/nginx/seahub.error.log;
    
                    proxy_read_timeout  1200s;
    
                    client_max_body_size 0;
            }
    }

    检查 nginx 语法并重载 nginx

    # nginx -t && nginx -s reload

    5.5 其他事项

    域名相关的东西就不说了。

    配置的时候注意可执行文件、配置文件的权限,和文件拥有者和所在组。

    还有防火墙。除了 Linux distro 自身安装的各种防火墙程序之外,类似良心云这种厂商在虚拟化的应用服务器之外还有一层硬件级别的防火墙,如果配置后发现不能访问可以优先往这些方面排查。

    然后就可以通过 https://seafile.example.com 访问属于自己的 seafile 服务了。

    5.6 我为什么推荐 Seafile?

    Seafile 社区版开源,足够个人使用,最重要的是核心服务由 C 编写,性能高,开销低,对于硬件配置友好。

    补充一个 seafile 开源版服务端架构

    • Seahub:网站界面,供用户管理自己在服务器上的数据和账户信息。Seafile 服务器通过 "gunicorn"(一个轻量级的 Python HTTP 服务器)来提供网站支持。Seahub 作为 gunicorn 的一个应用程序来运行。Seafile web 是 python web 框架 Django 开发的
    • Seafile server (seaf-server): 数据服务进程, 处理原始文件的上传/下载/同步,采用 C 语言编写
    • Controller: 监控 ccnet 和 seafile 进程,必要时会重启进程
    • 所有 Seafile 服务都可以配置在 Nginx/Apache 后面,由 Nginx/Apache 提供标准的 http(s) 访问
    • 当用户通过 seahub 访问数据时,seahub 通过内部 RPC 来从 seafile server 获取数据

    20220616231550

    image source

    作为单纯的文件服务器,我还是比较推荐 seafile 的,下面有一些速度截图。在内网传输如果硬件不是瓶颈的话,应该能吃满网卡带宽,试问有几个网盘能做到?但是如果想要功能上的丰富性,那么 NextCloud 和 Cloudreve 等将会是更好的选择。

    进入后台管理页面,可以随意切换公网和内网访问,大部分时候还是使用公网的域名访问配置
    20220616144938

    跑到了 100MiB/s,但是没有截到图 ?️
    20220616144704

    切换到内网,打开浏览器上传的速度,受限于机器性能,比如我的 Phicomm N1 最多只能跑到 50MiB/s
    20220616145227

    内网时使用 Firefox 下载的速度 97.6MB/sec 起飞~
    20220616222128

    在公网映射后下载的速度瓶颈一般是 VPS 的带宽了,拥有带宽越高的公网服务器,上传和下载、分享文件给别人下载等体验就会越好。

    全文完。

    6. 引用与致谢

    end.