snapd进程持续写盘导致系统卡顿

系统使用一段时间后,莫名其妙出现卡顿现象。发现硬盘灯闪个不停。

经查,是snapd进程持续不停的往硬盘写入数据,同时也会占用CPU。

写入量不大,但是磁盘占用率出奇的高。

导致系统出现卡顿,这个问题从ubuntu18.04到20.04实测都有,更老的版本没有实测不妄加批评。

解决办法网上找了N圈也没有找到解决办法。所以,只好……

干掉它!

$ sudo apt purge snapd

卸载后系统丝般顺滑。。

因为我暂时snap用的不多,加上也没别的办法,毕竟已经影响到系统的正常使用了,只好选择卸载。

有人说不能卸载,可以试试下面的命令:

$ sudo apt autoremove --purge snapd

卸载之后,继续重装一下,貌似也不再出现问题。

参考链接


iptables之recent模块小结(ubuntu 16.04/20.04)

iptables的recent模块用于限制一段时间内的连接数, 是谨防大量请求攻击的必杀绝技! 善加利用该模块可充分保证服务器安全。

recent常用参数

  • --name      设定列表名称,即设置跟踪数据库的文件名. 默认DEFAULT;
  • --rsource   源地址,此为默认。 只进行数据库中信息的匹配,并不会对已存在的数据做任何变更操作;
  • --rdest       目的地址;
  • --seconds  指定时间内. 当事件发生时,只会匹配数据库中前"几秒"内的记录,--seconds必须与--rcheck或--update参数共用;
  • --hitcount   命中次数. hits匹配重复发生次数,必须与--rcheck或--update参数共用;
  • --set           将地址添加进列表,并更新信息,包含地址加入的时间戳。 即将符合条件的来源数据添加到数据库中,但如果来源端数据已经存在,则更新数据库中的记录信息;
  • --rcheck     检查地址是否在列表,以第一个匹配开始计算时间;
  • --update    和rcheck类似,以最后一个匹配计算时间。 如果来源端的数据已存在,则将其更新;若不存在,则不做任何处理;
  • --remove   在列表里删除相应地址,后跟列表名称及地址。如果来源端数据已存在,则将其删除,若不存在,则不做任何处理;

recent模块需要注意的地方

  1. 目录/proc/net/下的xt_recent目录是在启用recent模块之后才有的,如果没有在iptables中使用recent模块,/proc/net/目录中是没有xt_recent目录的;
  2. 因recent模块最多只能记录20条记录,所以当源发送的数据包超过20后,recent模块的计数器会立刻减掉20,这也就是为什么old_packets的值就总是处于1-20之间;
  3. 如果配合seconds参数使用的是--rcheck参数而不是--update,则recent模块会从收到第一个数据包开始计算阻断时间,而--update是从收到的最后一个数据包开始计算阻断时间,即如果服务器在8点收到了源发出第一个icmp数据包,在8点15分收到源发出的第20个数据包,如果使用的是--rcheck参数,那么8点半的时候,用户就又可以发送icmp数据包了,如果使用是--update参数,则用户必须等到8点40才能发送icmp数据包;
  4. 当源发送数据包的个数大于或等于recent模块的hitcount参数所指定的值时,相应的iptables规则才会被激活;

recent命令大体有如下三个排列组合

  • --set句在前,--update(或--rcheck)句在后;
  • --update(或--rcheck)句在前,--set句在后;
  • --set句带或不带-j ACCEPT。

基本是上面这三项的排列组合;

下面通过几个案例进行说明

1)  利用iptables的recent模块来抵御简单的DOS攻击, 下面以限制ssh远程连接为例

$ iptables -I INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j DROP

$ iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --set --name SSH

$ iptables -I INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds  300 --hitcount 3 --name SSH -j DROP

以上三条规则的解释如下:

  1. 利用connlimit模块将单IP的并发设置为3;会误杀使用NAT上网的用户,可以根据实际情况增大该值;
  2. 利用recent和state模块限制单IP在300s内只能与本机建立3个新连接。被限制一分钟后即可恢复访问。
  3. 第一句是记录访问tcp 22端口的新连接,记录名称为SSH, --set 记录数据包的来源IP,如果IP已经存在将更新已经存在的条目
  4. 第三句是指SSH记录中的IP,300s内发起超过3次连接则拒绝此IP的连接。      --update 是指每次建立连接都更新列表;      --seconds必须与--update同时使用      --hitcount必须与--update同时使用
  5. 可以使用下面的这句记录日志:
$ iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --name SSH --second 300 --hitcount 3 -j LOG --log-prefix "SSH Attack"

recent模块可以看作iptables里面维护了一个地址列表,这个地址列表可以通过"--set"、"--update"、"--rcheck"、"--remove"四种方法来修改列表,每次使用时只能选用一种。 还可附带"--name"参数来指 定列表的名字(默认为DEFAULT),"--rsource"、"--rdest"指示当前方法应用到数据包的源地址还是目的地址(默认是前者)。recent语句都带有布尔型返回值,每次执行若结果为真,则会执行后续的语句,比如"-j ACCEPT"之类的。"--seconds"参数表示限制包地址被记录进列表的时间要小于等于后面的时间。

基于上面的说明,现在来看四个基本方法的作用:

  • --set       将地址添加进列表,并更新信息,包含地址加入的时间戳。
  • --rcheck  检查地址是否在列表。
  • --update  跟rcheck一样,但会刷新时间戳。
  • --remove 就是在列表里删除地址,如果要删除的地址不存在就会返回假。

