作者归档:admin

nginx 规则匹配与 acme.sh 自动证书续签

这事情是这样的,我半个月前发现之前配置的 Syncthing 代理和 Nextcloud 页面的 Let’s Encrypt 证书都过期了。按道理讲,oneinstack 的一键包会添加一个 crontab 任务自动续签证书,但是就是没 work,手动执行 acme.sh 以后,发现是域名认证无法通过,请求 .well-known/acme-challenge下的认证文件时返回 403 错误。

Nextcloud 使用了一键包中提供的 rewrite rule,Syncthing 是自己改的 nginx 配置文件,而同服务器上的 h5ai 却续签正常。在这种情况下,首先肯定是怀疑自己改错了。

在查看了 Syncthing 的 nginx 配置文件以后,发现默认将所有请求转发给 localhost 处理,那么问题就显而易见了,Syncthing 不知道那个 .well-known 是什么东西,自然返回错误,因此加上了一条 location 规则:

location /.well-known {
}

嗯,可以续签了。

但是同样的方法在 Nextcloud 上却行不通,加入了这个规则以后,curl 仍然返回 403 错误。查看了 oneinstack 的 rewrite rule 以后发现,似乎本来就对这个目录做了处理。考虑到一堆正则看得头大,想着直接 override 掉好了,在查找了 location 的用法以后,加上了这么一行:

location ^~ /.well-known/acme-challenge {
}

然后就能用了。

最后再转载一些对于 location 用法的解释:

location  = / {
  # 精确匹配 / ,主机名后面不能带任何字符串
  [ configuration A ]
}

location  / {
  # 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
  # 但是正则和最长字符串会优先匹配
  [ configuration B ]
}

location /documents/ {
  # 匹配任何以 /documents/ 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration C ]
}

location ~ /documents/Abc {
  # 匹配任何以 /documents/Abc 开头的地址,匹配符合以后,还要继续往下搜索
  # 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
  [ configuration CC ]
}

location ^~ /images/ {
  # 匹配任何以 /images/ 开头的地址,匹配符合以后,停止往下搜索正则,采用这一条。
  [ configuration D ]
}

location ~* \.(gif|jpg|jpeg)$ {
  # 匹配所有以 gif,jpg或jpeg 结尾的请求
  # 然而,所有请求 /images/ 下的图片会被 config D 处理,因为 ^~ 到达不了这一条正则
  [ configuration E ]
}

location /images/ {
  # 字符匹配到 /images/,继续往下,会发现 ^~ 存在
  [ configuration F ]
}

location /images/abc {
  # 最长字符匹配到 /images/abc,继续往下,会发现 ^~ 存在
  # F与G的放置顺序是没有关系的
  [ configuration G ]
}

location ~ /images/abc/ {
  # 只有去掉 config D 才有效:先最长匹配 config G 开头的地址,继续往下搜索,匹配到这一条正则,采用
    [ configuration H ]
}

location ~* /js/.*/\.js

已=开头表示精确匹配
如 A 中只匹配根目录结尾的请求,后面不能带任何字符串。
^~ 开头表示uri以某个常规字符串开头,不是正则匹配
~ 开头表示区分大小写的正则匹配;
~* 开头表示不区分大小写的正则匹配
/ 通用匹配, 如果没有其它匹配,任何请求都会匹配到
顺序 no优先级:
(location =) > (location 完整路径) > (location ^~ 路径) > (location ~,~* 正则顺序) > (location 部分起始路径) > (/)

上面的匹配结果
按照上面的location写法,以下的匹配示例成立:

/ -> config A
精确完全匹配,即使/index.html也匹配不了
/downloads/download.html -> config B
匹配B以后,往下没有任何匹配,采用B
/images/1.gif -> configuration D
匹配到F,往下匹配到D,停止往下
/images/abc/def -> config D
最长匹配到G,往下匹配D,停止往下
你可以看到 任何以/images/开头的都会匹配到D并停止,FG写在这里是没有任何意义的,H是永远轮不到的,这里只是为了说明匹配顺序
/documents/document.html -> config C
匹配到C,往下没有任何匹配,采用C
/documents/1.jpg -> configuration E
匹配到C,往下正则匹配到E
/documents/Abc.jpg -> config CC
最长匹配到C,往下正则顺序匹配到CC,不会往下到E

 

qBittorrent 自动重启

因为 libtorrent 全是 bug,所以用了它的 qBittorrent 经常会莫名其妙出现一些错误,然后自己挂掉。虽然每次的 backtrace 都是在 libtorrent 里面出现的错误,但是同样用了 lt 的 Deluge 就一点都没有问题,所以估计这俩的代码都写得太差吧。

