利用vsftpd搭建ftp文件服务器

Posted by wangtiegang on July 7, 2019

最近跟外部业务系统进行数据对接,其中涉及到对方要获取我们到附件,跟同事商量了一下后,最后决定搭建一个 ftp 文件服务器,让对方通过 url 从 ftp 服务器下载附件。之前没搭建过ftp服务器,了解了一下之后,发现大多是使用 vsftpd 软件去实现,才发现平时从各种电影网站下载电影到时候,那些 ftp:// 开头的下载链接都是 ftp 文件服务器,原来都不需要写代码。。。

安装vsftpd

运行 yum -y install vsftpd 命令进行安装,安装完成之后可以查看安装的版本如下:

vsftpd-1

可以看到配置文件也都在etc目录下

vsftpd-2

在vsftpd的相关路径中可以看到 /usr/lib/systemd/system/vsftpd.service 文件,所以也可以使用 systemctl 来管理 vsftpd 的服务。

vsftpd-3

vsftpd配置

vsftpd 默认开启匿名登陆,在启动服务之后,ftp文件夹默认在 /var/ftp/pub , 在浏览器中输入 ftp://172.16.133.133/ 即可以看 pub 文件夹,如果目录下有文件都话,点击文件即可以下载。

vsftpd-4

vsftpd 有三种登陆方式

  • 匿名登陆
  • 新建linux系统级别用户,再配置成 vsftpd 用户,通过用户名和密码登陆
  • 配置 vsftpd 虚拟用户,通过配置的用户名和密码登陆

本次选择配置虚拟用户的方式控制用户登陆,个人感觉这样会比较好。

编辑 /etc/vsftpd/vsftpd.conf 配置文件

  • 禁用匿名登陆

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    # 不允许匿名用户登入。
    anonymous_enable=NO
      
    # 是否允许本地用户登入,YES时可以通过linux系统用户登陆,文件目录默认为/home下的对应用户目录。
    local_enable=YES
    
    # 是否允许登陆用户有写权限。属于全局设置,默认值为YES。
    write_enable=YES/NO(YES)
    
    # 用于指定用户列表文件中的用户不允许切换到上级目录。
    chroot_local_user=YES
    
    # 还有很多其他配置项,可以根据情况自己设定。
    

    此时重启服务,刷新浏览器,会发现弹出登陆框,输入linux系统用户即可登陆到该用户目录下。

  • 配置虚拟用户登陆

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    # 增加,启用虚拟用户模式
    guest_enable=YES
    
    # 增加,配置虚拟用户映射到的本地用户名
    guest_username=wtg
    
    # 修改,配置虚拟用户的认证方式
    pam_service_name=/etc/pam.d/ftpvuser.pam
    
    # 增加,虚拟用户的配置文件目录
    user_config_dir=/etc/vsftpd/vuser.d
    
  • 刚刚配置了虚拟用户到认证方式,现在我们创建相关文件

    创建授权认证文件,进入 /etc/pam.d/ 目录,备份原来的 vsftpd 文件,创建新的 vsftpd 文件,内容如下:

    1
    2
    3
    
    #%PAM-1.0
    auth       required     pam_userdb.so db=/etc/vsftpd/vuser.d/vuser
    account    required     pam_userdb.so db=/etc/vsftpd/vuser.d/vuser
    

    创建虚拟用户的秘钥文件,此文件的格式为第一行是用户名,第二行是密码,第三行是用户名,第四行是密码,以此类推可以添加多个,执行 vi /etc/vsftpd/vuser.d/vuser.list,添加如下内容:

    1
    2
    
    vwtg
    vwtg
    

    使用db_load工具生成加密 vuser.list

    此处尴尬的是本地虚拟机无法操作,因为我虚拟机装的CentOs7,竟然找不到db4的包,下载离线的rpm包也找不到,db4还停留在CentOs6,无法继续操作下去。网上的博客大多写的没有顺序或不够明确,本来想实际操作然后按顺序记录的,现在有点不太确定是否配置正确和完整了,不过思路是没有问题的,同事在公司的CentOs6上安装了一个,可以使用

    1
    2
    3
    4
    5
    6
    7
    8
    
    # 安装db4工具
    yum install db4-utils -y
    
    # 加密
    db_load -T -t hash -f vuser.list vuser.db
      
    file vuser.list 
    file vuser.db 
    

    每个用户单独配置文件 /etc/vsftpd/vuser.d/vwtg ,文件名为虚拟用户名,可以根据需要添加相关配置内容:

    1
    2
    3
    4
    5
    6
    7
    8
    
    # 写权限
    write_enable=NO
    
    # 宿主目录
    local_root=/home/wtg
    
    # 能否上传
    anon_upload_enable=NO               
    

    配置完成重启服务器,如果一切正常,就可以使用虚拟用户登陆ftp服务器了。

java利用ftp协议上传下载文件到ftp服务器

  • 引入相关依赖

    1
    2
    3
    4
    5
    
      <dependency>
          <groupId>commons-net</groupId>
          <artifactId>commons-net</artifactId>
          <version>3.6</version>
      </dependency>
    
  • 上传代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    
    /**
     * @author : wangtiegang
     * @date : Create in 2019/7/1 10:14
     */
    public class FtpUtils {
    
      private static final Logger log = LoggerFactory.getLogger(FtpUtils.class);
    
      /**
       * 通过ftp服务上传文件
       * @param host
       * @param port
       * @param username
       * @param password
       * @param filename
       * @param input
       * @return
       */
      public static boolean uploadFile(String host, int port, String username, String password, String targetPath, String filename, InputStream input) {
          boolean result = false;
          FTPClient ftp = new FTPClient();
          try {
              int reply;
              // 连接FTP服务器
              ftp.connect(host, port);
              // 登录
              ftp.login(username, password);
              reply = ftp.getReplyCode();
              if (!FTPReply.isPositiveCompletion(reply)) {
                  log.error("FTP服务器返回状态码不合法: " + reply);
                  ftp.disconnect();
                  return result;
              }
              //切换到上传目录
              if (!ftp.changeWorkingDirectory(targetPath)) {
                  // 如果目录不存在创建目录
                  if(ftp.makeDirectory(targetPath)){
                      ftp.changeWorkingDirectory(targetPath);
                  }else {
                      log.error("ftp服务器创建目标路径失败:" + targetPath);
                      return result;
                  }
              }
              // 客户端开启被动模式,不开启被动模式会导致上传文件内容为空的情况
              ftp.enterLocalPassiveMode();
              // 设置上传文件的类型为二进制类型
              ftp.setFileType(FTP.BINARY_FILE_TYPE);
              // 上传文件, ftp服务默认ISO-8859-1编码
              String isoName = new String(filename.getBytes("UTF-8"),"ISO-8859-1");
              if (!ftp.storeFile(isoName, input)) {
                  log.error("ftp服务器保存文件失败:" + filename);
                  return result;
              }
              input.close();
              ftp.logout();
              result = true;
          } catch (IOException e) {
              log.error("ftp服务器上传文件失败:" + filename, e);
          } finally {
              if (ftp.isConnected()) {
                  try {
                      ftp.disconnect();
                  } catch (IOException ioe) {
                      log.error("ftp服务器断开连接失败:" + filename, ioe);
                  }
              }
          }
          return result;
      }
    
    }
    
  • 下载代码跟上传代码差不多,由于是业务系统那边技术写的,此处就不展示了。