例1:限制无法ssh直接连接服务器,需先用较大包ping一下,此时在15秒内才可以连接上

$ iptables -P INPUT DROP

$ iptables -A INPUT -s 127.0.0.1/32 -j ACCEPT

$ iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

$ iptables -A INPUT -p icmp --icmp-type 8 -m length --length 128 -m recent --set --name SSHOPEN --rsource -j ACCEPT

$ iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT

$ iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --rcheck --seconds 15 --name SSHOPEN --rsource -j ACCEPT

以上命令解说

  1. 将INPUT链默认策略置为DROP,当包走完INPUT链而没被拿走时就会丢弃掉;
  2. 本地localhost的包全部接受;
  3. 对于已建立连接或是与已连接相关的包都接受,服务器对外连接回来的包一般都走这条;基本环境已经配好了,现在开始要为连接到服务器的ssh打开通路。
  4. icmp类型 8 是ping包;指定包大小为 128 字节;recent用的列表名称为SSHOPEN,列表记录源地址。符合上述条件的数据包都接收。如果ping包内容为 100 字节,则加上IP头, ICMP头的 28 字节,总共 128 字节。
  5. 接受一般的ping包;
  6. 对连接ssh 22端口的连接进行处理,来源于SSHOPEN源地址列表并且在列表时间小于等于15秒的才放行。

例2:  限制每ip在一分钟内最多对服务器只能有8个http连接

$ iptables -I INPUT -p tcp --dport 80 -d 192.168.10.10 -m state --state NEW -m recent --name httpuser --set

$ iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j LOG --log-prefix 'HTTP attack: '

$ iptables -A INPUT -m recent --update --name httpuser --seconds 60 --hitcount 9 -j DROP

以上命令解说

  1. 192.168.10.10是服务器ip
  2. 参数-I,将本规则插入到 INPUT 链里头的最上头。只要是 TCP连接,目标端口是80,目标 IP是我们服务器的IP,刚刚新被建立起来时,我们就将这个联机列入 httpuser 这分  清单中;
  3. 参数-A,将本规则附在 INPUT 链的最尾端。只要是60秒内,同一个来源连续产生多个联机,到达第9个联机时,我们对此联机留下Log记录。记录行会以 HTTP attack 开头。  每一次的本规则比对, –update 均会更新httpuser清单中的列表;
  4. 参数-A,将本规则附在 INPUT 链的最尾端。同样的比对条件,但是本次的动作则是将此连接丢掉;
  5. 所以,这三行规则表示,我们允许一个客户端,每一分钟内可以接上服务器8个。具体数值可以看运维者决定。这些规则另外也可以用在其它对外开放的网络服务上,例如port  22 (SSH), port 25 (smtp email)。

2) 对连接到服务器B的SSH连接进行限制,每个IP每小时只限连接5次

-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set -j ACCEPT

服务器A连接服务器B的SSH服务的数据包流程,假设以下数据包是在一小时(3600秒)内到达服务器B(iptables配置如上)的:

  1. 当这个服务器A的第1个SSH包到达服务器B,规则1检查SSHPOOL列表中这个源IP是否有hitcount,因为是第一个包,显而易见,列表是0,规则1判定这个数据包不必执行      DROP,并且也不处理这个数据包,将数据包转给下条规则。
  2. 规则2将这个数据包计入SSHPOOL列表,就是做+1,因为规则中有-j ACCEPT,规则2放行这个包。
  3. 第1个数据包进入服务器B,不用再在iptables里转了。
  4. 当第2个SSH包到达服务器B,规则1检查SSHPOOL列表的hitcount,发现是1没有超过5,于是判定不执行DROP并转给下条规则处理。
  5. 规则2在SSHPOOL中+1,并放行,第2个数据包进入服务器B。
  6. 第3、4、5个包同上。 g) 第6个包到达服务器B,规则1检查SSHPOOL列表中的hitcount,发现是5了已经连接5次了,于是规则2执行DROP,不必再转给下条规则了丢弃该包。 h) 第7、8…个包同上。

实际上recent的处理更为复杂, 从上面的流程可以看出,--set的功能在于计录数据包,将源IP加入列表。--rcheck(update)的功能在于判定数据包在seconds和hitcount条件下是否要DROP。

如果采用下面的配置, 则必须在INPUT链的默认策略为ACCEPT的情况下才能生效并使用, 否则(即INPUT链的默认策略为DROP)所有的SSH包都被丢弃了!!!!

-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT                            //必须添加这个前提条件才能生效!
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --set
-A INPUT -p tcp --dport 22 -m state --state NEW -m recent --name SSHPOOL --rcheck --seconds 3600 --hitcount 5 -j DROP

这个命令与上面命令的区别在于:set句在前,且set句不带-j ACCEPT。这导致数据包的流程也不同。

  1. 第1个数据包到达规则1后马上计入SSHPOOL列表,并且规则1因为没有-j ACCEPT,直接将数据包转给下条规则。规则2拿到这个数据包后检查SSHPOOL列表,发现是1,也  不处理这个包,转给下条规则。如果后续的规则都没有再处理这个数据包,则最后由INPUT链的默认策略ACCEPT处理。由于上面的策略是DROP,所以丢弃该包,于是这两行命令在我的服务器上不能用。
  2. 这里有个问题,由于set句在前,数据包进入是先计入列表,再判定是否合法。这导致第5个包到达后,先在列表中+1,结果是5,再由规则2判定,发现是5,结果丢弃该包,    最后真正ACCEPT的只有4个包。其实个人认为这样写的代码不符合正常的思维逻辑, 而且这样写只能正常工作于默认策略是ACCEPT的情况,所以不建议用这个版本的命令,我的版本ACCEPT、DROP策略都能用。