因此,写了一个简单的脚本去监控 qb 的运行状态,在它挂掉的时候自动重启,在漏内存的时候自动 kill 掉重开一个。

具体代码可以看 Github。默认行为是在 Xserver 存在的情况下启动 GUI 版的 qb,如果没有 Xserver 就启动 qbittorrent-nox,一分钟检测一次运行状态,挂了就重开。

如果在 VNC 下面使用 GUI 版的 qb,且想要随着桌面自动启动的话,需要在 ~/.config/autostart 下放置一个 desktop 文件

如果想看到一个 Terminal,并且监控一下重启的原因,用这个版本:

[Desktop Entry]
Encoding=UTF-8
Version=0.9.4
Type=Application
Name=qBittorrent-daemon
Comment=
Exec=bash -c '/usr/bin/python3 <path>/launch.py'
OnlyShowIn=XFCE;
StartupNotify=false
Terminal=true
Hidden=false

如果不需要看到那个 Terminal,用这个版本:

[Desktop Entry]
Encoding=UTF-8
Version=0.9.4
Type=Application
Name=qBittorrent-daemon
Comment=
Exec=/usr/bin/python3 <path>/launch.py
OnlyShowIn=XFCE;
StartupNotify=false
Terminal=false
Hidden=false

 

关于 Xshell 5 到期不能使用的问题

辣鸡韩国人。辣鸡韩国人。辣鸡韩国人。(XShell 的开发商 NetSarang 是韩国公司)

Xshell 5 的家庭/学校授权的免费版还不错,是全功能的,但是 6 以后只能同时开 4 个标签页,这个对我这种习惯多标签操作的人来说十分不合适。所以我们得想办法折腾一下。目前有这几个办法:

  1. 修改 nslicense.dll
    找个反汇编软件,打开 nslicense.dll
    搜索16进制
    7F0C81F98033E1010F8680
    修改为
    7F0C81F98033E101E98100
    修改为
    7F0C81F98033E1010F8380
    都可以
    附上修改好的下载
  2. 使用 Xmanager 破解版
    在我用的时候,有这些序列号可用(现在已经不行了):
    Serial:160501-116212-999918
    Serial:160501-116315-999718
    Serial:160501-116681-999470
    Serial:160501-116172-999838
    Serial:160501-116524-999046
    Serial:160501-116476-999086
    然后去官方用这些序列号下载 Xmanager 5,断网安装,用以上序列号激活,之后,修改 hosts文件

    127.0.0.1 transact.netsarang.com
    127.0.0.1 update.netsarang.com
    127.0.0.1 www.netsarang.com
    127.0.0.1 www.netsarang.co.kr
    127.0.0.1 sales.netsarang.com

    就可以正常使用
    考虑到这些序列号已经被官方屏蔽,这里放出下载

  3. 换 PuTTY/KiTTY
    开源拖拉机又不是不能用。就我自己而言,使用 Xshell 主要图以下几点:字体好看、代理方便、多标签、SSH KeepAlive、保存用户名密码、有较长的向上翻页
    实际上,这些功能在 PuTTY/KiTTY 里面都有
    Window -> Lines of Rollback 调整保存历史行数
    Window -> Appearance -> Font settings 调整字体和反锯齿方案,可以有 Consolas 和 ClearType
    Connection 中可以调 KeepAlive 包
    Connection -> Data 可以保存登录用户名,KiTTY 还可以保存密码
    Connection -> Proxy 可以设置代理
    Connection -> SSH -> Auth 可以设置 Private Key
    如果要修改默认设置,在空白情况下改好了以后,在 Sessions 里面点击 Default Settings 然后按保存
    多标签可以通过一个外壳 MTPuTTY 实现
    该有的都有了,拥抱开源吧
  4. Xmanager Keygen
    https://github.com/DoubleLabyrinth/Xmanager-keygen

Hetzner Cloud Volume 功能的使用

Hz cloud 什么都好,就是盘太小,最基础的实例只有 20G 盘,相比 Scaleway 的 50G 还是差了点。不过考虑到它 CPU 也好,盘也快,所以想把建在 Scaleway 上面的本博客搬到 Hz cloud。正好最近 Hz cloud 出了 Volume 的功能可以自己加硬盘,在星菊的帮助下,使用 LVM 完成了 Volume 和自带分区合并的功能。

要做到这点,需要分两步,一个是在 Rescue 模式下将系统安装在 LVM 分区上,第二步是在系统中扩展 LVM 分区。

安装系统时,需要在后台进入 Rescue 模式,Hz 家的 Rescue 都一样,在选定 image 以后会弹出配置文件让你编辑,在分区那里需要这么写:

PART /boot ext4 512M
PART lvm vg0 all
LV vg0 root / ext4 all

之后双击 Esc 退出,正常安装就行,之后 LVM 分区就挂载在 / 这里了。

然后重启进入系统,在 Volume 页面创建之后 attach 到之前的实例。通常来说,系统会安装在 /dev/sda,新的 Volume 在 /dev/sdb。执行以下命令将分区合并:

pvcreate -ff /dev/sdb
vgextend vg0 /dev/sdb
lvresize -l +100%FREE vg0/root
resize2fs /dev/vg0/root

做了如下几件事:

  1. 在 /dev/sdb 上创建 Physical Volume
  2. 将 Volume Group vg0 扩展到 /dev/sdb 上
  3. 扩展 Logical Volume vg0/root 到所有的可用空间
  4. 扩展 /dev/vg0/root 上的文件系统

我们可以通过 pvdisplay vgdisplay 和 lsblk 看到效果:

root@sb1 ~ # pvdisplay
  --- Physical volume ---
  PV Name               /dev/sda2
  VG Name               vg0
  PV Size               <37.65 GiB / not usable 2.00 MiB
  Allocatable           yes (but full)
  PE Size               4.00 MiB
  Total PE              9637
  Free PE               0
  Allocated PE          9637
  PV UUID               ZbfxjP-RNf5-ScPU-eclg-dMjj-0WKg-T3FA2p

  --- Physical volume ---
  PV Name               /dev/sdb
  VG Name               vg0
  PV Size               750.00 GiB / not usable 4.00 MiB
  Allocatable           yes
  PE Size               4.00 MiB
  Total PE              191999
  Free PE               191999
  Allocated PE          0
  PV UUID               ZphGg0-2XcJ-Kjzy-gfBX-7pSp-Wo4L-fbVkD5

root@sb1 ~ # vgdisplay
  --- Volume group ---
  VG Name               vg0
  System ID
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  3
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                1
  Open LV               1
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               787.64 GiB
  PE Size               4.00 MiB
  Total PE              201636
  Alloc PE / Size       9637 / 37.64 GiB
  Free  PE / Size       191999 / <750.00 GiB
  VG UUID               7It9l8-70zz-03Uk-8md3-mPBZ-o7fe-clN3QX

root@sb1 ~ # lsblk
NAME         MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
sda            8:0    0  38.2G  0 disk
├─sda1         8:1    0   512M  0 part /boot
└─sda2         8:2    0  37.7G  0 part
  └─vg0-root 253:0    0 787.7G  0 lvm  /
sdb            8:16   0   750G  0 disk
└─vg0-root   253:0    0 787.7G  0 lvm  /
sr0           11:0    1  1024M  0 rom

在完成了所有命令之后,可以在 lsblk 中看到 / 已经扩充到了 787.7G

关于公网分流任务使用 qBittorrent + libtorrent 内存泄漏的一些想法

出现的问题是,在 Linux qb 挂了 400+ 公网种子的情况下,使用 libtorrent 1.1 作为后端,在运行三至四天以后就会内存使用量不断增加,直到占用了几乎所有的可用内存,系统崩溃为止。

