热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

nginx正向代理SFTP整体配置方案

一、概述目前由于行内网络规划以及安全的原因,不能直接从应用区域直接访问第三方SFTP文件服务器,只能允许代理服务器网络区域出去,也就是SFTP正向代理转发到第三方的SFTP文件服务器,而我们使用的代理

一、概述
目前由于行内网络规划以及安全的原因,不能直接从应用区域直接访问第三方SFTP文件服务器,只能允许代理服务器网络区域出去,也就是SFTP正向代理转发到第三方的SFTP文件服务器,而我们使用的代理应用软件则是开源的nginx。以前搞过正向代理HTTP,而没有尝试过正向代理SFTP,其实也就是TCP协议。为了满足应用需求,我们需要搭建nginx正向代理SFTP服务应用。

nginx从 1.9.0开始,新增加了一个stream模块,用来实现四层协议的转发、代理或者负载均衡等。这完全就是抢HAproxy份额的节奏,鉴于nginx在7层负载均衡和web service上的成功,和nginx良好的框架,stream模块前景一片光明。

 

ngx_stream_core_module模块
是模拟反代基于tcp或udp的服务连接,即工作于传输层的反代或调度器

二、Nginx编译安装步骤

 

卸载

linux有一系列的软件管理器,比如常见的linux下的yum、Ubuntu下的apt-get等等。通过这些软件管理器可以很快的卸载软件,并且不会有文件及配置残留。这里我使用的是yum,命令如下

yum remove nginx

 

1、首先,要准备的是软件,可以在网上下载,http://nginx.org/en/download.html,我安装的是

 

nginx-1.16.0  pgp

 

 

2.解压并切换到安装目录

tar -zxvf nginx-1.16.0.tar.gz

cd nginx-1.16.0

3.编译安装

./configure --prefix=/xjld/app/nginx --sbin-path=/xjld/app/nginx/sbin/nginx --conf-path=/xjld/app/nginx/conf/nginx.conf --with-http_stub_status_module --with-http_gzip_static_module --with-stream


make && make install
检测是否安装完成:出现如下,则说明安装成功

Nginx启动和端口查看

 

4.修改配置文件

vim /xjld/app/nginx/conf/nginx.conf(在配置文件最后行添加如下)
PS:这个模块一定要放在http外面

s

stream {
upstream dnc_sftp {
hash $remote_addr consistent;
server 172.18.58.41:22 max_fails=3 fail_timeout=30s;
}

server{
listen 8080;
proxy_connect_timeout 5s;
proxy_timeout 5s;
proxy_pass dnc_sftp;
}

}

解析:

如上配置文件的含义为
将端口8080反向代理NAME1组的serverIP:PORT,最大失败次数为3,超时时间为30秒;
将端口60000反向代理NAME2组的serverIP:PORT,最大失败次数为3,超时时间为30秒。

5.检测语法

/opt/nginx/sbin/nginx -t

6.开启NGINX

/opt/nginx/sbin/nginx

7.重启NGINX

/opt/nginx/sbin/nginx -s reload

这里推荐使用reload而不是restart。

 


stream core 一些变量
(注意:变量支持是从 nginx 1.11.2版本开始的)
$binary_remote_addr 二进制格式的客户端地址 $bytes_received 从客户端接收到的字节数 $bytes_sent 发往客户端的字节数 $hostname 连接域名 $msec 毫秒精度的当前时间 $nginx_version nginx 版本 $pid worker进程号 $protocol 通信协议(UDP or TCP) $remote_addr 客户端ip $remote_port 客户端端口 $server_addr 接受连接的服务器ip,计算此变量需要一次系统调用。所以避免系统调用,在listen指令里必须指定具体的服务器地址并且使用参数bind。 $server_port 接受连接的服务器端口 $session_time 毫秒精度的会话时间(版本1.11.4开始) $status 会话状态(版本1.11.4开始), 可以是一下几个值: 200 成功 400 不能正常解析客户端数据 403 禁止访问 500 服务器内部错误 502 网关错误,比如上游服务器无法连接 503 服务不可用,比如由于限制连接等措施导致 $time_iso8601 ISO 8601时间格式 $time_local 普通日志格式的时间戳 
 

五.eclipse导入maven项目,修改配置文件,maven版本(apache-maven-3.3.3.rar)


  com.jcraft
  jsch
  0.1.55


