使用SFTPGo搭建SFTP服务器

简介

SFTPGo是一款基于Go语言开发的简单易用的sftp server软件,支持Linux、MacOS及Windows平台。本文以Win10系统为例。

摘自网络:

FTP与SFTP区别:
ftp协议设计之初,分为了主动工作模式和被动工作模式,这两种工作模式一个是需要在服务器端随机开一个端口,让客户端连接这个新开的端口进行数据传输,一个是在ftp客户端随机开一个端口供服务器端主动连过来进行通讯,不管是哪一种对于有防火墙或者nat代理的网络都是极其不友好的,而且ftp通讯协议可以被wireshark等抓包工具轻易的抓出来登录ftp的用户名和密码,属于很不安全的一种通讯协议。
sftp协议基于tcp协议,只需要一个tcp端口即可完成全部的数据传输工作,对防火墙友好,通讯过程加密,不会被人轻易发现sftp的登录账户和密码信息,很适合作为ftp的替代品。

官网直飞

步骤:

如果是exe方式安装,按向导安装后可直接访问(服务自启动):

http://localhost:8080/web/admin/setup

或命令行启动:

sftpgo.exe service start --config-dir C:\ProgramData\SFTPGo --log-file-path logs\sftpgo.log

1 安装

winget install SFTPGo

2 打开控制台进行初始化配置

http://localhost:8080/web/admin

配置

方式一:命令行配置

Usage:
  sftpgo [command]

Available Commands:
  acme           Obtain TLS certificates from ACME-based CAs like Let's Encrypt
  gen            A collection of useful generators
  help           Help about any command
  initprovider   Initialize and/or updates the configured data provider
  ping           Issues an health check to SFTPGo
  portable       Serve a single directory/account
  resetprovider  Reset the configured provider, any data will be lost
  resetpwd       Reset the password for the specified administrator
  revertprovider Revert the configured data provider to a previous version
  serve          Start the SFTPGo service
  smtptest       Test the SMTP configuration
  startsubsys    Use sftpgo as SFTP file transfer subsystem

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

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

The serve command supports the following flags:

  • --config-dir string. Location of the config dir. This directory is used as the base for files with a relative path, eg. the private keys for the SFTP server or the SQLite database if you use SQLite as data provider. The configuration file, if not explicitly set, is looked for in this dir. We support reading from JSON, TOML, YAML, HCL, envfile and Java properties config files. The default config file name is sftpgo and therefore sftpgo.json, sftpgo.yaml and so on are searched. The default value is the working directory (".") or the value of SFTPGO_CONFIG_DIR environment variable.

  • --config-file string. This flag explicitly defines the path, name and extension of the config file. If must be an absolute path or a path relative to the configuration directory. The specified file name must have a supported extension (JSON, YAML, TOML, HCL or Java properties). The default value is empty or the value of SFTPGO_CONFIG_FILE environment variable.

  • --grace-time, integer. Graceful shutdown is an option to initiate a shutdown without abrupt cancellation of the currently ongoing client-initiated transfer sessions. This grace time defines the number of seconds allowed for existing transfers to get completed before shutting down. 0 means disabled. The default value is 0 or the value of SFTPGO_GRACE_TIME environment variable. A graceful shutdown is triggered by an interrupt signal or by a service stop request on Windows, if a grace time is configured.

  • --loaddata-from string. Load users and folders from this file. The file must be specified as absolute path and it must contain a backup obtained using the dumpdata REST API or compatible content. The default value is empty or the value of SFTPGO_LOADDATA_FROM environment variable.

  • --loaddata-clean boolean. Determine if the loaddata-from file should be removed after a successful load. Default false or the value of SFTPGO_LOADDATA_CLEAN environment variable (1 or true, 0 or false).

  • --loaddata-mode, integer. Restore mode for data to load. 0 means new users are added, existing users are updated. 1 means new users are added, existing users are not modified. Default 1 or the value of SFTPGO_LOADDATA_MODE environment variable.

  • --loaddata-scan, integer. Quota scan mode after data load. 0 means no quota scan. 1 means quota scan. 2 means scan quota if the user has quota restrictions. Default 0 or the value of SFTPGO_LOADDATA_QUOTA_SCAN environment variable.

  • --log-compress boolean. Determine if the rotated log files should be compressed using gzip. Default false or the value of SFTPGO_LOG_COMPRESS environment variable (1 or true, 0 or false). It is unused if log-file-path is empty.

  • --log-file-path string. Location for the log file, default "sftpgo.log" or the value of SFTPGO_LOG_FILE_PATH environment variable. Leave empty to write logs to the standard error.

  • --log-max-age int. Maximum number of days to retain old log files. Default 28 or the value of SFTPGO_LOG_MAX_AGE environment variable. It is unused if log-file-path is empty.

  • --log-max-backups int. Maximum number of old log files to retain. Default 5 or the value of SFTPGO_LOG_MAX_BACKUPS environment variable. It is unused if log-file-path is empty.

  • --log-max-size int. Maximum size in megabytes of the log file before it gets rotated. Default 10 or the value of SFTPGO_LOG_MAX_SIZE environment variable. It is unused if log-file-path is empty.

  • --log-level string. Set the log level. Supported values: debug, info, warn, error. Default debug or the value of SFTPGO_LOG_LEVEL environment variable.

  • --log-utc-time boolean. Enable UTC time for logging. Default false or the value of SFTPGO_LOG_UTC_TIME environment variable (1 or true, 0 or false)

