Ubuntu 开启远程登录 SSH 的安装和配置

SSH 为 SecureShell 的缩写,由 IETF 的网络工作小组(NetworkWorkingGroup)所制定;SSH 是一种安全协议,主要用于给远程登录会话数据进行加密,保证数据传输的安全。利用 SSH 协议可以有效防止远程管理过程中的信息泄露问题。

更新源列表

打开”终端窗口”,输入 “sudo apt-get update” –> 回车 –> “输入当前登录用户的管理员密码” –> 回车,就可以了。

安装 SSH

在 “终端窗口” 输入 “sudo apt-get install openssh-server” –> 回车 –> 输入 “y” –> 回车 –> 安装完成。

sudo apt-get install openssh-server

查看 SSH 服务是否启动

打开”终端窗口”,输入 “sudo ps -e | grep ssh” –> 回车 –> 有 sshd,说明 ssh 服务已经启动,如果没有启动,输入 “sudo service ssh start” –> 回车 –> ssh 服务就会启动。

未分类

查看 Ubuntu 的 IP 地址

打开”终端窗口”,输入 “sudo ifconfig” –> 回车 –> 就可以查看到 IP 地址。

未分类

使用 Putty 远程登录

运行 putty –> 输入主机的 IP 地址、会话名称 –> 保存 。

未分类

双击 “会话名称” 打开连接 –> 输入用户名和密码 –> 登录成功。

未分类

登录之后可能会出现中文字符无法正确显示,只要在标题栏上右键 –> Chenge Settings… -> Translation -> Remote character set –> 选择 “UTF-8” –> 点击 “Apply” 即可。

未分类

未分类

CentOS 服务器修改或增加 SSH 端口

默认 SSH 默认端口为 22,所有服务器都一样,所以比较容易被别人扫描,尝试暴力破解登录。比较简单的办法,就是修改默认端口了。

修改 SSH 端口的方法本来挺简单的,网上也是一搜一把。

下面以修改为 10086 端口为例

1. 修改 /etc/ssh/sshd_config 文件,找到 Port 22 ,在其下方,增加 Port 10086

vi /etc/ssh/sshd_config

注意,这里是增加,而不是修改,主要是为了防止改了之后,新端口不能正确登录的麻烦。所以先新增,然后测试新端口能正确登录了,再将 Port 22 行注释掉即可。

2. 重启 sshd 服务

systemctl restart sshd

一般到这里也就可以试试新端口是否正确工作了。

但是阿里云服务器 ECS 有个安全组策略,需要手动设置其开放 10086 端口的访问:

3. 进入云服务器实例管理界面,左侧菜单“本实例安全组” > 配置规则,找到自定义 TCP (22/22)规则条目,> 克隆,修改协议类型为 “自定义 TCP”,端口范围设置为 10086/10086 ,提交保存即可。

如果经过上面步骤,新端口 SSH 依然连接超时,那么可能需要检查服务器防火墙设置,以及 SELinux 之类配置。

一般阿里云服务器,因为有上述安全组策略的存在,应该是默认没有开启防火墙的。因此前不知道阿里的安全组策略,我把下面几步都做了:

关于 SELinux 和 防火墙的相关配置和描述,请参考 皓煙:http://blog.csdn.net/ausboyue/article/details/53691953
对于使用 iptables 的服务器,请参考 http://blog.csdn.net/default7/article/details/42015409

在新端口连接测试通过之后,注意参考上述第 1 步注释掉原来的 22 端口配置,当然,也可以参考上述第 3 步,删除阿里 ECS 安全组策略里边的 自定义 ICP (22/22)规则条目。

因为 ECS 的安全组策略我是在走完 SELinux 和 防火墙,甚至包括 iptabls 等流程之后,依然连接超时,之后才知道的。现在我也在想:既然有了凌驾于服务器防火墙配置之上的 安全组策略存在了,那么防火墙、SELinux 之类的是不是也可以禁用了呢?

Linux下配置SSH无密码登录

  • 用ssh-keygen创建公钥
[root@qzweb1 .ssh]# ssh-keygen -t rsa    //生成密钥
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa):    //回车,使用默认目录
Enter passphrase (empty for no passphrase):     //直接回车设置空密码           
Enter same passphrase again:            //也是回车
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
e0:be:39:e4:08:a0:4c:e7:16:f5:bc:80:68:14:59:8a root@qzweb1
The key's randomart image is:
+--[ RSA 2048]----+
| .+.             |
|.o.  .           |
|E.. o +          |
|.+ + o +         |
|=.o . o S        |
|...o ...         |
|  .. +.          |
|    . oo         |
|      o.         |
+-----------------+
  • 查看生成出来的密钥
[root@qzweb1 .ssh]# cd ~/.ssh/
[root@qzweb1 .ssh]# ls -l
总用量 12
-rw-------  1 root root 1675 11月 23 15:14 id_rsa
-rw-r--r--  1 root root  393 11月 23 15:14 id_rsa.pub
-rw-r--r--. 1 root root 3176 11月 22 10:45 known_hosts
[root@qzweb1 .ssh]#
  • 下发公钥至目标机器
