Browsed by
Category: 计算机技术

定时清理释放内存

定时清理释放内存

家里有台 Raspberry Pi3, 日常做点小任务,比如做 samba 服务器当 NAS、做 web 的功能测试、学习点 Linux 知识等,基本都是一些负荷不大的任务。不过由于我是死忠的 GUI 党, 因此总是喜欢进入 Pi 那个巨丑无比的界面里进行操作,这也导致 Pi3 的内存会逐渐显得有些捉襟见肘,时间长了,就不得不使用 swap 。这可能会有损 microSD 卡的寿命,因此希望 Pi 能定时清理、释放内存。

网上搜了搜,也比较简单,而且效果比较明显。简要记录一下:

在 /etc/cron.daily 目录下,创建一个 gilson-clearcache 文件,内容如下:

#!/bin/sh
sync
echo 3 > /proc/sys/vm/drop_caches

将这个文件设置为可执行文件即可:

sudo chmod +x ./gilson-clearcache

设置为可执行文件后,可以手工执行一下,可以看到 “free -m” 显示的结果里,“buff/cache available”等项有明显的改善。

不过考虑到 Pi3 可怜的 1GB 内存,这种内存回收方面的改善,估计不能从根本上解决问题,上 Pi4 (2GB或者4GB)或许更好。后续继续观察一下,如果实在不行,就换 Pi4 或者等 Pi5 吧。

给 vbox 的客机系统扩容

给 vbox 的客机系统扩容

主机是Window 10, 运行在 VirtualBox 中的客机系统是 Debian (testing)。当初估计不足,只划了 8G 空间给客机系统,因此面临着容量不足的问题,迫切需要扩容,要不然就要重新构建一个客机,实在过于麻烦了。

从网上搜集了一些信息,有各种问题。绝大部分的资料其实不能算扩容,无非就是增加一个盘,然后 mount 到新的分区而已。而我希望是将现有的虚拟硬盘直接扩容,无需改变或者 mount 特定的分区或者目录。最后通过安装 GParted 软件,加上修改部分配置,终于解决了问题,从8G 扩展到 28G, 如下图所示:

扩容后的硬盘分区
扩容后的硬盘分区

系统只有两个分区: 主分区 和 交换分区。目的就是扩大主分区(/dev/sda1)的容量即可,其他无需改变(至少在使用者的角度是没有任何变化)。

增加 VBox 虚拟介质容量

VBox 新版都支持给虚拟介质扩容,操作简单。在“管理 – 虚拟介质管理”里找到客机的虚拟介质,直接增加容量即可。比如,将介质从 8G 直接调整到 28G。

但是客机系统不是直接就使用了扩容的硬盘容量。新增加的部分对客机系统而言,属于“未分配”的容量,因此需要进入客机系统(也就是 Debian)中进行磁盘管理,让系统能识别、管理这部分新容量。

Debian 磁盘管理

牛人直接用 fdisk 大概就可以搞定。作为一名无可救药的图形界面党, 我当然还是倾向于使用图形界面的软件来解决问题(非常不 linux,非常不 geeker),也就是 GParted。

GParted 很像 Windows 的磁盘管理工具,因此使用起来油然而生熟悉的感觉。启动 GParted 后,很容易就看到未分配的磁盘容量。可惜不能直接移动或者扩容/dev/sda1,原因大概是中间有个 swap 分区。刚开始我被困住了,后来想明白:

既然 swap 分区阻挡了主分区的扩容(移动),那删除掉 swap 分区,那主分区和未分配分区不就连起来了吗? 试试后发现果然如此:(1)删除 swap 分区, (2)调整主分区(/dev/sda1)的大小,(3)然后再重新将剩余的分区设置为 swap 分区。

千万别格式化主分区!只需要重新格式化 swap 分区即可。

GParted 有个bug:在上述步骤中,重新删除、创建了 swap 分区,可是 GParted 并没有修改 /etc/fstab 里对应的 UUID 值!导致每次重启后,发现 swap 区都没有激活使用。

解决这个bug也简单,在 GParted 中查询 swap 分区的属性,获取其 UUID 值,然后修改 /etc/fstab 中对应的 swap 分区的 UUID 值即可。