Log file can be rotated on demand sending a SIGUSR1 signal on Unix based systems and using the command sftpgo service rotatelogs on Windows.

If you don't configure any private host key, the daemon will use id_rsa, id_ecdsa and id_ed25519 in the configuration directory. If these files don't exist, the daemon will attempt to autogenerate them. The server supports any private key format supported by crypto/ssh.

The gen command allows to generate completion scripts for your shell and man pages.

sftpgo.exe service --help
Manage the SFTPGo Windows Service

Usage:
  sftpgo service [command]

Available Commands:
  install     Install SFTPGo as Windows Service
  reload      Reload the SFTPGo Windows Service sending a "paramchange" request
  rotatelogs  Signal to the running service to rotate the logs
  start       Start the SFTPGo Windows Service
  status      Retrieve the status for the SFTPGo Windows Service
  stop        Stop the SFTPGo Windows Service
  uninstall   Uninstall the SFTPGo Windows Service

Flags:
  -h, --help   help for service

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

方式二:配置文件sftpgo.json

示例

{
  "common": {
    "idle_timeout": 15,
    "upload_mode": 0,
    "actions": {
      "execute_on": [],
      "execute_sync": [],
      "hook": ""
    },
    "setstat_mode": 0,
    "rename_mode": 0,
    "temp_path": "",
    "proxy_protocol": 0,
    "proxy_allowed": [],
    "proxy_skipped": [],
    "startup_hook": "",
    "post_connect_hook": "",
    "post_disconnect_hook": "",
    "data_retention_hook": "",
    "max_total_connections": 0,
    "max_per_host_connections": 20,
    "allowlist_status": 0,
    "allow_self_connections": 0,
    "defender": {
      "enabled": false,
      "driver": "memory",
      "ban_time": 30,
      "ban_time_increment": 50,
      "threshold": 15,
      "score_invalid": 2,
      "score_valid": 1,
      "score_limit_exceeded": 3,
      "score_no_auth": 0,
      "observation_time": 30,
      "entries_soft_limit": 100,
      "entries_hard_limit": 150
    },
    "rate_limiters": [
      {
        "average": 0,
        "period": 1000,
        "burst": 1,
        "type": 2,
        "protocols": [
          "SSH",
          "FTP",
          "DAV",
          "HTTP"
        ],
        "generate_defender_events": false,
        "entries_soft_limit": 100,
        "entries_hard_limit": 150
      }
    ]
  },
  "acme": {
    "domains": [],
    "email": "",
    "key_type": "4096",
    "certs_path": "certs",
    "ca_endpoint": "https://acme-v02.api.letsencrypt.org/directory",
    "renew_days": 30,
    "http01_challenge": {
      "port": 80,
      "proxy_header": "",
      "webroot": ""
    },
    "tls_alpn01_challenge": {
      "port": 0
    }
  },
  "sftpd": {
    "bindings": [
      {
        "port": 2022,
        "address": "",
        "apply_proxy_config": true
      }
    ],
    "max_auth_tries": 0,
    "banner": "",
    "host_keys": [],
    "host_certificates": [],
    "host_key_algorithms": [],
    "moduli": [],
    "kex_algorithms": [],
    "ciphers": [],
    "macs": [],
    "trusted_user_ca_keys": [],
    "revoked_user_certs_file": "",
    "login_banner_file": "",
    "enabled_ssh_commands": [
      "md5sum",
      "sha1sum",
      "sha256sum",
      "cd",
      "pwd",
      "scp"
    ],
    "keyboard_interactive_authentication": true,
    "keyboard_interactive_auth_hook": "",
    "password_authentication": true,
    "folder_prefix": ""
  },
  "ftpd": {
    "bindings": [
      {
        "port": 0,
        "address": "",
        "apply_proxy_config": true,
        "tls_mode": 0,
        "certificate_file": "",
        "certificate_key_file": "",
        "min_tls_version": 12,
        "force_passive_ip": "",
        "passive_ip_overrides": [],
        "passive_host": "",
        "client_auth_type": 0,
        "tls_cipher_suites": [],
        "passive_connections_security": 0,
        "active_connections_security": 0,
        "debug": false
      }
    ],
    "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,
        "certificate_file": "",
        "certificate_key_file": "",
        "min_tls_version": 12,
        "client_auth_type": 0,
        "tls_cipher_suites": [],
        "prefix": "",
        "proxy_allowed": [],
        "client_ip_proxy_header": "",
        "client_ip_header_depth": 0,
        "disable_www_auth_header": false
      }
    ],
    "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,
      "options_passthrough": false,
      "options_success_status": 0,
      "allow_private_network": false
    },
    "cache": {
      "users": {
        "expiration_time": 0,
        "max_size": 50
      },
      "mime_types": {
        "enabled": true,
        "max_size": 1000,
        "custom_mappings": []
      }
    }
  },
  "data_provider": {
    "driver": "sqlite",
    "name": "sftpgo.db",
    "host": "",
    "port": 0,
    "username": "",
    "password": "",
    "sslmode": 0,
    "disable_sni": false,
    "target_session_attrs": "",
    "root_cert": "",
    "client_cert": "",
    "client_key": "",
    "connection_string": "",
    "sql_tables_prefix": "",
    "track_quota": 2,
    "delayed_quota_update": 0,
    "pool_size": 0,
    "users_base_dir": "",
    "actions": {
      "execute_on": [],
      "execute_for": [],
      "hook": ""
    },
    "external_auth_hook": "",
    "external_auth_scope": 0,
    "pre_login_hook": "",
    "post_login_hook": "",
    "post_login_scope": 0,
    "check_password_hook": "",
    "check_password_scope": 0,
    "password_hashing": {
      "bcrypt_options": {
        "cost": 10
      },
      "argon2_options": {
        "memory": 65536,
        "iterations": 1,
        "parallelism": 2
      },
      "algo": "bcrypt"
    },
    "password_validation": {
      "admins": {
        "min_entropy": 0
      },
      "users": {
        "min_entropy": 0
      }
    },
    "password_caching": true,
    "update_mode": 0,
    "create_default_admin": false,
    "naming_rules": 5,
    "is_shared": 0,
    "node": {
      "host": "",
      "port": 0,
      "proto": "http"
    },
    "backups_path": "backups"
  },
  "httpd": {
    "bindings": [
      {
        "port": 8080,
        "address": "",
        "enable_web_admin": true,
        "enable_web_client": true,
        "enable_rest_api": true,
        "enabled_login_methods": 0,
        "enable_https": false,
        "certificate_file": "",
        "certificate_key_file": "",
        "min_tls_version": 12,
        "client_auth_type": 0,
        "tls_cipher_suites": [],
        "proxy_allowed": [],
        "client_ip_proxy_header": "",
        "client_ip_header_depth": 0,
        "hide_login_url": 0,
        "render_openapi": true,
        "web_client_integrations": [],
        "oidc": {
          "client_id": "",
          "client_secret": "",
          "config_url": "",
          "redirect_base_url": "",
          "scopes": [
            "openid",
            "profile",
            "email"
          ],
          "username_field": "",
          "role_field": "",
          "implicit_roles": false,
          "custom_fields": [],
          "insecure_skip_signature_check": false,
          "debug": false
        },
        "security": {
          "enabled": false,
          "allowed_hosts": [],
          "allowed_hosts_are_regex": false,
          "hosts_proxy_headers": [],
          "https_redirect": false,
          "https_host": "",
          "https_proxy_headers": [],
          "sts_seconds": 0,
          "sts_include_subdomains": false,
          "sts_preload": false,
          "content_type_nosniff": false,
          "content_security_policy": "",
          "permissions_policy": "",
          "cross_origin_opener_policy": "",
          "expect_ct_header": ""
        },
        "branding": {
          "web_admin": {
            "name": "",
            "short_name": "",
            "favicon_path": "",
            "logo_path": "",
            "login_image_path": "",
            "disclaimer_name": "",
            "disclaimer_path": "",
            "default_css": "",
            "extra_css": []
          },
          "web_client": {
            "name": "",
            "short_name": "",
            "favicon_path": "",
            "logo_path": "",
            "login_image_path": "",
            "disclaimer_name": "",
            "disclaimer_path": "",
            "default_css": "",
            "extra_css": []
          }
        }
      }
    ],
    "templates_path": "templates",
    "static_files_path": "static",
    "openapi_path": "openapi",
    "web_root": "",
    "certificate_file": "",
    "certificate_key_file": "",
    "ca_certificates": [],
    "ca_revocation_lists": [],
    "signing_passphrase": "",
    "token_validation": 0,
    "max_upload_file_size": 0,
    "cors": {
      "enabled": false,
      "allowed_origins": [],
      "allowed_methods": [],
      "allowed_headers": [],
      "exposed_headers": [],
      "allow_credentials": false,
      "max_age": 0,
      "options_passthrough": false,
      "options_success_status": 0,
      "allow_private_network": false
    },
    "setup": {
      "installation_code": "",
      "installation_code_hint": "Installation code"
    },
    "hide_support_link": false
  },
  "telemetry": {
    "bind_port": 0,
    "bind_address": "127.0.0.1",
    "enable_profiler": false,
    "auth_user_file": "",
    "certificate_file": "",
    "certificate_key_file": "",
    "min_tls_version": 12,
    "tls_cipher_suites": []
  },
  "http": {
    "timeout": 20,
    "retry_wait_min": 2,
    "retry_wait_max": 30,
    "retry_max": 3,
    "ca_certificates": [],
    "certificates": [],
    "skip_tls_verify": false,
    "headers": []
  },
  "command": {
    "timeout": 30,
    "env": [],
    "commands": []
  },
  "kms": {
    "secrets": {
      "url": "",
      "master_key": "",
      "master_key_path": ""
    }
  },
  "mfa": {
    "totp": [
      {
        "name": "Default",
        "issuer": "SFTPGo",
        "algo": "sha1"
      }
    ]
  },
  "smtp": {
    "host": "",
    "port": 25,
    "from": "",
    "user": "",
    "password": "",
    "auth_type": 0,
    "encryption": 0,
    "domain": "",
    "templates_path": "templates",
    "debug": 0,
    "oauth2": {
      "provider": 0,
      "tenant": "",
      "client_id": "",
      "client_secret": "",
      "refresh_token": ""
    }
  },
  "plugins": []
}