从上面可以看出,在使用recent模块的命令的时候,一定要先确认iptables的INPUT链的默认策略是什么。

接着说下--rcheck 和 --update的区别 --rcheck从第1个包开始计算时间,--update是在rcheck的基础上增加了从最近的DROP包开始计算阻断时间,具有准许时间和阻断时间,update会更新last-seen时间戳。

就拿上面那个配置案例来说, rcheck是接收到第1个数据包时开始计时,一个小时内仅限5次连接,后续的包丢弃,直到一小时过后又可以继续连接。update则是接收到第1个数据包时计算准许时间,在一个小时的准许时间内仅限5次连接,当有包被丢弃时,从最近的丢弃包开始计算阻断时间,在一个小时的阻断时间内没有接收到包,才可以继续连接。所以rcheck类似令牌桶,一小时给你5次,用完了抱歉等下个小时吧。update类似网银,连续输错5次密码,停止一小时,只不过update更严格,阻断时间是从最近的一次输错时间开始算,比如输错了5次,过了半个小时又输错一次,这时阻断时间不是剩半小时,而是从第6次重新计算,剩一小时. 

可以拿下面这个命令进行测试, 自行替换rcheck、update,然后ping一下就明白了:

-A INPUT -p icmp -m recent --name PINGPOOL --rcheck --seconds 30 --hitcount 5 -j DROP
-A INPUT -p icmp -m recent --name PINGPOOL --set -j ACCEPT
 
-A INPUT -p icmp -m recent --name PINGPOOL --update --seconds 30 --hitcount 5 -j DROP
-A INPUT -p icmp -m recent --name PINGPOOL --set -j ACCEPT

温馨提示: ICMP包和UDP包在iptables中的state情况是一样的,因为是无状态的,不同于TCP,iptables可以靠SYN等flags确定state,而iptables是基于ICMP包/UDP包到达服务器的间隔时间来确定state的。比如在做上面测试的时候,使用ping 192.168.10.10 -t时,除了第一个ICMP包state是NEW,后续的包state都是ESTABLISHED,结果因为前面有一句:

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

结果测试ping一直是通的,这个一定要弄明白!

3) 限制80端口60秒内每个IP只能发起10个新连接,超过记录日记及丢失数据包,可防CC及非伪造IP的syn flood

$ iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j LOG --log-prefix 'DDOS:' --log-ip-options

$ iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --rcheck --seconds 60 --hitcount 10 -j DROP

$ iptables -A INPUT -p tcp --dport 80 --syn -m recent --name webpool --set -j ACCEPT

以上命令解说

  • 第1行规则表示: 60秒10个新连接,超过记录日志。
  • 第2行规则表示: 60秒10个新连接,超过记录日志。
  • 第3行规则表示: 范围内允许通过。
    即每个IP目标端口为80的新连接会记录在案,可在/proc/net/xt_recent/目录内查看,rcheck检查此IP是否在案及请求次数,如果超过规则就丢弃数据包,否则进入下条规则并更新列表信息。

发送特定指定执行相应操作,按上面设置, 如果自己IP被阻止了,可设置解锁。

$ iptables -A INPUT -p tcp --dport 5000 --syn -j LOG --log-prefix "WEBOPEN: "
#记录日志,前缀WEBOPEN:

$ iptables -A INPUT -p tcp --dport 5000 --syn -m recent --remove --name webpool --rsource -j REJECT --reject-with tcp-reset
#符合规则即删除webpool列表内的本IP记录

4)  默认封闭SSH端口,为您的SSH服务器设置开门暗语

$ iptables -A INPUT -p tcp --dport 50001 --syn -j LOG --log-prefix "SSHOPEN: "
#记录日志,前缀SSHOPEN:

$ iptables -A INPUT -p tcp --dport 50001 --syn -m recent --name sshopen --set --rsource -j REJECT --reject-with tcp-reset
#目标端口tcp 50001的新数据设定列表为sshopen返回TCP重置,并记录源地址。

$ iptables -A INPUT -p tcp --dport 22 --syn -m recent --name sshopen --rcheck --seconds 15 --rsource -j ACCEPT
#开启SSH端口,15秒内允许记录的源地址登录SSH。
 
#开门钥匙
nc host 50001 
telnet host 50001
nmap -sS host 50001

5) 指定端口容易被破解密钥,可以使用ping指定数据包大小为开门钥匙

$ iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -j LOG --log-prefix "SSHOPEN: "
#记录日志,前缀SSHOPEN:

$ iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -m recent --name sshopen --set --rsource -j ACCEPT

#指定数据包78字节,包含IP头部20字节,ICMP头部8字节。
$ iptables -A INPUT -p tcp --dport 22 --syn -m recent --name sshopen --rcheck --seconds 15 --rsource -j ACCEPT

按照上面配置后, 依然无法ssh登录到指定主机, 因为没有添加"INPUT链的默认策略为ACCEPT"的前提, 即需要下面这个前提条件!

$ iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

整理后的配置规则

$ iptables -F

$ iptables -X

$ iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT

$ iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -j LOG --log-prefix 'SSH_OPEN_KEY'

$ iptables -A INPUT -p icmp --icmp-type 8 -m length --length 78 -m recent --name openssh --set --rsource -j ACCEPT

$ iptables -A INPUT -p tcp --dport 22 --syn -m recent --name openssh --rcheck --seconds 60 --rsource -j ACCEPT