一点思考

本次扩容过程中,被 swap 分区困扰了很久,有各种问题。要么是 swap 分区阻挡了主分区扩容,要么是 swap 分区的 UUID 更新(这个算GParted的bug)。

如果不设置 swap 分区呢? 修改为采用 swap 文件方式,只保留一个主分区,这样就灵活很多。当然,实际部署 Linux 系统如果采用这种方式,可能会有问题(比如崩盘导致数据丢失等),既然是客机系统,倒是无所谓。

DNS over HTTPs

DNS over HTTPs

传统的 DNS 基于 UDP 协议,并且采用明文方式传递请求和结果。在互联网早期,这样做没什么问题。而现在网络越来越复杂,网络实体越来越多,各种看得见、看不见的手都可能修改 DNS 的结果。

简单的解决方式就是对 DNS 进行加密。 Mozilla 联合 Cloudflare 通过 HTTPs 来传递 DNS 消息,也就是 DoH (DNS over HTTPs)。这种方式从设计上看,不如 DNS over TLS 高效,但是胜在简单、无需过多更改网络设备和软件。

Firefox 已经内置了对 DoH 的支持,而且非常简单。问题是默认的两个 DoH 服务商:Cloudflare 和 NextDNS,在国内由于某种不可描述的原因,访问速度都很受影响。实际上国内腾讯和阿里的公共 DNS 服务也支持 DoH,以腾讯为例,它提供的 DoH 访问地址是:

https://doh.pub/dns-query

Firefox 的网络设置中,按下图进行配置即可:

Firefox 中设置腾讯 DoH
Firefox 中设置腾讯 DoH

另外,阿里提供的 DoH 访问地址为:

https://dns.alidns.com/dns-query
NetworkManager state is now ASLEEP

NetworkManager state is now ASLEEP

最近有一台 HP ELite 笔记本退役了,其实配置还不错,500GB SSD 硬盘、16GB内存,看着挺轻薄,本来还打算用来替换自己平时使用的笔记本,后来发现有些不爽:(1)触控板有点飘 (2)有个键被我不小心按坏了,也许本来就坏了 (3)屏幕时不时出现横线、甚至出现闪烁,很不舒服。

食之无味、弃之可惜。忽然想到可以安装 Debian 做家庭服务器用,上述缺点就无关紧要了。安装了最新的 Debian 10, 然后修改成 Debian(sid),过程很顺利。非常棒!以至于我甚至打算直接 VNC, 或者用 VSCode 登录上去做一些开发工作。

因为是当服务器用,因此一直都是合盖,然后扔角落里默默工作。接着又发现一个问题:过一段时间后,WiFi 网络老是断开,无法远程登录,需要重新开盖然后登录。琢磨着大概是系统休眠了,检查 syslog 信息,发现以下信息:

NetworkManager: sleep: wake requested (sleeping: yes  enabled: yes)
NetworkManager: state change: unavailable -> unmanaged (reason 'sleeping', sys-iface-state: 'managed')
NetworkManager: NetworkManager state is now ASLEEP

看来确实休眠了。搜索网络,查到一篇 Ubuntu 停止休眠的文章(请点击此处),考虑到 Ubuntu 和 Debian 本质没什么区别,操作也是有效的。

关闭休眠功能,请使用以下命令:

sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

当然,如果后悔了,需要重新打开休眠功能,可以使用以下命令(未验证):

sudo systemctl unmask sleep.target suspend.target hibernate.target hybrid-sleep.target
xrdp的小问题

xrdp的小问题

目标系统是 Debian, 采用 xrdp 远程登录窗体界面,总是在显示登录时黑屏。查了很久一直没有结论,后来就干脆用 vnc 算了。

今天在查其他问题时,无意间翻查到文件 “/usr/share/doc/xrdp/README.Debian”, 里面提示需要修改“/etc/X11/Xwrapper.config”文件,将

allowed_users=console

修改为

allowed_users=anybody

重启后,果然可以通过xrdp正常登录了! 只是比较奇怪,为什么 Debian 系统不将默认值修改为 anybody?是没人维护的原因吗? 那为啥又在 readme 文件中单独说明呢?