六.测试

 

package dnc_util;

import com.ctid.util.file.SFtpUtil;

public class TestSftp {

public static void main(String[] args) throws Exception {
String host = "172.18.58.XX";
String username = "appmanagXX";
String password = "GBhnjm5XX";
int port = 22;
int timeOut = 10*1000;

String localFile = "D:/sftptest/New-net.log";
String destPath ="/xjld/test/te";

SFtpUtil st =new SFtpUtil();
st.connect(host, username, password, port, timeOut);
st.upload(localFile, destPath, "old.log", "New.log");

st.disconnect();

}

}

 

 

sftp工具类

 

package com.ctid.util.file;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ctid.core.exception.ServiceException;
import com.ctid.core.util.StringUtil;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.ChannelSftp.LsEntry;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
/**
* 用于SFTP文件上传下载
* @date 2019-06-14
* @author 王伟
*/
public class SftpUtil implements AutoCloseable{


private final Log LOGGER = LogFactory.getLog(SftpUtil.class);

//创建sftp通信通道
private ChannelSftp sftp = null;
private Session session = null;
//文件分割符,默认为linux系统
private static final String SEPARATOR = "/";


//SFTP协议
private final String SFTP_PROTOCAL = "sftp";
//默认登陆超时时间15s
private final int LOGON_TIME_OUT = 15*1000;
// //默认session中socket超时时间30分钟
private final int SOCKET_TIME_OUT = 30*60*60*1000;

/**
* 根据输入参数获取SFTP链接
* @param host 主机IP
* @param username 主机登陆用户名
* @param password 主机登陆密码
* @param port 主机ssh登陆端口,如果port <= 0取默认值(22)
* @param timeOut 登录超时,通道连接超时时间
* @throws Exception
* @see http://www.jcraft.com/jsch/
*/
public boolean connect(String host, String username, String password, int port,int timeOut) throws Exception {
boolean result = false;
Channel channel = null;
JSch jsch = new JSch();
if (timeOut <0) {
timeOut = LOGON_TIME_OUT;
}
session = createSession(jsch, host, username, port);
// 设置登陆主机的密码
session.setPassword(password);
session.setTimeout(SOCKET_TIME_OUT);
// 设置登陆超时时间
session.connect(timeOut);
try {
// 创建sftp通信通道
channel = (Channel) session.openChannel(SFTP_PROTOCAL);
channel.connect(timeOut);
sftp = (ChannelSftp) channel;
//设置根路径,远程以及本地,对于window系统不适用,window需要写绝对路径到盘符
sftp.cd(SEPARATOR);
sftp.lcd(SEPARATOR);
result = true;
} catch (JSchException e) {
LOGGER.error("exception when channel create. "+e.getMessage(), e);
throw new ServiceException("exception when channel create. "+e.getMessage(), e);
}
return result;
}

/**
* Private/public key authorization (加密秘钥方式登陆)
* @param username 主机登陆用户名(user account)
* @param host 主机IP(server host)
* @param port 主机ssh登陆端口(ssh port), 如果port<=0, 取默认值22
* @param privateKey 秘钥文件路径(the path of key file.)
* @param passphrase 密钥的密码(the password of key file.)
* @param timeOut 登录超时,通道连接超时时间
* @throws Exception
* @see http://www.jcraft.com/jsch/
*/
public boolean connect(String username, String host, int port, String privateKey, String passphrase,int timeOut)
throws Exception {
boolean result = false;
Channel channel = null;
JSch jsch = new JSch();
if (timeOut <0) {
timeOut = LOGON_TIME_OUT;
}
// 设置密钥和密码 ,支持密钥的方式登陆
if (!StringUtil.isEmpty(privateKey)) {
if (!StringUtil.isEmpty(passphrase)) {
// 设置带口令的密钥
jsch.addIdentity(privateKey, passphrase);
} else {
// 设置不带口令的密钥
jsch.addIdentity(privateKey);
}
}
Session session = createSession(jsch, host, username, port);
// 设置登陆超时时间
session.connect(timeOut);
try {
// 创建sftp通信通道
channel = (Channel) session.openChannel(SFTP_PROTOCAL);
channel.connect(timeOut);
sftp = (ChannelSftp) channel;
//设置根路径,远程以及本地,对于window系统不适用,window需要写绝对路径到盘符
sftp.cd(SEPARATOR);
sftp.lcd(SEPARATOR);
result = true;
} catch (JSchException e) {
LOGGER.error("exception when channel create."+e.getMessage(), e);
throw new ServiceException("exception when channel create."+e.getMessage(), e);
}
return result;
}

/**
* upload the file to the server

* 将本地文件名为 localFile 的文件上传到目标服务器, 目标文件名为 destFile,

* 采用默认的传输模式: OVERWRITE 覆盖式推送
* @param sftp
* @param localFile 本地文件的绝对路径
* @param destFile 目标文件的绝对路径
* @throws ServiceException
*/
public boolean upload(String localFile, String destFile) throws ServiceException {
boolean result = false;
try {
File file = new File(localFile);
if (file.isDirectory()) {
for (String fileName : file.list()) {
sftp.put(FileUtil.setDirectoryFile(localFile, fileName), destFile,ChannelSftp.OVERWRITE);
}
} else {
sftp.put(localFile, destFile, ChannelSftp.OVERWRITE);
}
result = true;
} catch (Exception e) {
LOGGER.error(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
throw new ServiceException(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
}
return result;
}

/**
* upload the file to the server

* 将本地文件名为 localFile 的文件上传到目标服务器, 目标路径为destPath,

* 目标文件名称为destFileName
* 采用默认的传输模式: OVERWRITE 覆盖式推送
* @param sftp
* @param localFile 本地文件的绝对路径
* @param destPath 目标文件的绝对目录路径
* @param destFileName 目标文件名称
* @throws ServiceException
*/
public boolean upload(String localFile, String destPath,String destFileName) throws ServiceException {
boolean result = false;
String destFile = "";
try {
//创建远程路径
createRemotedir(destPath);
//拼接远程路径+文件名
destFile = FileUtil.setDirectoryFile(destPath, destFileName);
sftp.put(localFile,destFile,ChannelSftp.OVERWRITE);
result = true;
} catch (Exception e) {
LOGGER.error(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
throw new ServiceException(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
}
return result;
}


/**
* upload the file to the server and rename file

* 将本地文件名为 localFile 的文件上传到目标服务器, 目标路径为destPath,

* 目标文件名称为destFileName,重命名后的文件名称为newFileName
* 采用默认的传输模式: OVERWRITE 覆盖式推送
* @param sftp
* @param localFile 本地文件的绝对路径
* @param destPath 目标文件的绝对目录路径
* @param destFileName 目标文件名称
* @param newFileName 重命名后的名称
* @throws ServiceException
*/
public boolean upload(String localFile, String destPath,String destFileName,String newFileName) throws ServiceException {
boolean result = false;
String destFile = destPath;
String newFile = "";
try {
//创建远程路径
createRemotedir(destPath);
//拼接远程路径+文件名
destFile = FileUtil.setDirectoryFile(destPath, destFileName);
sftp.put(localFile,destFile,ChannelSftp.OVERWRITE);
//新文件名不为空,拼接重命名后的新文件,并重新命名
if(!StringUtil.isEmpty(newFileName)){
newFile = FileUtil.setDirectoryFile(destPath, newFileName);
sftp.rename(destFile, newFile);
}
result =true;
} catch (Exception e) {
LOGGER.error(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
throw new ServiceException(localFile+" upload to "+destFile+" exception "+e.getMessage(), e);
}
return result;
}

/**
* 使用sftp下载文件,若本地存储路径下存在与下载重名的文件,忽略这个文件
* @param remotePath 服务器上源文件的路径, 必须是目录
* @param savePath 下载后文件的存储路径, 必须是目录
* @param remoteFileName 服务器上的文件名称
* @throws ServiceException
*/
public boolean download(String remotePath, String savePath,String remoteFileName) throws ServiceException {
boolean result = false;
try {
//切换到远程对应remotePath目录下
sftp.cd(remotePath);
//创建本地目录savePath
createLocalDir(savePath);
File localFile = new File(FileUtil.setDirectoryFile(savePath, remoteFileName));
// savePath路径下已有文件与下载文件重名, 忽略这个文件
if (localFile.exists() && localFile.isFile()) {
return true;
}
//下载远程文件到savePath,文件名称为remoteFile
sftp.get(remoteFileName, localFile+"");
result = true;
} catch (Exception e) {
LOGGER.error(remotePath+SEPARATOR+remoteFileName+" download to "+savePath+" exception "+e.getMessage(), e);
throw new ServiceException(remotePath+SEPARATOR+remoteFileName+" download to "+savePath+" exception " +e.getMessage(), e);
}
return result;
}

/**
* sftp下载目标服务器上remotePath目录下所有指定的文件.

* 若本地存储路径下存在与下载重名的文件,忽略这个文件.

* @param remotePath 服务器上源文件的路径, 必须是目录
* @param savePath 文件下载到本地存储的路径,必须是目录
* @param fileList 指定的要下载的文件名列表
* @throws ServiceException
*/
public boolean downloadFileList(String remotePath, String savePath,List fileList) throws ServiceException {
boolean result = false;
try {
sftp.cd(remotePath);
String localFile = "";
for (String srcFile : fileList) {
try {
localFile = FileUtil.setDirectoryFile(savePath, savePath);
File file = new File(localFile);
// savePath路径下已有文件与下载文件重名, 忽略这个文件
if (file.exists() && file.isFile()) {
continue;
}
sftp.get(srcFile, localFile);
} catch (Exception e) {
LOGGER.error(remotePath + SEPARATOR + srcFile+ " download to " + localFile + " exception "+e.getMessage(), e);
}
}
result = true;
} catch (Exception e) {
LOGGER.error(remotePath + " download to " + savePath + " exception "+e.getMessage(), e);
throw new ServiceException(remotePath + " download to " + savePath + " exception "+e.getMessage(), e);
}
return result;
}

/**
* 删除文件
* @param dirPath 要删除文件所在目录
* @param file 要删除的文件
* @param sftp
* @throws SftpException
*/
public boolean delete(String dirPath, String file) throws SftpException {
sftp.cd(SEPARATOR);
String now = sftp.pwd();
sftp.cd(dirPath);
sftp.rm(file);
sftp.cd(now);
return true;
}

/**
* 删除文件
* @param filePath 要删除文件的路径
* @param sftp
* @throws SftpException
*/
public boolean delete(String filePath) throws SftpException {
sftp.cd(SEPARATOR);
String now = sftp.pwd();
sftp.cd(getDirectory(filePath));
sftp.rm(getFileName(filePath));
sftp.cd(now);
return true;
}


/**
* @功能描述 从路径中抽取文件名
* @param path 路径
* @return 返回文件名
*/
private String getFileName(String path) {
try {
if (path.contains("\\")) {
return path.substring(path.lastIndexOf("\\") + 1);
}else if(path.contains("/")){
return path.substring(path.lastIndexOf("/") + 1);
}else{
return path;
}
} catch (Exception e) {
return null;
}
}
/**
* @功能描述 从路径中抽取目录
* @param path 路径
* @return 返回目录
*/
private String getDirectory(String filePath) {
try {
if (filePath.contains("\\")) {
return filePath.substring(0, filePath.lastIndexOf("\\") + 1);
}
return new File(filePath).getPath().substring(0, filePath.lastIndexOf("/") + 1);
} catch (Exception e) {
return null;
}
}
/**
* 获取remotePath路径下以regex格式指定的文件列表,传""或者null默认获取所有文件
* @param remotePath sftp服务器上的目录
* @param regex 需要匹配的文件名,
* @return 获取的文件列表
* @throws SftpException
*/
@SuppressWarnings("unchecked")
public List listFiles(String remotePath, String regex) throws SftpException {
List fileList = new ArrayList();
try{
// 如果remotePath不是目录则会抛出异常
sftp.cd(remotePath);
if ("".equals(regex) || regex == null) {
regex = "*";
}
Vector sftpFiles = sftp.ls(regex);
String fileName = null;
for (LsEntry lsEntry : sftpFiles) {
fileName = lsEntry.getFilename();
fileList.add(fileName);
}
}catch (Exception e) {
LOGGER.error("get file list from path :"+remotePath + " exception "+e.getMessage(), e);
fileList = null;
}
return fileList;
}

 

/**
* 根据用户名,主机ip,端口获取一个Session对象
* @param jsch jsch对象
* @param host 主机ip
* @param username 用户名
* @param port 端口
* @return
* @throws Exception
*/
private Session createSession(JSch jsch, String host, String username,int port) throws Exception {
Session session = null;
if (port <= 0) {
// 连接服务器,采用默认端口
session = jsch.getSession(username, host);
} else {
// 采用指定的端口连接服务器
session = jsch.getSession(username, host, port);
}
// 如果服务器连接不上,则抛出异常
if (session == null) {
throw new Exception(host + "session is null");
}
// 设置第一次登陆的时候提示,可选值:(ask | yes | no)
session.setConfig("StrictHostKeyChecking", "no");
return session;
}

/**
* 循环创建远程路径
* @param destDirPath
* @throws SftpException
*/
private void createRemotedir(String destDirPath) throws SftpException {
//设置根路径
sftp.cd(SEPARATOR);
String[] folders = destDirPath.split(SEPARATOR);
for (String folder : folders) {
if (folder.length() > 0) {
try {
// 如果folder不存在,则会报错,此时捕获异常并创建folder路径
sftp.cd(folder);
} catch (SftpException e) {
sftp.mkdir(folder);
sftp.cd(folder);
}
}
}
}
/**
* 创建本地路径
* @param savePath 本地文件路径
* @return
* @throws Exception
*/
private File createLocalDir(String savePath) throws Exception {
File localPath = new File(savePath);
if (!localPath.exists() && !localPath.isFile()) {
if (!localPath.mkdirs()) {
throw new Exception(localPath + " directory can not create. ");
}
}
return localPath;
}




/**
* Disconnect with server
* 断开sftp连接
*/
public void disconnect() {
try {
if (sftp != null) {
sftp.quit();
}
if (sftp != null) {
sftp.disconnect();
}
if (session != null) {
session.disconnect();
}
} catch (Exception e) {
sftp = null;
session = null;
}
}

@Override
public void close() throws Exception {
sftp.disconnect();
}

 

}


推荐阅读
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在Linux下安装Perl的步骤,并提供了一个简单的Perl程序示例。同时,还展示了运行该程序的结果。 ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • 本文介绍了在CentOS上安装Python2.7.2的详细步骤,包括下载、解压、编译和安装等操作。同时提供了一些注意事项,以及测试安装是否成功的方法。 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
  • centos6.8 下nginx1.10 安装 ... [详细]
  • 构建LNMP架构平台
    LNMP架构的组成:Linux、Nginx、MySQL、PHP关于NginxNginx与apache的作用一样,都是为了搭建网站服务器,由俄罗斯人lgorsysoev开发,其特点是 ... [详细]
  • linux下编译安装lnmp
    2019独角兽企业重金招聘Python工程师标准#######################安装依赖#####################安装必要的包:y ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • 本文介绍了在Windows环境下如何配置php+apache环境,包括下载php7和apache2.4、安装vc2015运行时环境、启动php7和apache2.4等步骤。希望对需要搭建php7环境的读者有一定的参考价值。摘要长度为169字。 ... [详细]
  • web.py开发web 第八章 Formalchemy 服务端验证方法
    本文介绍了在web.py开发中使用Formalchemy进行服务端表单数据验证的方法。以User表单为例,详细说明了对各字段的验证要求,包括必填、长度限制、唯一性等。同时介绍了如何自定义验证方法来实现验证唯一性和两个密码是否相等的功能。该文提供了相关代码示例。 ... [详细]
  • Imtryingtofigureoutawaytogeneratetorrentfilesfromabucket,usingtheAWSSDKforGo.我正 ... [详细]
  • nginx+多个tomcat
    学习nginx的时候遇到的问题:nginx怎么部署两台tomcat?upstream在网上找的资源,我在nginx配置文件(nginx.conf)中添加了两个server。结果只显 ... [详细]
  • linux搭建FTP
    linux下FTP的搭建及优化[日期:2007-11-04]李磊19840817吴康[字体:大中小]首先安装Linux企业版第一张光盘中的vsftpd- ... [详细]
  • Windows下实用工具整理
    Windows下实用工具整理命令工具cmder支持tab标签、集成git、支持绝大UnixLinux命令。但是安装之后一般都会有以下几个问题:中文乱码问题、文字重叠问 ... [详细]
author-avatar
烦恼的天伦之乐_456
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有