[root@qzweb1 .ssh]# scp id_rsa.pub 192.168.113.132:~/.ssh/
[email protected]'s password: 
id_rsa.pub                                                                                                                                                                                                                                  100%  393     0.4KB/s   00:00    
[root@qzweb1 .ssh]#
  • 配置目标机并设置文件和目录权限
[root@qzweb2 ~]# cd ~/.ssh/
[root@qzweb2 .ssh]# ls
id_rsa.pub
[root@qzweb2 .ssh]# cat id_rsa.pub >> authorized_keys
[root@qzweb2 .ssh]# chmod 600 authorized_keys  
[root@qzweb2 .ssh]# chmod 700 -R ~/.ssh 
[root@qzweb2 .ssh]#
  • 使用SSH进行连接
[root@qzweb1 .ssh]# ssh 192.168.113.132
Last login: Thu Nov 23 13:42:21 2017 from 192.168.81.24

相关说明

创建的~/.ssh/id_rsa、id_rsa.pub的文件,其中第一个为密钥,第二个为公钥。过程中会要求输入密码,为了ssh访问过程无须密码,可以直接回车。

ssh-keygen:生成秘钥的部分参数:
-t指定算法
-f 指定生成秘钥路径
-N 指定密码

相关说明2

ssh-copy-id 命令可以把本地的ssh公钥文件安装到远程主机对应的账户下。用法:

ssh-copy-id -i /root/.ssh/id_rsa 192.168.1.11

0
The authenticity of host '192.168.1.11 (192.168.1.11)' can't be established.
RSA key fingerprint is 6e:34:d4:8c:fb:72:72:3a:49:7a:14:23:20:59:ea:28.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.1.11' (RSA) to the list of known hosts.
[email protected]'s password: (输入192.168.1.11 root密码)
Now try logging into the machine, with "ssh '192.168.2.11'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

ssh-copy-id -i /root/.ssh/id_rsa 192.168.1.12
同上

ssh-copy-id -i /root/.ssh/id_rsa 192.168.1.13
同上

sftp上传文件到linux服务器上(ssh验证)

需求:

以前,手动上传配置文件到服务器,然后手工复制到另外一台服务器上,然后登陆SSH Secure File Transfer Client客户端,执行相关shell命令号
现在这些操作需要一键完成,即文件复制到另一台服务器,登陆ssh客户端,切换用户,执行导入命令行
解决办法:

  • 获得应用程序所在的机器用户名和密码,然后执行shell脚本完成以上操作
  • 未采用:因为运维不提供应用服务器的用户名和密码
    直接连接另一台服务器,执行复制文件,然后执行shell脚本(采取)
    要上传文件到linux服务器上,使用FTP协议,公司linux服务器上需要ftp客户端需要安全验证,比较麻烦,所以想到使用sftp来解决,sftp是基于ssh的安全协议的ftp协议,Java中有JSch包来实现连接服务器。

第一步:下载JSch包,请从官网下载它:http://www.jcraft.com/jsch/
第二步:新建FtpsFileList.java文件

//只有上传方法,也可以有下载文件方法
public class FtpsFileList {
    private static final Logger LOG = LoggerFactory.getLogger(FtpsFileList.class);

    //将本地的dirFile这个文件复制到远程服务器上的desFile文件夹下
    public static void loadFile(String host, int port, String username, final String password, String dirFile,String desFile) {
        ChannelSftp sftp = null;
        Channel channel = null;
        Session sshSession = null;
        try {
            JSch jsch = new JSch();//创建一个jsch对象
            jsch.getSession(username, host, port);
            // 根据用户名,主机ip,端口获取一个Session对象
            sshSession = jsch.getSession(username, host, port);
            //设置密码
            sshSession.setPassword(password);
            Properties sshConfig = new Properties();
            sshConfig.put("StrictHostKeyChecking", "no");
            // 为Session对象设置properties
            sshSession.setConfig(sshConfig);
            sshSession.connect();
            LOG.debug("Session connected!");
            // 打开SFTP通道
            channel = sshSession.openChannel("sftp");
            // 建立SFTP通道的连接
            channel.connect();
            LOG.debug("Channel connected!");
            sftp = (ChannelSftp) channel;

            //InputStream is = sftp.get("/ftp/re/20140713.dat");
            InputStream fis = new FileInputStream(new File(dirFile));
            //文件上传(通过inputstream流来实现)  详见https://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html
            sftp.put(fis,desFile);
            LOG.info("文件复制到服务器成功!r");

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeChannel(sftp);
            closeChannel(channel);
            closeSession(sshSession);
        }
    }

    private static void closeChannel(Channel channel) {
        if (channel != null) {
            if (channel.isConnected()) {
                channel.disconnect();
            }
        }
    }

    private static void closeSession(Session session) {
        if (session != null) {
            if (session.isConnected()) {
                session.disconnect();
            }
        }
    }
}