另外,由于 Raspberry Pi 也是基于 Debian 系统,因此 Pi 中做同样的修改,也可以通过 xrdp 正常登录。

xrdp 读取 “/etc/ssl/private/ssl-cert-snakeoil.key” 进行加密,但是这个文件默认只有 “ssl-cert” 组的成员才可以读取,因此还需要将 xrdp 用户加入该组:

sudo adduser xrdp ssl-cert
SSH 配置证书登录

SSH 配置证书登录

SSHd 配置采取了一些安全措施,比如:修改端口、禁止 root 远程登录(这里)、启动 fail2ban 防止恶意登录(这里),等等。目前看这些措施基本满足了日常的维护管理需求。

通常还会采取证书登录方式,禁止密码鉴权登录。不过以往考虑到密码方式更方便,因此没有动力去修改。时间就这么过去了……

最近登录服务器检查日志, 惊讶地发现 fail2ban 每日的日志居然有十几M之多,全是各类奇葩以各种方式尝试登录 SSH。虽然 fail2ban 工作得很好,但是万一出现了 bug 呢? 万一哪个变态就是锲而不舍、经年累月地尝试登录呢?应该下狠手,让老铁们彻底绝望,因此决定禁止密码方式登录,要求采用证书登录。

配置不复杂,涉及客户端生成证书密钥,以及将公钥上传到服务器等。主要参考 Linode 的两篇配置文档(这里这里)。 以下是详细步骤:

生成证书

客户端也是 Linux 系统,因此相当简单:

ssh-keygen -b 4096

该命令在当前用户的 .ssh 目录下创建了两个文件: id_rsa 以及 id_rsa.pub 。

其中 “id_rsa.pub” 是当前用户的公钥文件,将其上传到服务器上,然后添加进 ~/.ssh/authorized_keys 文件中:

cat id_rsa.pub >> .ssh/authorized_keys

添加完成后,服务器上的 id_rsa.pub 文件不用再保留,删除即可。要注意,authorized_keys 文件应该设置为别人不允许访问,确保足够的安全性。例如设置文件权限为600:

chmod 600 authorized_keys

当 SSH 客户端登录时, SSHd 默认读取该用户的 authorized_keys 信息进行证书鉴权。

修改 /etc/ssh/sshd_config 文件

PasswordAuthentication no

然后重启 sshd 即可:

sudo systemctl restart sshd

之后,客户端如果采用密码鉴权方式登录,或者粗暴破解,将被无情拒绝。

如果有多个客户端需要登录服务器,则需要各自生成证书,并将公钥上传到服务器,并添加到 authorized_keys 文件中即可。

Cloudflare 返回的DNS结果

Cloudflare 返回的DNS结果

最近查一个客户遇到的 SIP 呼叫问题,发现在检查 DNS 记录时有问题,没有正确获取 DNS 记录。切换了几个 DNS 服务器测试,只有 Cloudflare DNS 服务器(1.1.1.x 系列) 返回的DNS记录会触发问题。

这并不是说 Cloudflare 的DNS记录有错误,而是我们自己实现的 DNS 库没有考虑到该记录的不同寻常之处。Cloudflare 的返回结果确实有点与众不同。

下图是Google DNS 以及 Ali DNS 返回的DNS结果,请注意其中的 Name 字段的内容(0xC0 0x0C)

Google DNS 结果
Google / Ali DNS 返回结果

很明显,这种DNS结果采用了 compress 方式,通过 offset 来获取真正的Name。图中的 0x0C 实际就是偏移量,指向了包中的另一处地址。Compress 方式最直接的好处就是节省了包大小。

而 Cloudflare 的 DNS 结果如下图所示,直接将域名包含在 Name 中,以 0x03 标注开始,以 0x00 表示字符串结束。不再需要偏移指向其他地址。

Cloudflare 的 DNS 记录
Cloudflare DNS 返回的结果

这种方法的好处是够直接,不再需要跳转获取真实的域名信息。当然坏处是增加了数据包的大小。

我们测试了网络上大部分的 DNS 服务器,目前仅发现 Cloudflare 采取了这种方式,其他服务器都是采用 compress 方式。