在 qb 的这个 Issue 中(https://github.com/qbittorrent/qBittorrent/issues/8630),有人在 Windows 上观察到了一样的现象,报告在 Enable OS cache 的情况下最终会导致内存泄漏。

在 https://github.com/qbittorrent/qBittorrent/issues/8295 和 https://github.com/arvidn/libtorrent/issues/1997 这两个 Issue 中,有人提到是 libtorrent 本身的 IO 和缓存实现存在问题,导致磁盘 IO 效率过低。但是这两个问题也都是在 Windows 上观察得出的,目前提供的方法是关闭 OS Cache,打开 libtorrent 的 coalesce reads & writes 选项,以在 Windows 上达到较好的 IO 性能表现(这个选项在 Linux 上是不必要的,因为 Linux 有 pwritev() 的实现,不需要通过 pwrite() 进行模拟——arvidn)。

但是在 Linux 上,这个问题仍然没有任何解决的迹象。在我看来,假定 libtorrent 自身的内存管理不存在问题,没有内存泄漏的情况,那么内存占用应该存在于两个方面:一是在 libtorrent 1.1 解决了 IO 性能问题以后引入的新 bug,即 lt 可以同时打开大量的 File Descriptor 且不陷入死锁,那么由于使用 buffered IO 的问题,在系统内核层面上消耗了大量的内存;另一个可能性是 TCP Socket buffer,libtorrent 1.1 相比 1.0 修正了大量 TCP Socket 连接卡死的问题(甚至出现了 too many open files 的情况,参见之前的文章,这个现象在 lt 1.0 从未出现过),大量 peer 和 tracker 连接使用的 TCP Socket 在内核层面占用了大量的内存,进而出现内存占用高的问题。

目前先禁用 OS Cache 进行下一步测试,观察是否还会出现内存占用过高。如果有,那么应该是 TCP 造成的问题了。(在看了 IBM 关于 Linux Direct IO 的这篇文章后,我对 IO Buffer 这个方向不报太大希望,因为无论怎么看 Buffered IO 的实现也不像会把自己噎死的样子)

红米 5A 刷欧洲版 MIUI 记录

老年人的第一次刷机。

最近把红米备机拿出来用了,升到了 ADUI 10,感觉还不错,但是广告实在太多。想起来当年被卡 15 天解 BL 锁的限制早过了很久了,就想着把这破系统刷了吧。

查了一圈发现 MIUI EU 版是相对干净的系统,可以在这里取得。

准备工作

解锁 Bootloader
MIUI EU 版刷机包
Android Debug Bridge
第三方 Recovery TWRP
Root 包 Magisk

刷机步骤

  1. 解锁 Bootloader
    1. 进入“设置 -> 开发者选项 -> 设备解锁状态”中绑定账号和设备;
    2. 手动进入 Fastboot 模式(关机后,同时按住开机键和音量下键);
    3. 通过USB连接手机,点击 “解锁”按钮;
  2. 刷入 TWRP
    1. 在 Bootloader 模式下,运行 fastboot flash recovery <twrp_image>刷入 TWRP
    2. fastboot reboot 重启设备,注意此时需要立即按下音量上 + 电源以进入 Recovery 模式,否则 MIUI 会覆盖刷入的自定义 Revocery
  3. Recovery 成功刷入设备后,将手机关机,在关机状态下按住电源键和音量上键,进入 Recovery 模式,滑动 Swipe to Allow Modifications 进入主菜单。点击 Wipe,点击 Format Data,输入 yes 完成格式化,返回上一菜单,点击 Advanced Wipe,选择 Dalvik,Cache,System,Data 和 Internal Storage 分区,并滑动 Swipe to Wipe 进行擦除,然后返回 Recovery 主菜单
    1. 注意可能在 Wipe /data 分区时可能会出现错误:TWRP Unable to mount '/data',如果出现该错误,在 Fastboot 模式下运行 fastboot format userdata清理 /data 分区之后再进行操作
  4. 在电脑磁盘列表中找到手机,复制 ROM 至手机,复制完成后在 Recovery主菜单中,点击 Install,点击 ROM 包,滑动 Swipe to confirm Flash 进行刷入,重启设备
    1. 任意方法刷入 ROM 后,命令窗口中结束 adb 服务adb kill-server
  5. 重启进入 Recovery 模式,按照刷 ROM 的方式刷入 root 包

然后大功告成

参考资料

https://www.zhihu.com/question/50231539/answer/530627637
https://www.reddit.com/r/Nexus6P/comments/3qnzz0/twrp_unable_to_mount_data/

 

优化 wine 的字体显示

有时候总有一些不得不在 Linux 下跑一些 Windows 程序的需求,所以我们会用到 wine,但是 wine 默认并不是给中文用户设计的,因此我们需要一些办法来解决中文显示乱码和效果差的问题。

中文乱码,主要表现是非 ASCII 字符全部都显示为方框,这个是没有字体造成的,需要在 ~/.wine/drive_c/windows/Fonts 下面安装中文字体,一般来说,装好宋体、黑体和微软雅黑这些常用的就能用了,如果想装点别的,自然也可以。这里提供了一些打包好的基础字体下载:

cd ~/.wine/drive_c/windows/Fonts
wget https://down.gloriousdays.pw/Fonts/wine_fonts.tar.xz
tar cJvf wine_fonts.tar.xz
rm wine_fonts.tar.xz

搞定了字体以后,很快就会发现这些字体的显示效果十分差,完全没有做 AA 的意思,我们用 winetricks 解决这个问题:

apt install winetricks
winetricks settings fontsmooth=rgb

重新打开 exe 程序即可

使用 zram 进行内存压缩

对于像 KS-3 这样只有 4GB 内存的小内存服务器,如果想在上面跑一些比较复杂的服务,经常会遇到内存不足的问题。一般说到内存不足,第一反应都是加 swap 空间,但是对于机械硬盘的场景,添加盲目添加 swap 空间并不是一个好的选择,因为这样会显著增加系统整体的 latency。这个时候 zram 就可以派上用场了。

zram 是在 Linux Kernel 3.2 加入的一个模块,其功能是在内存中开辟一块空间,用来存储压缩后的内存数据,这样可以在牺牲一定的 CPU Cycle 的情况下,在内存中存储尽量多的数据而不需要写入到磁盘。

对于 Ubuntu 系统,开启 zram 的方法很简单,只需要安装 zram-config 这个包之后重启即可。zram 默认会将系统内存的一半作为 zram,然后根据 CPU 核心数平均分配到每个 zram 设备。比如在我的 KS-3 上,通过 zramctl 查看 zram 的情况,是这样的:

# zramctl
NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram3 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram2 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram1 lz4           491M   4K   63B    4K       4 [SWAP]
/dev/zram0 lz4           491M   4K   63B    4K       4 [SWAP]

注意到这里的压缩算法,有两种算法 lzo 和 lz4 可选,默认是 lzo。根据 Benchmark,lz4 的压缩和解压性能在压缩率和 lzo 持平的情况下显著高于后者,因此我们应该采用 lz4 而非 lzo 以获得更高的系统效率。

虽然 zramctl 可以帮助调整 zram 的情况,但是我们还是应该在系统启动时就将这些东西配置好。zram-config 安装好后会默认添加 zram-config.service,这个 service 是运行 /usr/bin/init-zram-swapping 这个脚本以配置对应的 zram 设备,默认情况下,其配置设备的内容应该是这样:

#!/bin/sh

# load dependency modules
NRDEVICES=$(grep -c ^processor /proc/cpuinfo | sed 's/^0$/1/')
if modinfo zram | grep -q ' zram_num_devices:' 2>/dev/null; then
  MODPROBE_ARGS="zram_num_devices=${NRDEVICES}"
elif modinfo zram | grep -q ' num_devices:' 2>/dev/null; then
  MODPROBE_ARGS="num_devices=${NRDEVICES}"
else
  exit 1
fi
modprobe zram $MODPROBE_ARGS

# Calculate memory to use for zram (1/2 of ram)
totalmem=`LC_ALL=C free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/  *.*//'`
mem=$(((totalmem / 2 / ${NRDEVICES}) * 1024))

# initialize the devices
for i in $(seq ${NRDEVICES}); do
  DEVNUMBER=$((i - 1))
  echo $mem > /sys/block/zram${DEVNUMBER}/disksize
  mkswap /dev/zram${DEVNUMBER}
  swapon -p 5 /dev/zram${DEVNUMBER}
done

如果我们要默认使用 lz4 算法,那么应该将最后一段改成这样:

# initialize the devices
for i in $(seq ${NRDEVICES}); do
  DEVNUMBER=$((i - 1))
  echo lz4 > /sys/block/zram${DEVNUMBER}/comp_algorithm
  echo $mem > /sys/block/zram${DEVNUMBER}/disksize
  mkswap /dev/zram${DEVNUMBER}
  swapon -p 5 /dev/zram${DEVNUMBER}
done

注意算法设置一定要在配置空间大小之前,否则不能正确修改。

修改过后,运行 systemctl restart zram-config 就可以载入新的配置。

参考资料:

https://askubuntu.com/questions/1044976/make-zram-use-lz4-compression-algorithm
https://github.com/lz4/lz4
https://sites.google.com/site/easylinuxtipsproject/speed#TOC-Only-768-MB-RAM-or-less:-enable-zRam
http://tuxdiary.com/2015/07/28/zram/
https://wiki.archlinux.org/index.php/improving_performance#Zram_or_zswap

 

修改 Linux 默认的 IO Scheduler

RHEL 系我不知道怎么弄,我也没有机器是这个

在 /etc/default/grub 中,找到 GRUB_CMDLINE_LINUX_DEFAULT="" 这行,可能原来后面双引号中间有参数,这个各个机器不同,如果要修改默认的 CFQ Scheduler,那么在这里加上 elevator=noop 这样的内容,且和之前的旧内容有一空格。之后 update-grub2 重启即可。

之后 cat /sys/block/sda/queue/scheduler 就可以看到当前使用的调度器

IO Scheduler 有三个选择 cfq noop 和 deadline

参考资料:

https://www.ibm.com/developerworks/cn/linux/l-lo-io-scheduler-optimize-performance/index.html
https://askubuntu.com/questions/78682/how-do-i-change-to-the-noop-scheduler
Red_Hat_Enterprise_Linux-6-Performance_Tuning_Guide-en-US
Red_Hat_Enterprise_Linux-7-Performance_Tuning_Guide-en-US