$ iptables -P INPUT DROP

针对上面整理后的配置规则说明

  • 第1,2行规则表示: 清空原有的iptables规则
  • 第3行规则表示: 已经建立成功的连接和与主机发送出去的包相关的数据包都接受,如果没有这一步,后面的tcp连接无法建立起来
  • 第4行规则表示: 出现长度为78字节icmp回响包在/var/log/syslog生成log,log以SSH_OPEN_KEY开头
  • 第5行规则表示: 出现长度为78字节icmp回响包,将源地址信息记录在openssh文件中,并接受
  • 第6行规则表示: 对于openssh文件中的源地址60s以内发送的ssh连接SYN请求予以接受
  • 第7行规则表示: 将INPUT链的默认策略设置为drop

调试过程:

  1. 如果没有设置第3行规则,则无法建立ssh连接
  2. 在没有第3行规则的情况下,设置第6行如果不加--syn,则可以ssh连接一会儿,过一会儿又自动断线,除非ping一下目的地址. 原理是:ping目的地址,则会更新openssh的时间,这样ssh连接还在60s之内,所以可以通信,过一会儿,60s超时,则就会断开ssh连接。如果加了--syn,只能进行开始的syn,无法正常连接

在客户机上,如果需要ssh到主机,需要先ping主机进行解锁

$ ping -s 50 ip    #linux主机的ip
$ ping -l 50 ip     #windows主机的ip

并在一分钟之内ssh到主机,这样在/proc/net/xt_recent/目录下生成openssh文件, 内容如下:

src=192.168.10.10
ttl: 53
last_seen: 42963x6778
oldest_pkt: 1 4296376778, 4295806644, 4295806895, 4295807146, 4295826619, 4295826870, 4295827122, 4295827372, 4295833120, 4295833369, 4295834525, 4295834777, 4295872016, 4295872267, 4295872519, 4295872769, 4295889154, 4295889406, 4295889658, 4295889910

参考链接


Iptables之recent模块小结

ubuntu 20.04配置rsync服务通过ssh同步

  • 安装配置为数据同步进行准备
$ sudo apt-get install rsync

# ubuntu 16.04/18.04默认源中都存在rssh ,但是 ubuntu 20.04开始,已经没办法从系统源中安装了。
# 原因在于 rssh 存在安全漏洞,并且长时间没有修复,并且已经没人维护了,我们使用rrsync替代 

$ export RSH_RSYNC_USER=rsh_backup

$ export RSH_RSYNC_USER_PASSWORD=rsh_password

# 如果需要备份/var/log 目录,建议把用户组设置成 adm 用户组,否则很多日志没办法读取
# sudo useradd -s "" $RSH_RSYNC_USER -g users -G adm
# 后期也可以通过 sudo usermod -g users -G adm $RSH_RSYNC_USER 更改用户组

# 不配置任何登陆默认shell,以便于 rrsync 接管
$ sudo useradd -s "" $RSH_RSYNC_USER

$ echo $RSH_RSYNC_USER:$RSH_RSYNC_USER_PASSWORD | sudo chpasswd

# 创建配置文件目录,增加配置信息
$ sudo mkdir /home/$RSH_RSYNC_USER

$ sudo chown -R $RSH_RSYNC_USER /home/$RSH_RSYNC_USER

$ sudo mkdir /home/$RSH_RSYNC_USER/.ssh

$ sudo chown -R $RSH_RSYNC_USER /home/$RSH_RSYNC_USER/.ssh

$ sudo touch /home/$RSH_RSYNC_USER/.ssh/authorized_keys

$ sudo chown -R $RSH_RSYNC_USER /home/$RSH_RSYNC_USER/.ssh/authorized_keys

# 配置许可访问的目录
$ echo 'command="/usr/bin/rrsync -ro /var/www /data/",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding' | sudo tee /home/$RSH_RSYNC_USER/.ssh/authorized_keys
  • 客户端同步,测试是否正常工作
$ export RSH_RSYNC_USER=rsh_backup 

$ export RSH_RSYNC_USER_PASSWORD=rsh_password

$ export RSH_RSYNC_PORT=22

$ export REMOTE_SERVER=www.mobibrw.com

$ export SYNC_DIR=/var/www

# 测试是否可以正常工作,另一个方面是许可ssh的登录key否则我们后续没办法使用sshpass
# 可以使用 --exclude 参数忽略指定的目录,相对路径,不是绝对路径
$ sudo rsync -avzP --delete -e 'ssh -p $RSH_RSYNC_PORT' $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DIR $SYNC_DIR
  • 转化为定时任务,自动同步
# 安装密码自动填写软件
$ sudo apt-get install sshpass

$ cd ~

$ touch backup_rsync.sh

$ chmod +x backup_rsync.sh

$ echo -e '#!'"/bin/bash\n" >> backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_USER=rsh_backup' backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_USER_PASSWORD=rsh_password' backup_rsync.sh

$ sed -i '$a\export RSH_RSYNC_PORT=22' backup_rsync.sh

$ sed -i '$a\export REMOTE_SERVER=www.mobibrw.com' backup_rsync.sh

# 此处注意最后的分隔符/如果没有这个分隔符,会导致目标目录多一个名为www的父目录
$ sed -i '$a\export SYNC_DIR=/var/www/' backup_rsync.sh

# 可以使用 --exclude 参数忽略指定的目录,相对路径,不是绝对路径
$ sed -i '$a\sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e \"ssh -p $RSH_RSYNC_PORT\" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DIR $SYNC_DIR' backup_rsync.sh