方式三:环境变量

You can also override all the available configuration options using environment variables. SFTPGo will check for environment variables with a name matching the key uppercased and prefixed with the SFTPGO_. You need to use __ to traverse a struct.

Let's see some examples:

  • To set the port for the first sftpd binding, you need to define the env var SFTPGO_SFTPD__BINDINGS__0__PORT

  • To set the execute_on actions, you need to define the env var SFTPGO_COMMON__ACTIONS__EXECUTE_ON. For example SFTPGO_COMMON__ACTIONS__EXECUTE_ON=upload,download

Telemetry Server

The telemetry server publishes the following endpoints:

  • /healthz, health information (for health checks)

  • /metrics, Prometheus metrics

  • /debug/pprof, if enabled via the enable_profiler configuration key, for profiling

客户端编码

maven依赖

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.7.13</version>
</dependency>

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.15</version>
</dependency>

<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

示例代码


import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.ssh.JschRuntimeException;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import cn.hutool.extra.ssh.JschUtil;
import cn.hutool.extra.ssh.Sftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;



public static void handler(String host, Integer port, String user, String pwd) {
    Session session = null;
    Sftp sftp = null;
    ChannelSftp channel = null;
    try {
        session = JschUtil.getSession(host, port, user, pwd);
        sftp = JschUtil.createSftp(session);
        channel = JschUtil.openSftp(session);

        String pwd1 = channel.pwd();
        Vector ls = channel.ls(pwd1);

        channel.mkdir("X1");
        channel.cd("X1");
        String pwd2 = channel.pwd();

        channel.mkdir("X2");
        channel.cd("X2");
        String pwd3 = channel.pwd();

        channel.mkdir("X3");
        channel.cd("X3");
        String pwd4 = channel.pwd();


        /*if (!destExist) {
            // 使用hutool创建目录有bug
            mkDirs(channel, destFtpUrl);
        }*/

        /*File zipFile = ZipUtil.zip("C:/Datas.json", "C:/Data_new");

        if (!sftp.exist("/XXX")) {
            mkDirs(channel, "/XXX");
        }

        sftp.upload("/XXX", zipFile);
        zipFile.delete();
        System.out.println(">>>>>>>>>>>>>>>>>>>>>");*/


    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (channel != null) {
            channel.disconnect();
        }

        if (sftp != null) {
            sftp.close();
        }

        if (session != null) {
            session.disconnect();
        }
    }
}