调用方式:

FtpsFileList.loadFile("10.31.92.70", 22, "serviceop", "115LbUrAbEsZw","/nfsc/qhcs-ansir-stg1/ansir/HanLP/xiaodai/loan-freebase.ttl","/wls/serviceop/virtuoso_script/loanXD.ttl");
logger.info("ttl文件复制成功");

到这一步,已经完成上传文件到linux服务器上

第三步:写好shell脚本(关键核心),这一步学习了好多东西,发现shell命令挺好玩的

#!/usr/bin/expect
spawn ssh [email protected]
set timeout 2
expect "password:"
send "115LbUrAbEsZwr"
expect "*]#"
set password "wuxin952"
spawn su root
expect "password:"  
send "wuxin952r" 
expect "#"
send "/wls/serviceop/virtuoso-opensource/home/bin/isql localhost:13002r" 
send "DB.DBA.TTLP_MT(file_to_string_output('/wls/serviceop/virtuoso_script/loan.ttl'),'','http://www.xiaowei.com');r"
interact

注释:因为需要交互式输入密码,所以选择使用expect命令环境来执行
具体释义见:

第四步:java代码调用shell脚本,代码如下,
Process类是一个抽象类,用于定义一个本地进程,Runtime.getRuntime().exec(sh)返回一个进程对象
具体见:process

//授予权利给shell脚本呢
Process ps1=Runtime.getRuntime().exec("chmod 777 /nfsc/qhcs-ansir-stg1/ansir/HanLP/xiaodai/bash_scp.sh");
//等待当前线程执行完,等待返回process类对象表示的进程结束
ps1.waitFor();
logger.info("chmod命令执行结束");

BufferedReader br1 = new BufferedReader(new InputStreamReader(ps1.getInputStream()));
while ((line = br1.readLine()) != null) {
    logger.info("chmod命令结果:"+line);
}
//实际调用使用expect 文件
Process ps2=Runtime.getRuntime().exec("expect /nfsc/qhcs-ansir-stg1/ansir/HanLP/xiaodai/bash_scp.sh");
ps2.waitFor();
logger.info("expect命令执行结束");

BufferedReader br2 = new BufferedReader(new InputStreamReader(ps2.getInputStream()));
while ((line = br2.readLine()) != null) {
    logger.info("expect命令结果:"+line);
}

String result = sb.toString();
logger.info("expect整理结果为:"+result);

记一次诡异的 ssh 互信免密码登录失败

0、背景

因为 hadoop 环境需要 master 能免密码 ssh localhost,所以我们需要建立与本机 localhost 的互信,方法很简单:

1. ssh-keygen -t rsa
   #Press enter for each line 
2. cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
3. chmod og-wx ~/.ssh/authorized_keys 

这三步执行下来就能顺利 ssh localhost 免密码登录了,但是昨天刚建好的互信,今天下午突然不能用了,ssh localhost 需要密码,第一反应是可能哪里设置和配置被改动了,看了下文件版本、配置修改时间都无变化,然而登录时的提示信息又过于简单,这个时候排查陷入僵局了。

work@test_zz_Master 192.168.187.213 18:45:18 ~ >
ssh localhost            
work@localhost's password: 

work@test_zz_Master 192.168.187.213 18:45:24 ~ >

1、怎么排查?

1.1 debug 日志

首先还是要拿到明细 debug 日志,看看卡在哪里了。linux 下的不少命令都自带调试功能,比如 ssh 就自带 debug 功能:

ssh -vvv localhost
OpenSSH_5.3p1, OpenSSL 1.0.1e-fips 11 Feb 2013
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug2: ssh_connect: needpriv 0
debug1: Connecting to localhost [127.0.0.1] port 22.
debug1: Connection established.
debug1: identity file /home/work/.ssh/identity type -1
debug1: identity file /home/work/.ssh/identity-cert type -1
...
debug3: remaining preferred: keyboard-interactive,password
// 启用公钥登录
debug3: authmethod_is_enabled publickey
debug1: Next authentication method: publickey
debug1: Trying private key: /home/work/.ssh/identity
debug3: no such identity: /home/work/.ssh/identity
debug1: Offering public key: /home/work/.ssh/id_rsa
debug3: send_pubkey_test
// 发送公钥包,等待服务器认证响应
debug2: we sent a publickey packet, wait for reply
debug3: Wrote 368 bytes for a total of 1741
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Trying private key: /home/work/.ssh/id_dsa
debug3: no such identity: /home/work/.ssh/id_dsa
debug1: Trying private key: /home/work/.ssh/id_ecdsa
debug3: no such identity: /home/work/.ssh/id_ecdsa
// 没通过认证,禁用该认证方法
debug2: we did not send a packet, disable method
debug3: authmethod_lookup password
debug3: remaining preferred: ,password
debug3: authmethod_is_enabled password
// 下一个认证方法:启用密码登录
debug1: Next authentication method: password
work@localhost's password: 