# 打开计划任务的日志,默认不开
$ sudo sed -i -r "s/#cron\.\*[ \t]*\/var\/log\/cron.log/cron.*                         \/var\/log\/cron.log/g" /etc/rsyslog.d/50-default.conf

#write out current crontab
$ sudo crontab -l > addcron

#echo new cron into cron file ,每隔30分钟我们调度一次任务,前面是文件锁,防止并发冲突
#如果需要每小时执行一次,则修改为 "* */1 * * * flock ...."
#如果需要凌晨2点执行,则修改为 "* 2 * * * flock ...."
$ echo "30 * * * * flock -x -w 10 /dev/shm/backup_rsync_corn.lock -c \"bash `echo ~`/backup_rsync.sh\"" >> addcron

#install new cron file
$ sudo crontab addcron

$ rm addcron

$ sudo service cron restart

目前我的阿里云,腾讯云服务器之间的同步脚本如下:

#!/bin/bash

export RSH_RSYNC_USER=user
export RSH_RSYNC_USER_PASSWORD=password
export RSH_RSYNC_PORT=22
export REMOTE_SERVER=121.199.27.227

export SYNC_WWW_DIR=/var/www/

sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e "ssh -p $RSH_RSYNC_PORT" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_WWW_DIR $SYNC_WWW_DIR --exclude "wordpress/wp-content/cache/" --exclude "wordpress/wp-content/plugins/crayon-syntax-highlighter/log.txt"

export SYNC_DATA_DIR=/data/
 
# 此处注意,如果使用 --exclude "/root/" 则忽略最顶部的root目录
# 如果使用 --exclude "root/" 则忽略所有路径中包含 root 的目录
# 主要 rsync 的 top-directroty 部分的规则
sshpass -p $RSH_RSYNC_USER_PASSWORD rsync -avzP --delete -e "ssh -p $RSH_RSYNC_PORT" $RSH_RSYNC_USER@$REMOTE_SERVER:$SYNC_DATA_DIR $RSYNC_DATA_DIR --exclude "/root/"

参考链接


Fix ufw service not loading after a reboot

I have a Ubuntu 18.04/20.04 server running ufw (Uncomplicated Firewall) and Docker. Docker relies on iptables-persistent, which is an interface to a much more powerful and complicated firewall that many people would rather avoid.

The problem here is that ufw and iptables-persistent are both ways for creating the same firewall. On my server, only one service would ever run at startup negating the other.

After a reboot ufw would always be disabled.

$ sudo ufw status

Status: inactive

Even though the ufw service is enabled, if you look closely, the active service has exited.

$ sudo systemctl status ufw 

● ufw.service - Uncomplicated firewall
    Loaded: loaded (/lib/systemd/system/ufw.service; enabled; vendor preset: enabled)
    Active: active (exited)

If I check the server services, both ufw and netfilter-persistent are enabled. netfilter-persistent is a means for managing iptables on Debian and Ubuntu systems.

$ sudo service --status-all

 [ + ]  netfilter-persistent
 [ + ]  ufw

The fix is simple; we need to tell the operating system to load ufw after the netfilter-persistent.

Find and backup the ufw service.

$ ls -l /lib/systemd/system/ufw.service

-rw-r--r-- 1 root root  266 Aug 15  2017  ufw.service
$ cd /lib/systemd/system/

$ sudo cp ufw.service ufw.service.original
$ cat /lib/systemd/system/ufw.service

 [Unit]
 Description=Uncomplicated firewall
 Documentation=man:ufw(8)
 DefaultDependencies=no
 Before=network.target

 [Service]
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/lib/ufw/ufw-init start quiet
 ExecStop=/lib/ufw/ufw-init stop

 [Install]
 WantedBy=multi-user.target

Update and save the modified service by appending `After=netfilter-persistent.service` to the `[Unit]` block.

$ sudo nano /lib/systemd/system/ufw.service
 [Unit]
 Description=Uncomplicated firewall
 Documentation=man:ufw(8)
 DefaultDependencies=no
 Before=network.target
 After=netfilter-persistent.service

 [Service]
 Type=oneshot
 RemainAfterExit=yes
 ExecStart=/lib/ufw/ufw-init start quiet
 ExecStop=/lib/ufw/ufw-init stop

 [Install]
 WantedBy=multi-user.target

Reboot and test.

$ sudo reboot
$ sudo ufw status

Status: active
 To                         Action      From
 --                         ------      ----
 OpenSSH                    ALLOW       Anywhere
 Nginx Full                 ALLOW       Anywhere

参考链接


How to Install and Configure Fail2ban on Ubuntu 20.04

Any service that is exposed to the Internet is at risk of malware attacks. For example, if you are running a service on a publicly available network, attackers can use brute-force attempts to sign in to your account.

Fail2ban is a tool that helps protect your Linux machine from brute-force and other automated attacks by monitoring the services logs for malicious activity. It uses regular expressions to scan log files. All entries matching the patterns are counted, and when their number reaches a certain predefined threshold, Fail2ban bans the offending IP using the system firewall for a specific length of time. When the ban period expires, the IP address is removed from the ban list.

This article describes how to install and configure Fail2ban on Ubuntu 20.04. 

低于 ubuntu 20.04 的系统,可以参考 ubuntu 16.04防止SSH暴力登录攻击 。

Installing Fail2ban on Ubuntu

The Fail2ban package is included in the default Ubuntu 20.04 repositories. To install it, enter the following command as root or user with sudo privileges :

