安装 {#安装}
安装命令:
sudo apt install openssh-server
查看服务的状态:
systemctl status sshd.service
配置 {#配置}
包括服务端和客户端配置
服务端常用配置 {#服务端常用配置}
编辑ssh
服务配置文件
sudo vim /etc/ssh/sshd_config
常用配置如下:
Banner /etc/issue.net # 登录前提示信息
Port 22 # 工作端口
PubkeyAuthentication yes # 允许公钥登录,ssh 除了可以用账号密码登录外还可以用公私钥来进行登录
ListenAddress 12.34.56.78 # 侦听地址,比如服务器有两块网卡,现在只能让用户通过第一块网卡来进行 ssh 连接,那么后面的地址就写第一块网卡的 IP 地址
PermitRootLogin no # 是否允许 root 账号来通过 SSH 登录;no 表示完全禁用;prohibit-password 表示禁止通过账号密码登录,但是可以通过公钥的方式登录
Protocol 2 # 只允许 SSH 2 协议来连接
AllowUsers user1 user2 # 只允许 user1 和 user2 账号通过 SSH 连接
DenyUsers user3 # 禁止 user3 账号通过 SSH 连接
AllowGroups sshusers # 只允许 sshusers 组里面的账号可以通过 SSH 连接
PasswordAuthentication no # 禁止使用密码登录
解决连接自动断开问题 {#解决连接自动断开问题}
问题描述:ssh 连接长时间不操作自动断开
解决方法共有三种
- 修改服务器端参数
# 如果你用多台本地机器连接服务器,可以考虑把服务器端的配置做修改(路径是:/etc/ssh/sshd_config),在其中添加一行内容
ClientAliveInterval 60 # 意思是每 60 秒向客户端发一次保持连接的信号
# 如果仍要设置断开时间,还有一个参数可以添加
ClientAliveCountMax 60 # 意思是如果客户端 60 次未响应就断开连接,依据你期望的时间来设定
- 修改本地参数
# 也可以让客户端向服务器发送保持连接的信号(路径是/etc/ssh/ssh_config)
# 在其中类似的添加相应的参数也行
ServerAliveInterval 60
ServerAliveCountMax 60
- 连接时指定参数
# 在连接前使用 -o 设置相应的参数
ssh -o ServerAliveInterval=30 root@192.168.1.1
SSH 工具 {#ssh-工具}
openssh
是一个服务套件,安装openssh-server
时不仅会安装 ssh 的服务端程序,还会安装一大堆 ssh 相关工具,比如:sftp
和scp
。
SCP 工具 {#scp-工具}
相当于将 ssh 和 rcp 结合,rcp 是明文传输的,通过 ssh 为通信双方建立一个安全加密的隧道,然后将 rcp 数据通过这个隧道传输以此实现数据的加密传输。
- 拷贝一个文件到目标机器上
scp a.txt 192.168.2.207:
默认使用本地账号名登录远程系统,并且默认拷贝到这个账号的主目录下
注意:最后面的冒号不能省
- 指定用户名、目标路径拷贝文件到远程机器上
scp a.txt study@192.168.2.207:/tmp/b.txt
将本机的 a.txt 通过 192.168.2.207 机器上的 study 账号拷贝到 /tmp/b.txt 路径下
- 拷贝一个目录到远程机器上
scp -rv dir/ study@192.168.2.207:
将本机的 dir/ 目录通过 192.168.2.207 机器上的 study 账号拷贝到其主目录下
参数:r
: 递归拷贝 v
:显示进度
- 拷贝远程机器文件到本机
scp study@192.168.2.207:/tmp/b.txt .
通过 192.168.2.207 机器上的 study 账号将 /tmp/b.txt 到本机当前目录下
SFTP 工具 {#sftp-工具}
相当于将 ssh 和 ftp 结合,ftp 是明文传输的,通过 ssh 为通信双方建立一个安全加密的隧道,然后将 ftp 数据通过这个隧道传输以此实现数据的加密传输。
- 连接 sftp
sftp study@192.168.2.207
连接成功后就会得到一个类似 ftp 的命令提示符,所有适用于 ftp 的指令在 sftp 命令提示符中都可以使用。
sftp> help、ls、cd、get(下载)、wget、put(上传)、mput、quit
客户端连接 {#客户端连接}
有三种连接方式:分别是指定用户名密码,配置文件和使用公钥进行登录。
通过用户名密码 {#通过用户名密码}
ssh study@192.168.2.207
ssh -l study 192.168.2.207
通过配置文件 {#通过配置文件}
首先编辑配置文件:~/.ssh/config
host fileserver # 这一组的名称,随意
Hostname 192.168.2.207
Port 22
User zhangsan
Host mailserver # 这一组的名称,随意
Hostname mail.lab.com
Port 2222
User lisi
编辑完成之后,保存。
之后就可以使用ssh fileserver
这条命令连接 192.168.2.207:22 机器上的 zhangsan 账号,省去了输入 IP、端口、账号等信息
通过公钥 {#通过公钥}
什么是公钥 / 私钥?
非对称算法(公钥算法),通过一次数学运算会生成两个值,一个是公钥,一个是私钥,无所谓哪个是公钥哪个是私钥,因为用公钥加密的只能用对应的私钥解密,用私钥加密只能用对应的公钥解密。
注意:公钥是拿出去给别人用,私钥得自己严格保密。
通过公钥登录的步骤:
-
生成密钥对(如果已有可跳过)
- 使用 rsa 非对称加密算法,并指定密钥长度为 4096。
ssh-keygen -t rsa -b 4096
生成的私钥位置在:
~/.ssh/id_rsa
;公钥位置在:~/.ssh/id_rsa.pub
- 命名密钥对,生成密钥对 id_mail 用来登录邮件服务器,生成密钥对 id_ftp 用来登录 ftp 服务器等。
ssh-keygen -t rsa -b 4096 -f id_mail ssh-keygen -t rsa -b 4096 -f id_ftp
- 修改私钥密码,可以设置为空(不建议)
ssh-keygen -p -f ~/.ssh/id_rsa
参数:
p
表示修改密码;f
指定修改的目标 -
上传公钥到目标机器
-
拷贝公钥到目标机器上(本机只有一个公钥时)
ssh-copy-id study@192.168.2.207
-
拷贝指定的公钥到目标机器上
ssh-copy-id -i id_rsa.pub study@192.168.2.207
拷贝后目标机器会生成
~/.ssh/authprized_keys
文件,内容上传的公钥内容相同。上传完公钥后,再次用 ssh 连接时就不需要输入账号密码了,输入的密码是私钥的密码,如果把私钥的密码设置为空那么就可以直接连接了,什么密码都不用输入(当然不建议这么做)。
-
SSH 其他应用 {#ssh-其他应用}
ssh 除了能远程登录之外,还有很多非常实用的功能。
执行一次性命令 {#执行一次性命令}
ssh -i ~/.ssh/id_mail study@192.168.2.207 -p 2222 ping 192.168.2.1
这条命令前部分是登录目标机器然后自动执行ping
命令,ping
命令执行完了就结束本次通信;这里只是一个例子,你可以在最后指定任何命令。
参数:-i
定一个私钥文件为这次通信加解密,如果只生成一个密钥对就不需要在后面指定秘钥文件,默认就会使用那一个;-p
指定端口。
上传文件夹 {#上传文件夹}
假定远程服务器带宽有限,目标是拷贝时不将服务带宽占满影响正常用户体验。
tar -cj dir/ | pv | cstream -t 100k | ssh study@192.168.2.207 'tar -xj'
将本地 dir/ 限速 100K/s 上传到 192.168.2.207 study账号的主目录下
执行步骤:
tar -cj dir/
生成 tar 包并压缩pv
显示传输过程中对带宽的占用情况cstream -t 100K
限速为 100K/s'tar -xj'
解压上传的tar包
远程目录挂载 {#远程目录挂载}
- 临时 :将 192.168.2.207 上的
/path/
目录通过 study 账号临时挂载到本机的/mnt
目录下
sshfs study@192.168.2.207:/path/ /mnt
使用 root 账号卸载
umount /mnt/myfiles
使用普通用户权限卸载
fusermount -u /mnt/myfiles
- 持久挂载 :将 1.1.1.1 上的
/path
目录通过 user 账号持久挂载到本机的/mntpoint
目录下
编辑配置文件:sudo vim /etc/fstab
user@1.1.1.1:/path /mntpoint fuse,sshfs rw,noauto,users,_netdev 0
端口转发 {#端口转发}
SSH 端口转发也属于 SSH 应用,但是它很实用就单独拎出一章来。
SSH 端口转发分为三种:本地端口转发,远程端口转发及动态端口转发。
常用的命令参数有:
- -C:压缩数据传输。
- -f:后台认证用户/密码,通常和 -N 连用,不用登录到远程主机。
- -N:不执行脚本或命令,通常与 -f 连用。
- -g:在 -L / -R / -D 参数中,允许远程主机连接到建立的转发的端口(即共享给他人),如果不加这个参数,只允许本地主机建立连接。
- -L:用于本地端口转发,具体用法在后文阐述。
- -R:用于远程端口转发,具体用法在后文阐述。
- -D:用于动态端口转发,具体用法在后文阐述。
注意:不管是本地端口转发,远程端口转发及动态端口转发都需要使用 SSH 服务端的root
账号来建立连接。
本地端口转发 {#本地端口转发}
ssh -L [收听接口:]收听端口:目标主机:目标端口 username@hostname
- 本机 IP 可以省略,默认为 0.0.0.0,如果你有多块网卡可以单独指定。
- 本地端口就是你手头这台机子的端口
- 目标 IP 是相对于你连接的 SSH 服务端来说的。假设你连接的 SSH 服务端 IP 是 1.1.1.1,你的目标 IP 写为
localhost
,此时localhost
不是代表你手头的这台机器,而是远程 SSH 服务端所在的 1.1.1.1 这台机器。- 目标端口,即目标 IP 的端口
如果要建立多条本地端口转发,多加几个 -L 参数即可。
假设有如下的场景一:
你家里有一台电脑,处于局域网中,内网 IP 为:192.168.1.32;你在某某云上有一台服务器,公网 IP 为:1.1.1.1。
现在你想要实现的目标是:访问本机的2001
端口相当于在访问 1.1.1.1 上的23
端口;在其它地方用别的电脑访问 1.1.1.1 的23
端口相当于在访问本机的2001
端口。
执行如下命令:
ssh -CfN -L 192.168.1.32:2001:localhost:23 study@1.1.1.1
执行这条端口转发命令后,将会在本机 SSH 客户端 192.168.1.32 与 SSH 服务端 1.1.1.1 之间建立一条 SSH 隧道。
把请求数据比作水,这条 SSH 隧道就好比一根水管,你从2001
端口这边灌水进去会从23
端口那边出来,反之你往23
端口这边灌水进去,会从2001
端口这边流出来。
其中192.168.1.32:
可以省略,默认为0.0.0.0
,如果你电脑上有好几块网卡,你只想在其中一块网卡上建立本地端口转发,那么可以加上本地 IP;之后的例子中就省略掉此部分了。
假设有如下的场景二:
你家里有主机 A,内网 IP 为 192.168.1.32;公司有跳板机 B,公网 IP 为:1.1.1.1;公司还有 WEB 服务器 C,内网 IP 为:10.0.0.1。
主机 A 可以访问跳板机 B,跳板机 B 和 WEB 服务器 C 之间可以互相访问。
现在你想要实现的目标是:访问本机 A 的2001
端口就相当于在访问 WEB 服务器 C 的80
端口(丐版 VPN)。
执行如下命令:
ssh -CfN -L 2001:10.0.0.1:80 jump@1.1.1.1
执行这条端口转发命令后,将会在本机 SSH 客户端 A 192.168.1.32 与 跳板机 B 之间建立一条 SSH 隧道。
所有访问本机 A 2001
端口的数据都将由这条隧道转发给跳板机 B,然后再由跳板机 B 将数据发送到 WEB 服务器 C 的80
端口,然后 WEB 服务器 B 80
端口返回的数据再顺着这条通道逆向发送到本机 A 的 2001 端口上。
这样就实现了访问本机的2001
端口相当于在访问 WEB 服务器的 10.0.0.1 的80
端口。
远程端口转发 {#远程端口转发}
ssh -R 目标端口:本地IP:本机端口 username@hostname
- 目标端口,即 hostname 的端口。
- 本地 IP 是相对于你手头上的这台机子,可以写
127.0.0.1
表示你手头上的这台机子;也可以写10.0.0.10
表示你所在内网的一台机器,访问这台机器的请求和响应将由你手头上的这台机子来进行转发。- 本地端口就是你手头这台机子的端口。
如果要建立多条远程端口转发,多加几个 -R 参数即可。
重要:使用远程端口转发需要编辑 SSH 服务端上的 /etc/ssh/sshd_config
文件,在其中添加或修改GatewayPorts yes
,然后重启sshd.service
服务;否则远程端口即 SSH 服务端上只会监听 127.0.0.1 这个 IP,导致其它机器无法访问到远程映射的端口。
假设有如下的场景:
你家里有一台主机 A,内网 IP 为:192.168.1.32;跳板机 B,公网 IP 为:1.1.1.1;公司有 WEB 服务器 C,内网 IP 为:10.0.0.1;及数据库服务器 D,IP 为 10.0.0.2。
它们之间的访问关系是:主机 A 和 WEB 服务器 C 都可以访问跳板机 B,反之则不行;数据库服务器 D 只能由 WEB 服务器 C 来进行访问。
网络拓扑如下:
现在你想要实现的目标是:访问跳板机 B 的2001
端口相当于在访问 WEB 服务器 C 的 80 端口;访问跳板机 B 的2002
端口相当于在访问数据库服务器的3306
端口。
为了实现此目标你可以在 WEB 服务器 C 上执行 SSH 远程端口转发命令:
ssh -CfN -R 2001:localhost:80 -R 2002:10.0.0.2:3306 jump@1.1.1.1
执行这条端口转发命令后,将会在 WEB 服务器 C 和跳板机 B 之间建立一条 SSH 隧道。
当使用主机 A 访问跳板机 B 的2001
端口时会将请求通过 SSH 隧道转发到 WEB 服务器 C 的80
端口上,80
返回的数据顺着这条路原路发送回主机 A上。
当使用主机 A 访问跳板机 B 的2002
端口时会将请求通过 SSH 隧道转发到 WEB 服务器 C 上,然后再有 WEB 服务器 C 将请求数据发送到数据库服务器 D 的3306
端口上,3306
返回的数据顺着这条路原路发送回主机 A 上。
以上就是 SSH 远程转发的案例。
其实如果只需要用主机 A 访问 WEB 服务器 C,也可以通过 WEB 服务器 C 与跳板机 B 之间建立一个本地端口转发,在 WEB 服务器 C 上执行:
ssh -CfN -L 80:localhost:2001 jump@1.1.1.1
连接建立起之后,用主机 A 访问跳板机 B 的2001
端口依旧能访问到 WEB 服务器上的80
端口。
在这方面远程端口转发和本地端口转发是很类似的,但是对于数据库服务器 D 的访问则必须建立远程端口转发才可以。
动态端口转发 {#动态端口转发}
前面的两种转发都需要事先确定要映射的端口,而动态端口转发,顾名思义就是不需要实现指定端口。
其原理是在 SSH 服务端开启一个SOCKS
代理(默认是 scoks 5),至于要访问什么网站,完全是动态的,取决于原始通信。相当于将 SSH 服务器变成了一个代理服务器(丐版魔法)。
ssh -D [本机IP:]本地端口 username@hostname
- 本机 IP 可以省略,默认为 0.0.0.0,如果你有多块网卡可以单独指定。
- 本地端口就是你手头这台机子的端口
假设有如下的场景:
你家里有一台主机 A,内网 IP 为:192.168.1.32;云服务器 B,公网 IP 为:1.1.1.1。
由于你家里的网络条件不是很好,现在你想要通过云服务器 B 来进行代理上网。
那么你可以执行:
ssh -CfN -D 2001 study@1.1.1.1
执行成功后会在本机的2001
端口与1.1.1.1
建立一个动态转发,将浏览器的代理设置为本机的2001
端口,代理类型选择socks 5
之后,访问 baidu.com 的流量顺序是:
localhost:2001 --> localhost:22 --> 1.1.1.1:22 --> baidu.com:80
可以看到请求的流量都是走 SSH 隧道,会经过加密,所以是非常安全的。响应的数据也同理,按照原路返回。
思路打开,如果在云服务器 B 上执行上面那条命令,会发生什么呢?这会让云服务 B 对自身进行动态端口转发,使它成为一个任何人都可以访问的代理服务器。
保持转发不掉线 {#保持转发不掉线}
在建立端口转发隧道后,如果一段时间内没有使用,可能会导致连接断开的情况。为了解决这个问题,可以使用 autossh
工具来维持隧道并实现自动重新连接的功能。
以下命令在 root 账号下执行。
-
安装 autossh
apt update apt install autossh
-
编辑 autossh 服务文件
vim /etc/systemd/system/autossh.service
填入以下内容并保存:
[Unit] Description=AutoSSH Service After=network-online.target [Service] User=root ExecStart=/usr/bin/autossh -M 0 -CN -R 2001:localhost:22 root@1.1.1.1 [Install] WantedBy=multi-user.target
在 ExecStart 部分填写 ssh 端口转发命令,
- M 0
是 autossh 命令的参数,表示不开启监视端口;其它参数是 ssh 命令命令的参数。-M
参数在autossh
命令中用于指定一个监视端口,以便自动 SSH 会话在远程主机上建立一个用于检测连接状态的隧道。这个监视端口通常用于确保 SSH 连接的稳定性,如果 SSH 连接断开,那么监视端口也会关闭,从而触发autossh
重新建立连接。注意:不能在 ExecStart 中添加 ssh 端口转发的 -f 参数。
-
重新加载服务配置文件
systemctl daemon-reload
-
启动 autossh 服务并设置开机自启
# 启动 autossh 服务 systemctl start autossh.service # 设置开机自启 systemctl enable autossh.service
防爆破 {#防爆破}
任何连接到互联网的机器都是恶意攻击的潜在目标。 有一个名为 Fail2Ban 的工具可用来缓解服务器上的非法访问。
安装 {#安装-1}
sudo apt install fail2ban
fail2ban
的工作原理是每隔一段时间读取分析日志文件,如果有异常 IP 则会禁用它。
注意:每次在重启的时候都会重新读取一次日志文件,可能造成的影响是你刚刚解禁了一个 IP,然后你重启了fail2ban
,这个 IP 又被禁用了。
配置 {#配置-1}
默认配置文件/etc/fail2ban/jail.conf
在软件更新时会被覆盖
从/etc/fail2ban/jail.conf
复制一份作为本地配置文件,命名为/etc/fail2ban/jail.local
,优先级高于默认配置文件。
全局配置项
lgnoreip = 127.0.0.1/8 192.168.1.245/24 # 忽略地址/地址段(不禁止这些地址),密码错多少次都不会禁止它
bantime = -1 # 后面加的是时间(秒),当有人连续输错密码超过指定次数后禁止多长时间,-1表示永久禁止
findtime = 600 # 每隔 600 秒检查一次日志,检查到异常 IP 后就 ban
maxretry = 5 # 最大连续错误尝试 5 次
配置 sshd 开启 Jail
常用命令 {#常用命令}
- 查看总览
sudo fail2ban-client status
- 查看配置项执行详细信息
sudo fail2ban-client status sshd
- 查看防火墙规则
sudo iptables -L -n
- 手动解除被禁 IP
使用iptables
手动删除对192.168.2.190
的防火墙规则
sudo iptables -D f2b-sshd -s 192.168.2.190-j REJECT
参数-D
表示删除规则;f2b-sshd
为规则名称;-s
要解除的ip地址;j REJECT
拒绝的方式是REJECT
,后面写自己防火墙禁用的方式。
使用fail2ban
解除对192.168.2.190
禁用
sudo fail2ban-client set sshd unbanip 192.168.2.190