可以看到,确实是认证失败了,但是仅凭一句 we did not send a packet, disable method,咱们还是无法看到失败的深层次原因,那咱们再对比下正常的认证流程应该是怎样的:

未分类

可以看到右边正常的会接受公钥,左边的则没有得到响应,继续走别的认证方式。

1.2 检查配置

打开服务器的 /etc/ssh/sshd_config

确认下面几行是这样的:

RSAAuthentication yes
PubkeyAuthentication yes
AuthorizedKeysFile      .ssh/authorized_keys

#GSSAPIAuthentication yes
#GSSAPICleanupCredentials yes

配置没问题,此路还是不通。

1.3 Debugging SSH public key

在B机器上,we sent a public key packet, wait for reply 之后则是紧跟着”debug1: Server accepts key: pkalg ssh-rsa blen 277″。由此可以看出,是A机器的sshd不认可publickey。

至于为什么不认可,在google上查了许多,毫无头绪,直到使用类似“ssh publickey ignore debug diagnose”这样的关键词,发现这个页面,其中的第二条和第六条给出了解答:

2. Debugging on the remote host by running sshd in debug mode: Run ‘/usr/sbin/sshd -d -p 2222′ on the remote host and connect to it. ’2222′ here is the port number of the sshd process you started on the remote host.

6. Check the permissions on your home directory, .ssh directory, and the authorized_keys file: If your ssh server is running with ‘StrictModes on’, it will refuse to use your public keys in the ~/.ssh/authorized_keys file. Your home directory should be writable only by you, ~/.ssh should be 700, and authorized_keys should be 600.

通过执行 /usr/sbin/sshd -d -p 2222 (在2222端口启动一个带debug输出的sshd) ,

然后 ssh -vv localhost -p 2222 ,可以看到 sshd 的输出:

[root(hostname)@bjdhj-187-213 ~]# /usr/sbin/sshd -d -p 2222
debug1: sshd version OpenSSH_5.3p1
debug1: read PEM private key done: type RSA
...
debug1: trying public key file /home/work/.ssh/authorized_keys
debug1: fd 4 clearing O_NONBLOCK
Authentication refused: bad ownership or modes for directory /home/work
debug1: restore_uid: 0/0
debug1: temporarily_use_uid: 500/500 (e=0/0)
debug1: trying public key file /home/work/.ssh/authorized_keys
debug1: fd 4 clearing O_NONBLOCK
Authentication refused: bad ownership or modes for directory /home/work
debug1: restore_uid: 0/0
Failed publickey for work from 127.0.0.1 port 45548 ssh2

可以看到倒数第三行:Authentication refused: bad ownership or modes for directory /home/work,

正好与那第六条相对应,再检查一下 /home/work ,其权限是否是其他组可读写。

同时,咱们也能从 /var/log/secure 看到明细的 debug 日志:

[root(hostname)@bjdhj-187-213 ~]# tail -f /var/log/secure
Sep  1 18:52:20 bjdhj-187-213 sshd[30936]: Server listening on 0.0.0.0 port 22.
Sep  1 18:52:23 bjdhj-187-213 sshd[30944]: Authentication refused: bad ownership or modes for directory /home/work
Sep  1 18:52:23 bjdhj-187-213 sshd[30944]: Authentication refused: bad ownership or modes for directory /home/work
Sep  1 18:52:25 bjdhj-187-213 sshd[30948]: Connection closed by 127.0.0.1

2、最终解决方案

ssh 为了保证通信安全,防止 key 被篡改或窃取,对目录和文件的权限要求相当严格,

咱们最终需要确保相关目录权限与下述一致:

chmod 0755 ~               # 或 chmod g-w ~   
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

sudo service sshd restart

后记:

当然了,这篇文章所反映的问题虽然很小,最后的答案也很简单,但是其展现的排查思路和方法却很独特,值得借鉴,毕竟很多时候咱们不能像平时一样,直接 debug 源码。

使用 autossh 建立反向 SSH 隧道管理个人计算机

设你有这样一个需求:你在家中有一台 Linux/Unix 设备,可以是路由器、NAS 或者台式机,存有自己常用工具或者数据,想要在自己外出时也能随时访问。那么你现在的目的和我一样了,你所需要的是少许 Linux/Unix 经验以及一台能够从公网访问的中继服务器。我们所需要的技术是通过 SSH 隧道搭建一个反向代理。

配置

在你的 SSH 配置文件中加入这一行 GatewayPorts clientspecified。可以直接使用命令:sudo echo “GatewayPorts clientspecifie” >> /etc/ssh/sshd_config。

然后重新加载 SSH 配置文件:sudo reload ssh。

然后在本地建立连接: ssh -f -R 0.0.0.0:20000:localhost:22 local_user@a_a_a_a

现在还有两个问题:你需要保持终端开启防止 SSH 进程被关闭;由于网络故障/波动导致 SSH 终断时无法自动重连。

前者可以使用 -N 参数来解决,后者需要 supervisor 等第三方监控工具。

使用 autossh 代替 ssh