public static void mkDirs(ChannelSftp channel, String dir) throws SftpException {
    String[] dirs = StrUtil.trim(dir).split("[\\\\/]+");
    String now = channel.pwd();
    if (dirs.length > 0 && StrUtil.isEmpty(dirs[0])) {
        channel.cd("/");
    }

    String[] var4 = dirs;
    int var5 = dirs.length;

    for(int var6 = 0; var6 < var5; ++var6) {
        String s = var4[var6];
        if (StrUtil.isNotEmpty(s)) {
            boolean exist = true;

            try {
                channel.cd(s);
            } catch (SftpException e) {
                exist = false;
            }

            if (!exist) {
                mkdir(channel, s);
                channel.cd(s);
            }
        }
    }

    channel.cd(now);
}

public static boolean mkdir(ChannelSftp channel, String dir) throws SftpException {
    if (isDir(channel, dir)) {
        return true;
    } else {
        try {
            channel.mkdir(dir);
            return true;
        } catch (SftpException e) {
            throw new JschRuntimeException(e);
        }
    }
}

public static boolean isDir(ChannelSftp channel, String dir) throws SftpException {
    SftpATTRS sftpATTRS;
    try {
        sftpATTRS = channel.stat(dir);
    } catch (SftpException e) {
        if (e.getMessage().toLowerCase().contains("no such file")) {
            return false;
        }

        throw e;
    }

    return sftpATTRS.isDir();
}