站在“人”的体验角度,似乎 Cloudflare 更合理一些。但是要注意,compress 方式更符合计算机的处理,毕竟前面的 Queries 部分已经解析过 Name 了,没必要再解析一次。另一方面,直接 offset 寻址,也远远快于再一次通过判断0x00来解析Name 字符串。

因此我个人认为 Cloudflare 的处理方式,即拖慢了速度,又增加了数据包消耗。当然,以目前计算机的处理能力以及网络速度,这些都是浮云。我们的解决方式也是淡定地接受这个结果,并修改 DNS 库进行适配即可。

在本次查问题中,测试了网上公布的香港 DNS 服务器,全部拒绝了来自大陆 IP 地址的 DNS 请求,真有意思。

推荐一个lua的小插件

推荐一个lua的小插件

以前一直用Geany编辑器编写Lua程序。其实这个工具很垃圾,只是别的工具更垃圾。要求也不高,无非就是变量、函数等跳转、列表,工程范围内查找,基本的编辑功能即可,不要求调试功能。

平时写脚本一般都是采用visual studio code,很棒的工具,就简单编辑功能而言,vsc 做得相当好。因此也试图尝试 vsc 的插件,看看能否满足上述编写Lua脚本的要求。

看到 vsc 推荐作者sumneko 的插件,名字居然就叫 Lua,如下图所示。简单试了一下,感觉不错,符合上述各项需求,值得推荐。

Lua 插件
Lua 插件
升级php7

升级php7

这是一个升级的季节……

前两天刚升级完Git,感觉可以稍微轻松一下。今天收到email,WordPress 升级了! 升级也就算了,关键是进入管理界面时,扑面而来一个提示:“WordPress has detected that your site is running on an insecure version of PHP” ,这意思是:您的php版本太老了,该升级了!

查了一下当前Debian 9默认的php版本:V5.6.40,似乎不算太老啊。顺手又查了一下该系统中最新的php版本,已经是V7.0.33版本。V7的版本应该足够WordPress 使用,于是决定升级php来解决这个提示问题。

PHP毕竟是世界上最好的语言,各种插件都已经相应升级好了,都有PHP7对应的版本,因此事情就简单了,使用以下命令,直接安装即可:

sudo apt install libapache2-mod-php7.0 php7.0-fpm php7.0-gd php7.0-curl php7.0-mbstring php7.0-mcrypt php7.0-json php7.0-mysql php7.0-opcache php7.0-readline php7.0-xml php7.0-xmlrpc php7.0-zip php7.0-bz2 php-imagick

升级完php及apache的模块后,需要设置 Apache 使用最新的php7版本。也很简单,重新设置相应的模块并重启 Apache 即可:

sudo a2dismod php5
sudo a2enmod php7.0
sudo a2enmod proxy_fcgi
sudo a2enconf php7.0-fpm
sudo systemctl restart apache2
从HG迁移库到Git

从HG迁移库到Git

迁移工作比较简单,参考BitBucket推荐的一篇blog,基本操作与该博主的描述一致,部分有些差异。

以下操作基于Debian系统。

首先安装mercurial-git,这个工具会自动将原hg库的信息提交给新的Git库,会保留以前commit的comment内容,这点尤为重要。如果不关心以前的comment,就没啥好说了,直接将整个代码提交给Git就完事了。

sudo apt install mercurial-git

接着需要让 HG 知道有 mercurial-git 这个扩展,并能操作Git库。 修改~/.hgrc文件,添加以下内容即可:

[extensions]
hgext.git=

如果希望将HG的branch也转化成Git中的branch,则需要做一些稍显古怪的操作。请注意:HG中的branch不对应Git的branch!我不太清楚是HG的问题,还是 mercurial-git 这个工具的问题,需要为每个分支设置bookmark,然后根据这些bookmark转换成Git中的branch。

例如,将HG库中的default、mss_v36、mss_v36_dev三个分支,分别对应Git库中的master、mss_v36_hg 以及 mss_v36_dev_hg 分支:

hg bookmark -r default master
hg bookmark -r mss_v36 mss_v36_hg
hg bookmark -r mss_v36_dev mss_v36_dev_hg

然后,直接推送到Git的远端库即可:

hg push git+ssh://git@bitbucket.org:my_account/my_apps.git