不过我们还有一个更常用的选择方案:autossh:

autossh -M 20001 
-fN -o "PubkeyAuthentication=yes" 
-o "StrictHostKeyChecking=false" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" 
-R a_a_a_a:20000:localhost:22 
-p 8383 remote_user@a_a_a_a

说明:

  • -M 20001 选项指定中继服务器上的监视端口,用于交换监视 SSH 会话的测试数据,需要保证该端口在服务器上未被占用。
  • -o 用于设置 autossh 参数。
  • -f 指定 autossh 在后台运行,并不会传给 ssh。和 ssh 的 -f 不一样,autossh 指定 -f 时将无法寻求密码。指定 -f 时,会将环境变量 AUTOSSH_GATETIME 覆盖为 0!

开机启动

在 Ubuntu 中我们可以使用 systemd 管理 autossh 的开机启动问题(旧版本中可以使用 init.d)。配置很简单,只需要创建一个 /etc/systemd/system/remote-autossh.service 文件:

[Unit]
Description=AutoSSH service for remote tunnel
After=network-online.target

[Service]
User=your_username
ExecStart=/usr/bin/autossh -M 20001 -N -o "PubkeyAuthentication=yes" -o "StrictHostKeyChecking=false" -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R a_a_a_a:20000:localhost:22 -p 8383 remote_user@a_a_a_a

[Install]
WantedBy=multi-user.target

这样就创建了一个 remote-autossh 服务,并指定其在网络服务启动后启动。可以运行 systemctl daemon-reload && systemctl start remote-autossh 立即启动服务,或者 systemctl enable remote-autossh.service 启动服务并设置为开机启动。

需要注意的是,配置文件中的 autossh 命令需要替换为其绝对地址,以及不支持 -f 参数。

ubuntu开启ssh服务

安装openssh-server

sudo apt-get update
sudo apt-get install openssh-server

查看ssh服务

sudo ps -e|grep ssh #是否存在sshd进程

如果没有sshd进程,执行:

sudo service ssh start

查看ubuntu IP

ifconfig

使用ssh客户端工具连接

ssh 你的ip

Linux下通过SSH实现服务器间简单的分发文件与执行命令

SSH介绍

SSH服务由服务端软件OpenSSH(openssl)和客户端(常见的有SSH(linux),SecureCRT,xshell,Putty)组成,SSH服务默认使用22端口提供服务,它有两个不兼容的SSH协议版本,分别是1.x和2.x.

SSH 1.x协议存在被黑客针对联机的Key pair插入恶意程序代码的风险,而SSH 2.x针对这个问题,多加了一个确认联机正确性的Diffie-Hellman机制,每次数据传输中,都会以该机制检查输出来源是否正确.

SSH的服务认证类型主要分为:

  • 基于口令的安全认证
  • 基于密钥的安全认证:首先建立一对密钥对,把公钥(public key)放在需要访问的目标服务器上.另外还需要吧私有密钥(private key)放到SSH的客户端或对应的客户端服务器上.

SSH的操作命令

SSH连接其他服务器

ssh -p22 [email protected] #被连接的主机

SSH通过远程连接执行命令

ssh -p22 [email protected] /sbin/ifconfig eht0

ssh 链接主机记录信息位置

~/.ssh/known_hosts

ssh客户端文件拷贝至远端服务器

可以通过 -l 参数限制传输速度.

scp -P22 -rp /tmp/oldboy [email protected]:/tmp/oldboy #方向由左至右

sftp功能?(不要用)

sftp无法显示登陆用户的目录,可以随时跳到别的目录

sftp -oPort=55555 [email protected]
get(download) put(upload)

实现SSH密钥批量分发

#确认系统版本信息
cat /etc/redhat-release
uname -r
uname -m
#添加批量分发账号
useradd fenfa (所有计算器创建分发账号)
echo 123456|passwd --stdin fenfa
#分发账号需要sudo授权rsync
echo "fenfa ALL=(ALL) NOPASSWD: /usr/bin/rsync" >>/etc/sudosers
visudo -c
#生成密钥对
ssh-keygen -t dsa
#查看密钥对
ls -l .ssh/
#分发密钥
ssh-copy-id -i .ssh/id_dsa.pub "-p [email protected]"
#测试
ssh -p55555 [email protected] /sbin/ifconfig

增量,加密传输文件:

rsync -avz hosts -e 'ssh -p55555' [email protected]:~

简单文件批量分发脚本(有待修改)