$ sudo apt update

$ sudo apt install fail2ban

Once the installation is completed, the Fail2ban service will start automatically. You can verify it by checking the status of the service:

$ sudo systemctl status fail2ban

The output will look like this:

● fail2ban.service - Fail2Ban Service
     Loaded: loaded (/lib/systemd/system/fail2ban.service; enabled; vendor preset: enabled)
     Active: active (running) since Wed 2020-08-19 06:16:29 UTC; 27s ago
       Docs: man:fail2ban(1)
   Main PID: 1251 (f2b/server)
      Tasks: 5 (limit: 1079)
     Memory: 13.8M
     CGroup: /system.slice/fail2ban.service
             └─1251 /usr/bin/python3 /usr/bin/fail2ban-server -xf start

That’s it. At this point, you have Fail2Ban running on your Ubuntu server.

Fail2ban Configuration

The default Fail2ban installation comes with two configuration files, `/etc/fail2ban/jail.conf` and `/etc/fail2ban/jail.d/defaults-debian.conf`. It is not recommended to modify these files as they may be overwritten when the package is updated.

Fail2ban reads the configuration files in the following order. Each `.local` file overrides the settings from the `.conf` file:

  • `/etc/fail2ban/jail.conf`
  • `/etc/fail2ban/jail.d/*.conf`
  • `/etc/fail2ban/jail.local`
  • `/etc/fail2ban/jail.d/*.local`

For most users, the easiest way to configure Fail2ban is to copy the `jail.conf` to `jail.local` and modify the `.local` file. More advanced users can build a `.local`configuration file from scratch. The `.local` file doesn’t have to include all settings from the corresponding `.conf` file, only those you want to override.

Create a `.local` configuration file from the default `jail.conf` file:

$ sudo cp /etc/fail2ban/jail.{conf,local}

To start configuring the Fail2ban server open, the `jail.local` file with your text editor :

$ sudo nano /etc/fail2ban/jail.local

The file includes comments describing what each configuration option does. In this example, we’ll change the basic settings.

Whitelist IP Addresses

IP addresses, IP ranges, or hosts that you want to exclude from banning can be added to the `ignoreip` directive. Here you should add your local PC IP address and all other machines that you want to whitelist.

Uncomment the line starting with `ignoreip` and add your IP addresses separated by space:

/etc/fail2ban/jail.local

ignoreip = 127.0.0.1/8 ::1 123.123.123.123 192.168.1.0/24

Ban Settings

The values of `bantime`, `findtime`, and `maxretry` options define the ban time and ban conditions.

`bantime` is the duration for which the IP is banned. When no suffix is specified, it defaults to seconds. By default, the `bantime` value is set to 10 minutes. Generally, most users will want to set a longer ban time. Change the value to your liking:

/etc/fail2ban/jail.local

bantime = 1d

To permanently ban the IP use a negative number.

`findtime` is the duration between the number of failures before a ban is set. For example, if Fail2ban is set to ban an IP after five failures (`maxretry`, see below), those failures must occur within the `findtime` duration.

/etc/fail2ban/jail.local

# 这个时间段内超过规定次数会被ban掉
findtime = 10m

`maxretry` is the number of failures before an IP is banned. The default value is set to five, which should be fine for most users.

/etc/fail2ban/jail.local

maxretry = 5

Email Notifications

Fail2ban can send email alerts when an IP has been banned. To receive emails, you need to have an SMTP installed on your server and change the default action, which only bans the IP to `%(action_mw)s`, as shown below:

/etc/fail2ban/jail.local

action = %(action_mw)s

`%(action_mw)s` bans the offending IP and sends an email with a whois report. If you want to include the relevant logs in the email, set the action to `%(action_mwl)s`.

You can also adjust the sending and receiving email addresses:

/etc/fail2ban/jail.local

destemail = admin@linuxize.com 
sender = root@linuxize.com

Fail2ban Jails

Fail2ban uses a concept of jails. A jail describes a service and includes filters and actions. Log entries matching the search pattern are counted, and when a predefined condition is met, the corresponding actions are executed.

Fail2ban ships with a number of jail for different services. You can also create your own jail configurations.

By default, only the ssh jail is enabled. To enable a jail, you need to add `enabled = true` after the jail title. The following example shows how to enable the proftpd jail:

/etc/fail2ban/jail.local

[proftpd]

port     = ftp,ftp-data,ftps,ftps-data
logpath  = %(proftpd_log)s
backend  = %(proftpd_backend)s

The settings we discussed in the previous section, can be set per jail. Here is an example:

/etc/fail2ban/jail.local

[sshd]
enabled   = true
maxretry  = 3
findtime  = 1d
bantime   = 4w
ignoreip  = 127.0.0.1/8 23.34.45.56

The filters are located in the `/etc/fail2ban/filter.d` directory, stored in a file with same name as the jail. If you have custom setup and experience with regular expressions you can fine tune the filters.

Each time you edit a configuration file, you need to restart the Fail2ban service for changes to take effect:

$ sudo systemctl restart fail2ban

Fail2ban Client

Fail2ban ships with a command-line tool named `fail2ban-client` that you can use to interact with the Fail2ban service.

To view all available options, invoke the command with the `-h` option:

$ fail2ban-client -h

This tool can be used to ban/unban IP addresses, change settings, restart the service, and more. Here are a few examples:

  • Check the jail status:

    $ sudo fail2ban-client status sshd
  • Unban an IP:

    $ sudo fail2ban-client set sshd unbanip 23.34.45.56
  • Ban an IP:

    $ sudo fail2ban-client set sshd banip 23.34.45.56

