由于现在许多项目和工程都在云服务器上部署,对于程序员来说,日常工作中常常会有登陆远程服务器的需求,所以使用SSH就成了一项必备的技能。
SSH全称叫 Secure Shell(安全外壳协议,简称SSH),其实是一种加密的网络传输协议,能够在不安全的网络中为计算机之间的网络服务提供安全的传输环境。SSH最常见的用途是在本地远程登录服务器,或者远程使用命令行界面执行远程命令。
基本用法
$ ssh username@hostname
username
:需要登录的远程服务器的用户名hostname
:远程服务器的地址,IP地址或者是域名
第一次连接一台陌生的服务器时,会出现下面一段话的提示,意思是当前主机不认识这台机器,新连接的服务器的指纹是陌生的,询问用户选择是否需要继续连接。
$ The authenticity of host 'XXX.XXX.XXX.XXX (XXX.XXX.XXX.XXX)' can't be established.
ECDSA key fingerprint is SHA256:LkV6C+x7h9NmxqzU7EjZemgtzK04gDJ5uUqVbFmILxU.
Are you sure you want to continue connecting (yes/no)?
一台服务器的指纹,指的是你所 SSH 的服务器的公钥哈希值。每一台被 SSH 连接的服务器都有唯一的一对密钥对,用于跟客户端通信,其中公钥的哈希值就可以用来唯一识别服务器。
因此,我们只需要输入yes
,然后回车即可。然后根据要求输入密码,就可以登录到远程服务器中。
SSH 会将本机连接过的所有服务器的公钥指纹信息,都储存在本机的~/.ssh/known_hosts
文件中。每次通过 SSH 连接一台服务器时,系统会通过该文件判断当前需要连接的服务器是否为陌生主机。
-p
参数可以指定 SSH 客户端连接的服务器端口。一般情况下, SSH 的默认登录端口号为22。如果登录时想指定某一特定端口:
$ ssh username@hostname -p 22
如果之前 SSH 登录过的服务器的密钥发生了变更,例如重新生成了新的密钥对,那么此时 SSH 登陆时就会收到提示 Host key verification failed
. 因为我们所有登录过的服务器的信息都保存在./ssh/known_hosts
文件中,所以如果主机的指纹发生改变,我们就需要删除之前主机的指纹信息,并添加新的。一个办法是手动删除,然后进行重新连接。第二个办法是可以使用 ssh-key-gen -R <hostname>
来进行删除,而且用这种方式删除会自动将原内容备份成 known_hosts.old
文件,这样即方便还安全。该命令可以用-f
来指定known_hosts
文件,默认情况下会使用./ssh/known_hosts
文件。
$ ssh-keygen -R hostname [-f known_hosts_file]
密钥登陆
创建密钥:
首先在本台主机上创建密钥,输入下面的指令,然后一直回车即可。
$ ssh-keygen
该命令会为本机生成公私钥对,通过密钥来进行远程登录的验证机制使用了密码学中的非对称加密体系。命令结束后,会在~/.ssh/
文件夹下出现两个新的文件:
id_rsa
:私钥id_rsa.pub
:公钥
注意:一定要保护好生产的私钥id_rsa
,一旦暴露,最好输入上述命令重新生成新的密钥。
免密登陆
如果想要免密登陆某个服务器,我们只需要将刚才生成的公钥保存在需要登陆的远程服务器的~/.ssh/authorized_keys
文件中。
例如如果我想免密登录到myserver服务器。则将~/.ssh/id_rsa
公钥中的内容,复制到myserver中的~/.ssh/authorized_keys
文件里即可。
也可以使用如下命令一键添加公钥:
$ ssh-copy-id myserver
如果有多个公钥(ssh-keygen
时可以用-t
参数,可以指定密钥的加密算法,不同的加密算法生成的公私钥对不同),可以用-i
参数用来指定公钥文件。
$ ssh-copy-id -i key_file username@hostname
第一次应用ssh-copy-id
系统会提示输入远程服务器的密码,之后再次登录时就可以免密登陆了。
一般来说,应用密钥登陆比使用密码登录更安全,所以启用密钥登录之后,最好关闭服务器的密码登录。如果需要在远程服务器上关闭密码登录。具体方法是先远程登录到服务器中,然后找到 sshd 的配置文件/etc/ssh/sshd_config
,最后将PasswordAuthentication
这一项设为no
。
$ PasswordAuthentication no
sshd是服务器运行的后台进程,当修改配置文件以后,需要重新启动 sshd,然后修改才能生效。可应用下面语句重启远程服务器上的 ssh
和 sshd
服务。
$ sudo systemctl restart ssh.service
$ sudo systemctl restart sshd.service
免密登陆后,我们可以在命令行下直接执行远程命令:
$ ssh username@hostname command
文件传输
对于单个文件的传输我们可以通过ssh + tee
的方式,先执行 ssh
命令,然后通过这样的方法利用标准输入实现 cat localfile | ssh remote_server tee serverfile
。tee
命令的主要作用是会将标准输出写入到一个文件
而对于多个文件或文件夹时,更好的办法是通过 scp
来传输文件。scp
其实就是 secure copy 的缩写,相当于cp
命令 + SSH,使用scp
传输数据时,文件和密码都是加密的,一般来说会更加地安全。它的底层是 SSH 协议,默认端口是22,执行该命令时其实就是先通过ssh
命令登录远程到主机,然后再执行拷贝操作。
scp
一般可以下三种复制操作:
- 将本地文件复制到远程服务器上。
- 将远程服务器上的文件复制到本地。
- 可以在两个远程系统之间实现文件拷贝。
指令格式如下:
$ scp source destination
当需要拷贝大量的文件或目录时,使用scp
命令则更加方便,因为它可以方便的遍历相关路径。可以一次复制多个文件 ,如果需要传输的是文件夹,需加上 -r
参数:
# 传输多个文件
$ scp source1 source2 destination
# 传输文件夹
$ scp -r source1 source2 destination
scp
也可以像ssh一样指定服务器的端口号,注意这里的参数 -P
为大写:
$ scp -P 22 source1 source2 destination
配置文件
在当前主机上,个人的 SSH 的相关配置在配置文件~/.ssh/config里, 常见的设置是为不同服务器指定参数,例如别名和端口号,这样就不用每次都输入很长的服务器地址和重复的参数。
保存了以下配置后,需要再登陆远程服务器时,可以直接使用别名ssh myserver1
来连接。
Host myserver1
HostName IP地址或域名
User 用户名
Port 端口号
Host myserver2
HostName IP地址或域名
User 用户名
Port 端口号
端口转发
首先解释一下端口映射和端口转发的区别:
端口映射:
由于IP地址数量有限,IPv4地址被划分为公网IP和私网IP。其中公网IP是能直接通过地址连接上网络的IP。而私网IP是不会出现在互联网上的,所以是无法直接通过私网IP地址来访问到主机。所以一般来说如果有信息想通过互联网传输到一个私网IP地址上,必须通过公网IP地址来中转。这就是为什么你每次使用ifconfig查到的地址,要么就是172.开头的,要么就是192.开头的。
端口映射就是将内网的端口映射到公网的某个端口上,然后当用户访问该公网IP上的这个端口时,服务器自动将请求映射到对应局域网内部的机器上,即将端口流量直接发到映射的内网主机上。比如你的服务器私网IP是172.26.97.166,那么只需要把172.26.97.166的80端口映射到公网的80端口就可以了。
端口转发:
端口转发(Port forwarding),有时也被叫做隧道,是 SSH 为网络安全通信提供的一种方法,可以使两台服务器之间实现加密通信。
其实不论是端口映射还是端口转发,其实核心原理是一样的,而且想要达到的目的也是一样的,只不过是使用的场景不一样,相对来说,端口转发通过 SSH 加密,安全性更好。
端口转发有两种,一种是本地端口转发和远程端口转发:
本地端口转发:指定一个本地端口(local-port),所有发向那个端口的请求,都会转发到和当前主机建立 SSH 隧道的一个目标主机,然后该目标主机会作为中介,将收到的请求发到最终的目标服务器(target-host)的目标端口(target-port)。目标服务器可以就是远程主机,也可以是远程主机附近的其他主机。
$ ssh -L local-port:target-host:target-port tunnel-host
远程端口转发:
远程端口转发与本地端口转发刚好相反,在建立本地计算机到远程计算机的一个 SSH 隧道以后,远程端口转发将所有对远程主机的请求通过隧道访问本地计算机。它的命令格式如下。
$ ssh -R remote-port:target-host:target-port -N remotehost
karry5307->AKssh5307