常见异常

连接失败


java.net.ConnectException: Connection refused: connect

身份认证失败


JSchException: Auth fail

当连接数压到10000时,会抛出以下异常


session is down

Connection reset by peer: socket write error

channel is not opened

inputstream is closed


docker安装:

docker search sftpgo
docker pull drakkan/sftpgo:latest


# -e SFTPGO_HTTPD__BINDINGS__0__PORT=8080:指定web界面端口号
# 默认sftp端口号是2022
# -e SFTPGO_SFTPD__TLS_MODE=0 关闭tls认证


docker run --name sftpgo -p 8080:8080 -p 2022:2022 -p 2121:2121 -e SFTPGO_HTTPD__BINDINGS__0__PORT=8080 -e SFTPGO_FTPD__BINDINGS__0__PORT=2121 -e SFTPGO_SFTPD__TLS_MODE=0 -d "drakkan/sftpgo:latest"

# 参考
# docker run --name some-sftpgo -p 8080:8090 -e SFTPGO_HTTPD__BINDINGS__0__PORT=8090 -v /opt/sftp/data:/srv/sftpgo -v /opt/sftp/home:/var/lib/sftpgo -p 2022:2022 -e SFTPGO_SFTPD__TLS_MODE=0 -d "drakkan/sftpgo:v2.1.0"





docker pull drakkan/sftpgo:v2.5.4


# Start a sftpgo server instance
docker run --name some-sftpgo -p 8080:8080 -p 2022:2022 -d "drakkan/sftpgo:v2.5.4"


# Enable FTP service
# You can change the passive ports range (50000-50100 by default) by setting the environment variables SFTPGO_FTPD__PASSIVE_PORT_RANGE__START and SFTPGO_FTPD__PASSIVE_PORT_RANGE__END
docker run --name some-sftpgo \
    -p 8080:8080 \
    -p 2022:2022 \
    -p 2121:2121 \
    -p 50000-50100:50000-50100 \
    -e SFTPGO_FTPD__BINDINGS__0__PORT=2121 \
    -e SFTPGO_FTPD__BINDINGS__0__FORCE_PASSIVE_IP=<your external ip here> \
    -d "drakkan/sftpgo:tag"

# 访问地址
http://127.0.0.1:8080/web/admin/setup
http://127.0.0.1:8080/web/admin/login
http://127.0.0.1:8080/web/client/login

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wsdhla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值