Conclusion

We’ve shown you how to install and configure Fail2ban on Ubuntu 20.04.

For more information on this topic, visit the Fail2ban documentation .

If you have questions, feel free to leave a comment below.

注意:如果服务器上启用了 UFW 防火墙,则几乎必然出现 Fail2ban 无法阻止攻击者 IP 的情况。

尽管 Fail2ban 已经提示阻止用户访问。但是由于 iptables 的顺序问题,根本不起作用,依旧在 /var/log/auth.log 中观察到不断的访问尝试。

解决方法如下:

$ sudo vim /etc/fail2ban/jail.local

banaction = iptables-multiport
banaction_allports = iptables-allports

更改为

banaction = ufw
banaction_allports = ufw

防火墙规则要求通过 UFW 进行设置。

重新载修改后的配置信息

$ sudo fail2ban-client reload

默认情况下,执行如下命令后:

$ sudo systemctl enable ufw

$ sudo ufw enable

UFW 服务器应该随着服务器重启自动启动,但是却经常没有启动,尤其是 ubuntu 20.04

参考 Fix ufw service not loading after a reboot 调整。

默认情况下,`Fail2ban`的配置是没办法阻止用户名尝试的,因此,我们需要新增如下配置才能解决问题。

First, define the filter for invalid users in `/etc/fail2ban/filter.d/sshd-invaliduser.conf`:

[INCLUDES]
before = common.conf

[Definition]
_daemon = sshd

failregex = ^%(__prefix_line)s[iI](?:llegal|nvalid) user .*? from <HOST>(?: port \d+)?\s*$
ignoreregex = 

[Init]
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

Then enable it in `/etc/fail2ban/jail.local`:

[sshd-invaliduser]
enabled = true
maxretry = 1
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s

默认情况下,`Fail2ban`的配置是没办法阻止root登陆尝试的,因此,我们需要新增如下配置才能解决问题。

[INCLUDES]
 
before = common.conf
 
[Definition]
 
_daemon = sshd
 
failregex = ^%(__prefix_line)spam_unix\(sshd:auth\):\s+authentication failure;\s*logname=\S*\s*uid=\d*\s*euid=\d*\s*tty=\S*\s*ruser=\S*\s*rhost=<HOST>\S*\s*user=(root|admin)\s.*$
 
ignoreregex =
 
[Init]
 
maxlines = 10
 
journalmatch = _SYSTEMD_UNIT=sshd.service + _COMM=sshd

Then enable it in `/etc/fail2ban/jail.local`:

[sshd-ban-root]
enabled = true
maxretry = 1
port    = ssh
logpath = %(sshd_log)s
backend = %(sshd_backend)s
移除被禁止访问的IP

我们自己操作的时候,可能会把自己给禁止访问,此时需要手工从禁止列表中移除某些特定的IP

$ sudo fail2ban-client unban xx.xx.xx.xx

参考链接


java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "".

ubuntu 18.04 .5 升级到 ubuntu 20.04.2 之后,发现 Tomcat 9.0.31 长时间没办法启动,观察日志,发现如下错误信息:

08-Feb-2021 22:09:23.792 SEVERE [main] org.apache.catalina.util.LifecycleBase.handleSubClassException Failed to start component [Connector[AJP/1.3-8009]]
        org.apache.catalina.LifecycleException: Protocol handler start failed
                at org.apache.catalina.connector.Connector.startInternal(Connector.java:1038)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.core.StandardService.startInternal(StandardService.java:438)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:930)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                at org.apache.catalina.startup.Catalina.start(Catalina.java:633)
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
                at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.base/java.lang.reflect.Method.invoke(Method.java:566)
                at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:343)
                at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:478)
        Caused by: java.lang.IllegalArgumentException: The AJP Connector is configured with secretRequired="true" but the secret attribute is either null or "". This combination is not valid.
                at org.apache.coyote.ajp.AbstractAjpProtocol.start(AbstractAjpProtocol.java:264)
                at org.apache.catalina.connector.Connector.startInternal(Connector.java:1035)
                ... 12 more

这个是由于在升级系统的时候,选择保留老版本的配置文件,这样就导致,如果 Tomcat 配置了通过 AJP 方式与Apache通信的情况下,会报告上面的错误信息。

新增 secretRequired 的目的是为了解决 AJP  端口暴露在公网的情况下,存在 AJP File Read/Inclusion in Apache Tomcat (CVE-2020-1938) and Undertow (CVE-2020-1745) 漏洞,由于 Tomcat AJP 协议设计上存在缺陷,攻击者通过 Tomcat AJP Connector 可以读取或包含 Tomcat 上所有 webapp 目录下的任意文件,例如可以读取 webapp 配置文件或源代码。此外在目标应用有文件上传功能的情况下,配合文件包含的利用还可以达到远程代码执行的危害。

连接方必须在连接的时候,传入正确的 secretRequired 才能与 Tomcat 通信,相当于通信需要的密码了。

网上很多人都是直接设置

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" secretRequired="" />

来解决问题的,也就是设置 secretRequired 为空字符,但是这样会导致攻击方不需要传递密码就可以通信了,因此诱发远程攻击漏洞。

正确的做法其实是不允许远程用户直接通过 Tomcat AJP 协议通信,也就是在设置绑定的 IP 地址为本地地址 127.0.0.1。如下:

<Connector port="8009" protocol="AJP/1.3" address="127.0.0.1" redirectPort="8443" secretRequired=""/>

参考链接