#!/bin/sh
. /etc/init.d/functions
if [ $# -ne 2 ]
then
echo "USAGE:/bin/sh $0 localfile remotedir"
exit 1
fi
for n in 1 2 3
do
scp -P55555 -r ~/$1 [email protected].$n:~ &>dev/null &&
ssh -p55555 -t [email protected].$n sudo rsync ~/$1 $2 &>/dev/null
if [ $? -eq 0 ]
then
action "fenfa $1 192.$n is ok" /bin/true
else
action "fenfa $1 192.$n is false" /bin/false
fi
done

简单的批量查看脚本

#!/bin/sh
if [ $# -ne 1 ]
then
echo "USAGE:$0 COMMAND"
exit 1
fi
for n in 1 2 3
do
echo ============192.168.117.$n========
ssh -p55555 [email protected].$n $1
done

非交互式生成密钥并实现批量管理

1、为所有机器创建传输用用户及密码

useradd key888
echo 123456|passwd --stdin key888
id key888
echo "key888 ALL=(ALL) NOPASSWD: ALL" >>/etc/sudoers 
visudo -c
su - key888

2、管理机创建密钥对

ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1

3、分发密钥

yum install expect -y #只安装在管理机
ssh-copy-id -i.ssh/id_dsa.pub "-p 52113 [email protected]"

4、此处需要三个脚本实现

fenfa_auto.sh

ssh_expect.exp

~/intall.sh

vi ssh_expect.exp
#!/usr/bin/expect
if { $argc != 2 }{
send_user "usage: expect ssh_expect.exp file hostn"
exit
}
#define var
set file [lindex $argv 0]
set host [lindex $argv 1]
set password "123456"
#spawn scp /etc/hosts [email protected]:/etc/hosts
#spawn scp -P55555 $file kendally@$host:$dirn
spawn ssh-copy-id -i $file "-p 55555 key888@host"
expect {
"yes/no"   {send "yes/r";exp_continue}
"*password"{send "$passwordr"}
}
expect eof
exit -onexit {
send_user "kendall say good bye to you!n"
}
#script usage
#expect kendall-6.exp file host 
#expaple
#expect ssh_expect.exp file host 
#expect ssh_expect.exp ~/.ssh/id_dsa.pub 172.16.1.31
vi fenfa_auto.sh
#!/bin/sh
. /etc/init.d/functions
shh-keygen -t dsa -P '' -f ~/.ssh/id_dsa >/dev/null 2>&1
if [ $? -eq 0 ];then
action "ccreat dsa $ip" /bin/true
else
action "create dsa $ip" /bin/false
exit 1
fi
for ip in 8 31 41
do
expect ssh_expect.exp ~/.ssh/id_dsa.pub 172.16.1.$ip >dev/null 2>&1
if [ $? -eq 0 ];then
action "$ip" /bin/true
else
action "$ip" /bin/false
fi
done
#dis fenfa scripts
for m in 8 31 41
do
scp -P55555 -rp ~/scripts [email protected].$m:~
done
#install service
for n in 8 31 41
do
ssh -t -p55555 [email protected].$n sudo /bin/bash ~/scripts/install.sh
done
vim intall.sh
yum install httpd -y

SSH反向连接及Autossh

简介

接触Linux恐怕对SSH再熟悉不过了,还有scp,sftp各种方便的功能,一般的使用都需要ip:port(如果不是默认22的话),但有些情况比较特殊,就是想连接一台内网主机(比如公司内网,当然你肯定做不了Port Forwarding,除非你想在公司防火墙上拆个洞)。稍懂一点网络的童鞋会明白,Internet上去主动连接一台内网是不可能的,一般的解决方案分两种,一种是端口映射(Port Forwarding),将内网主机的某个端口Open出防火墙,相当于两个外网主机通信;另一种是内网主机主动连接到外网主机,又被称作反向连接(Reverse Connection),这样NAT路由/防火墙就会在内网主机和外网主机之间建立映射,自然可以相互通信了。但是,这种映射是NAT路由自动维持的,不会持续下去,如果连接断开或者网络不稳定都会导致通信失败,这时内网主机需要再次主动连接到外网主机,建立连接。

环境

A要控制B

A主机:外网,ip:123.123.123.123,sshd端口:2221

B主机:内网,sshd端口:2223

无论是外网主机A,还是内网主机B都需要跑ssh daemon

一、使用SSH方式连接

1.1 首先在B上执行

$ ssh -NfR 1234:localhost:2223 [email protected] -p2221

这句话的意思是将A主机的1234端口和B主机的2223端口绑定,相当于远程端口映射(Remote Port Forwarding)。

这里每次需要输入A主机user1的登陆密码,后面会讲到解决办法。

1.2 这时在A主机上sshd会listen本地1234端口

$ ss -ant
State      Recv-Q Send-Q        Local Address:Port          Peer Address:Port
LISTEN     0      128               127.0.0.1:1234                     *:*

1.3 像平时一样连接到A主机的1234端口就可以控制内网B主机了

$ ssh localhost -p1234

二、使用Autossh方式

一开始提到,这种反向连接(Reverse Connection)不稳定,可能随时断开,需要内网主机B再次向外网A发起连接,这时需要个“朋友”帮你在内网B主机执行这条命令。它就是Autossh。

在此之前还要解决之前的一个问题,那就是每次内网主机B连接外网主机A时都需要输入密码,这个问题ssh本身是提供另外一种验证方式——通过密钥验证用户身份,实现自动登录。

2.1 在内网B主机上生产公钥和私钥

$ ssh-keygen
...(一直按Enter,最后在~/.ssh/下生成密钥)
$ ls ~/.ssh/
id_rsa id_rsa.pub known_hosts

2.2 复制B主机上生成的id_rsa.pub公钥到外网A主机上,并将内容加入到~/.ssh/authorized_keys中

$ cat id_rsa.pub >> ~/.ssh/authorized_keys

试下,内网B主机连接外网A主机,就不再输入密码验证了

补充:今天了解到ssh-copy-id这个命令,上面这个操作就变的简单了

$ ssh-copy-id [email protected]

2.3 再来看看Autossh的用法

$ autossh -M 5678 -NR 1234:localhost:2223 [email protected] -p2221

比之前的命令添加的一个-M 5678参数,负责通过5678端口监视连接状态,连接有问题时就会自动重连,去掉了一个-f参数,因为autossh本身就会在background运行。

三、终极方案:当重启内网B主机,谁来自动Autossh呢,加入daemon吧

以daemon方式执行,相当于root去执行autossh, ssh,这时刚才普通用户目录下的.ssh/authorized_keys文件会不起效。有两种办法解决,一种是用autossh的参数指定.ssh路径;另外一种是以普通用户身份执行daemon,下面是第二种方式。

/bin/su -c '/usr/bin/autossh -M 5678 -NR 1234:localhost:2223 [email protected] -p2221' - user1

autossh还有很多参数,用来设置重连间隔等等。

将上面命令放入下面各启动方式中,根据自己系统自己配置:

  • SysV:/etc/inid.d/autossh

  • Upstart: /etc/init/autossh.conf

  • systemd: /usr/lib/systemd/system/autossh.service

用啥ngrok,用ssh解决大局域网反向端口转发问题

自从家里换了联通光纤后,联通就在我家宽带出口前搭了一个路由器,我家也彻底沦为192.168.1.0/24段的局域网了,带来的问题就是在外网无法访问家里的路由器。这对于刷了LEDE,有时候需要从外网直接管理使用路由器的我,觉得难受极了。周末有空,干脆解决这个问题。

在这之前,了解过一个ngrok项目,用于将局域网内的某一个地址的端口,映射到公网。但是研究了一下该软件,发现其在LEDE的源中,并不包含,我又是个懒的去编译的程序员,因此想看看有没有其他办法。

研究一下,发现其实程序员必备的SSH就有这个功能。SSH一共支持三种端口转发:

  • 本地端口转发:就是客户端方的某个端口和服务器某个端口相连,这样访问客户端该端口,就相当于访问服务器端某个端口

  • 远程端口转发:还是把客户端方的某个端口和服务器某个端口相连,只不过反向的,访问服务器端某个端口,就相当于访问到了客户端该端口

  • 动态转发:SOCKS5代理模式,不多说了

更具体一些,可以参见这篇文章:https://blog.twofei.com/528/

回到我的需求,我是希望访问VPS的某个端口,就相当于访问路由器的指定端口。比如我访问VPS的2222,就相当于访问路由器的22端口。所以是第二种:远程端口转发

SSH做起来非常简单,首先,修改VPS端/etc/ssh/sshd_config加入GatewayPorts yes。据说,不这样外网无法访问转发的端口,未验证。然后路由器一条命令搞定:

ssh -f -NR "*:2222:localhost:22" user@vps  

这样子,访问VPS的2222端口,就直接访问到了路由器

进化一:持久

用ssh命令有个问题,因为各种因素,它可能会莫名挂掉,网络不好啦,网络干扰啦,网络xxx啦,总归都是网络问题。因此,我们得祭出神奇autossh。在LEDE的包中,默认就有,安装之,爱死LEDE。在这之前,自己搞定SSH的密钥登录哦,否则autossh起来,也会卡在输入密码。 autossh在LEDE的配置文件是/etc/config/autossh,配置一下

config autossh 'ssh'  
    option gatetime '0'
    option monitorport '20000'
    option poll '600'
    option ssh '-p 22 -NR *:2222:localhost:22 user@vps'

然后开启autossh

进化二:隐藏

在我家的运营商,我发现了一个问题,如果你ssh启动一段时间后,到目的地址的网络丢包就开始大量出现。思来想去,把ssh塞到ssr-tunnel中不就完事了。

先建立一个到VPS的22端口的ssr-tunnel隧道

ssr-tunnel -c /var/etc/shadowsocksr.json -l 2222 -L VPS:22 -f /tmp/ssr-tunnel.pid >> /tmp/ssr-tunnel.log  

这样,访问本机的2222端口,就相当于走ssr流量访问远端的22端口。把autossh的配置稍微改一下,让其访问本机2222端口

config autossh 'ssh'  
    option gatetime '0'
    option monitorport '20000'
    option poll '600'
    option ssh '-p 2222 -NR *:2222:localhost:22 vpsuser@localhost'

为了让ssr-tunnel隧道保持运行,需要搞个监控。不需要很复杂,放到crontab里就可以了

ps | grep [s]sr-tunnel || `ssr-tunnel -c /var/etc/shadowsocksr.json -l 2222 -L vps:22 -f /tmp/ssr-tunnel.pid >> /tmp/ssr-tunnel.log`  

进化三:多射

映射了第一个端口,你就想再来一个。什么aria2映射出来,就可以做外网离线下载。其实也蛮简单的,因为autossh支持多端口映射

config autossh 'ssh'  
    option gatetime '0'
    option monitorport '20000'
    option poll '600'
    option ssh '-p 2222 -NR *:2222:localhost:22 -NR *:6800:localhost:6800 vpsuser@localhost'

这样就把aria2的6800也映射出来了

就这样,结束了.

related post: http://briteming.blogspot.com/2016/04/ngrok.html

SSH的三种端口转发(Port forwarding)/ 隧道协议概要

用SSH有一段时间了,自认为对ssh的操作还是有一定的了解。而今天我要介绍的是ssh的三种端口转发(隧道协议、Tunnel、Port forwarding)功能的使用与它们的使用场合。

为什么要用ssh的端口转发功能,我想大家一定明白(不明白也无所谓,既然来到了这里,你肯定是想把它弄明白的!)。一来是为了安全(数据加密传输);二来是为了突破(穿越)某些防火墙对某些主机的访问限制。

据我所知,SSH一共提供了 3 种端口转发,分别是本地转发(-L参数)、远程转发(-R参数)和动态转发(-D参数)。接下来我就一一介绍这几种不同的转发方式的使用。我尽量简明扼要地叙述主题重点,让人一看就学会(回忆起)该如何操作。

本文用到的一些“术语”和约定

既然提到转发,就应该明白:这是三台主机之间要合作干的事。不然为何不两台主机直连,而要通过第三者转发?
本地主机:形式为IP或域名,你当前正在使用的这台机器;
远程主机:形式与本地主机一样。这里的“远程”并不是指实际的距离有多远,准确地说是“另一台”;

本地转发

本地转发,顾名思义(有点)就是把本地主机端口通过待登录主机端口转发到远程主机端口上去。

本地转发通过参数 -L 指定,格式:-L [本地主机:]本地主机端口:远程主机:远程主机端口。加上ssh待登录主机,这里就有了三台主机。

举例:ssh -L 50000:www.google.com:80 user@host。例中本地主机、远程主机和待登录主机分别用颜色红绿蓝标识。

当成功执行上面的命令之后,访问本地的50000端口,就等同于访问 www.google.com 的 80 端口。但和直接访问有着本质的区别:这次是通过登录主机来安全转发数据的,没有人知道你和远程主机之间传输了何种数据。就算你不能和远程主机建立连接(而登录主机能访问),那就能突破(绕过)(防火墙的)限制。

但本例其实举得不够好。就算你能访问 www.google.com,你却依然不能其它主机,甚至是 google域 的另一台主机,比如 plus.google.com。想要更全面的端口转发功能,还需动态转发。

远程转发

远程转发是指把登录主机端口通过本地主机端口转发到远程主机。
远程转发通过参数 -R 指定,格式:-R [登录主机:]登录主机端口:远程主机:远程主机端口。

举例:ssh -R 0.0.0.0:8080:localhost:80 user@host。

当成功执行上面的命令之后,访问登录主机的 8080 端口就相当于访问 localhost:80!

不要小看这个例子,它可是有相当有用。我书读得多,不会骗你 ????
设想这样一种情况(其实这种情况太普遍了):你在本机开发了一个web应用,想拿给别人测试,但现在你却处在内网,外网是无法直接访问内网的主机的,怎么办!?很多人可能会说,找台有公网IP的主机,重新部署一下就行了。这样可行,但太麻烦。然而自从你了解了ssh的远程转发之后,一切都变得简单了。只需在本地主机上执行一下上面例子的命令即可实现外网访问内网的web应用,相信我,我经常就这样干,屡试不爽。这简直是太好了,awesome! 让你从此对ssh爱不释手。

动态转发

相对于本地转发和远程转发的单一端口转发模式而言,动态转发有点更加强劲的端口转发功能,即是无需固定指定被访问目标主机的端口号。这个端口号需要在本地通过协议指定,该协议就是简单、安全、实用的 SOCKS 协议。FQ(你懂的)就靠她了!

动态转发通过参数 -D 指定,格式:-D [本地主机:]本地主机端口。相对于前两个来说,动态转发无需再指定远程主机及其端口。它们由通过 SOCKS协议 连接到本地主机端口的那个主机(peer,比如最常见的浏览器)指定(此属协议内容,无需深究)。

举例:ssh -D 50000 user@host。

当成功执行上面这个命令后。通过协议告诉你要访问的远程主机及端口,然后你与目标主机之间的数据就通过登录主机安全地传输了。

最常见的用途:FQ(大家都懂的)。在浏览器中设置代理类型为 SOCKS(5),主机及端口:127.0.0.1:50000。然后 gg/ytb/tt/fb 等就一丝不挂地摆在眼前了!