如何检查Linux中是否启用了USB3.0 UASP(USB附加SCSI协议)模式?

 USB 3.0 在数据量较多且零碎传输时,效能的表现会较差,主要原因是在于传输技术所造成的状况。

USB 采用半双工传输模式与 BOT (Bluk Only Transfer) 传输协议,半双工传输模式就像是再讲对讲机一样,一方说完另一方才能继续对话,也就是说数据的传输方向仅有单向传输功能。

BOT 传输协议则是一种单线程的传输架构,这个架构就像马路上只能行使一台车子,不管路有多宽,都必须等待这量车子行驶过后下一部车子才能继续通行。

USB 的加速方式
提升为全双工模式

当 USB 升级到 USB 3.0 时,将原来的半双工传输模式,改为全双工模式,并且提升十倍的带宽,不过其架构还是在 BOT 之下。

BOT 加速模式

 这个方式虽然还是在 BOT 的架构之下,但是是将原来在路上行使的轿车,换一台更大一点的公交车,将一次传送的数据量加大,就可以减少来回的次数,来达到加速的目的。

UASP 加速模式

BOT加速模式虽然可以有效的增加传输速度,不过还是没有在根本上解决无法多任务处理的问题,所以 USB-IF (USB Implementers Forum) 一个为开发 USB 规格的企业共同成立的非营利性机构,为了让传输效能更好,制定了UASP(USB Attached SCSI Protocol)传输架构,让 USB3.0 也能像 SCSI 传输协议的方式传输数据,不需等待上一笔数据传输完成后再进行传输数据的动作,并改善了在 CPU 的使用率、数据延迟及等待时间。

要达到 UASP 加速功能,请先确认您计算机端是否同样有支持 UASP 功能。
目前支持 UASP 的系统有 WIN 8 、Mac OS 8 & 9 ,除了以上系统,您也可以询问您购买的计算机公司,是否有提供相关的驱动程序。

继续阅读如何检查Linux中是否启用了USB3.0 UASP(USB附加SCSI协议)模式?

How to mount Virtualbox drive image(vdi) on Ubuntu 16.10/20.04

This tutorial will explain How to mount Virtualbox drive image(.vdi) on Ubuntu 16.10.First we need to install QEMU tools using the following command

sudo apt-get install qemu-kvm

Now we need to load the network block device (nbd) module using the following command

sudo modprobe nbd

run qemu-nbd, which is a user space loopback block device server for QEMU-supported disk images.

qemu-nbd -c /dev/nbd0 [vdi-file]

Note:- vdi-file :- Your vdi file location for example /home/test/ubuntu.vdi

Example

qemu-nbd -c /dev/nbd0 /home/test/ubuntu.vdi

You can check the partitions in the image using the following command

sudo fdisk -l /dev/nbd0

The above command will check the entire image as a block device named /dev/nbd0, and the partitions within it as subdevices. For example, the first partition in the image will appear as /dev/nbd0p1.

If you want to mount the first partition use the following command

sudo mount /dev/nbd0p1 /mnt

Now you can check all the contents of /mnt partition and copy all the required files.

After completing your work you can unmount the partition using the following command

sudo umount /mnt

Shutdown nbd services using the following command

sudo qemu-nbd -d /dev/nbd0

参考链接


ubuntu 20.04配置samba

$ sudo apt-get install libcanberra-gtk-module

$ sudo apt install avahi-daemon

$ sudo apt-get remove --purge samba

$ sudo apt-get install samba

编辑配置文件

$ sudo vim /etc/samba/smb.conf

文件尾部增加

[Movie]
   comment = Movie
   path = /mnt/data/Movie/ # 需要共享的目录位置
   browseable = yes # 是否可见
   read only = yes # 是否只读
   guest ok = yes # 登陆用户是否可访问
   valid users = user # 可访问的用户

重启服务

$ sudo service smbd restart

参考链接


ubuntu 18.04 Apache2启用HTTP/2

HTTP/2 可以让我们的应用更快、更简单、更稳定 – 这几词凑到一块是很罕见的!HTTP/2 将很多以前我们在应用中针对 HTTP/1.1 想出来的“歪招儿”一笔勾销,把解决那些问题的方案内置在了传输层中。不仅如此,它还为我们进一步优化应用和提升性能提供了全新的机会!

——《Web 性能权威指南》

Ubuntu18.04 官方源已经包含带有HTTP2模块的 Apache/2.4.29 ,所以我们可以很简单的启用 HTTP2。

$ sudo a2enmod http2

首先启用 http2 模块,然后在虚拟主机的配置文件中或者在Apache2的全局配置文件中加入:

Protocols h2 http/1.1

当客户端支持时优先使用 HTTP2 ,其次是 http/1.1,表明了一种优先顺序。目前为止就已经启用完成了,但如果你是使用的 Apache2+PHP 架构的应用程序,由于 mpm_prefork 模块不支持 mod_http2,所以我们需要切换 mpm_prefork、mod_php 到 mpm_event 和 php-fpm 来解决这个问题。

# Install php-fpm and enable
$ sudo apt install php-fpm

$ sudo systemctl enable php7.2-fpm

# To enable PHP 7.2 FPM in Apache2
$ sudo a2enmod proxy_fcgi setenvif

$ sudo a2enconf php7.2-fpm

# First to disable PHP 7.2/ mpm_prefork to avoid conflicts,then enable.
$ sudo a2dismod php7.2 mpm_prefork

$ sudo a2enmod mpm_event

继续阅读ubuntu 18.04 Apache2启用HTTP/2