爷爷

爷爷是位老党员──我们家族唯一的党员。

我不知道他对这一身份有什么看法,在他那个年代这似乎是件稀松平常的事。或许是因为他的「成分」非常干净,碰巧被别人拉去就入了。不像现在要写申请书,要做各种调查手续等等。我还记得初中入团填写申请表的时候还用爷爷的名义写了一封推荐信,尽管他并不识字,就跟那个年代大多数农民一样。

在我印象里,爷爷总是笑笑的没发过脾气,就像教科书里经典的慈祥老头那样。爷爷爱抽烟,到八十岁了还抽得跟二十几岁小伙子那么多;他也爱喝酒──但并不嗜酒,每天午饭总要喝上那么二两。我毫不怀疑他的社交能力,上至他这把年纪的老人,下至还没读高中的学生他都能聊得来。父亲说他以前脾气可差了,家里七个小孩都怕他,以前打小孩的时候是用的擀面杖,比父亲(打我们)用的衣架还疼。

我想起父亲对我们说过的,如果以后他带孙子也是信奉棍棒底下出孝子,或许也是跟爷爷一样?

爷爷的身体一直不差──至少对于他这个年纪的人来说。他的房间在大伯家的四楼,每天都要爬上爬下好几次。几年前爷爷的腿脚越来越没力了,父亲买了支拐杖给他,他还说那是给很老的老人用的,现在这年纪用多丢脸──出自一个快九十岁的老人。尽管住在大伯家,但他每天白天会和奶奶过来我们在老家的房子。他喜欢坐在一张破破的塑料椅上,看拳击、篮球、足球。虽然看不懂电视上的字,听不懂解说依然看得津津有味。父亲说他以前因为长得高,是村里的篮球队员,对于那个年代的南方人,一米七几的确是挺高的了。

这些年爷爷奶奶岁数越来越大,我们每年过年都要回老家过年。尤其是近几年中秋也是假期后,中秋节也回家过节,因为这是我们乡比过年还热闹的节日。2013 年的过年,兄弟姐妹们觉得父母岁数大了,凑齐了整个家族的所有人拍了家族的全家福。照片上爷爷奶奶坐在最前面的中间,旁边后面跟着三十几个儿孙,这是他们眼里最大的成就。但是前些天,爷爷偷偷跟姑丈说,他有个很大的遗憾就是没能抱到自己的男曾孙。堂哥倒是有一个小女孩,但是在他眼里只有男孩才是香火。他并没有跟大伯或者父亲说,大概是觉得跟外戚说比较不会给自己的儿孙那么大压力。这些年我越来越能理解老一辈这些传统观念—这当然不代表认同。爷爷对我们结婚生子这件事的问候一直是善意的,只是稍稍提一下,并没有过分追问。他一直很能拿捏跟人说话的尺度,不会咄咄逼人。我们也能通过其他渠道知道他的一些想法,这也是他的处世之道。

两年前,爷爷的弟弟过世了。他是村里祠堂的管理员,一个鳏老头。父亲和大伯帮忙做完他的后事,爷爷也没了兄弟姐妹。大概是在那之后,爷爷慢慢戒了烟,酒也少喝了。我那时候刚开始工作,问起他想不想喝茅台,我有钱买给他喝了,他说茅台也并没有那么好喝。

可能只是现在不好喝了。

年初的疫情让我们提前回深圳,彼时爷爷的身体看起来还算健康。后来我才知道那时爷爷已经得了癌症,但那时还看不出什么征兆。他的腿脚已经不太有力──虽然依然拒绝用那只拐杖,每天骑着那辆破破的单车慢慢溜着通勤于大伯家和我们家。看起来还有很长时间,理所当然。

中秋前夕,爷爷腰椎盘旧病复发,父亲提前去带他到市区住院。这次出院和以往不一样,情况并没有什么好转。中秋节我们回去的时候,他每天只能躺在床上,一只耳朵已经听不到了,眼睛也有点花,稍微远一点就看不清人。但是意识还很清醒,我还记得假期结束回家的时候在他房间聊了一个小时天。他聊起以前的事都还记得,村里发生了什么大多都知道。除了站起来坐起来没什么力其他都还好,吃得也跟以前一样多。当时我还不知道他的病情,心安理得地回去。

他只剩一个月了。

上周回老家看爷爷,他已经完全听不到了,跟他说话也没了意识,他说的话也很难让人听懂。他已经认不得人了,把别人统统称为同志。姑姑和母亲不忍看到这样,偷偷啜泣。奶奶还不知道发生了什么,只知道老头子身体不太好。偶尔进来问两句老头子好点了吗,被我们挡了回去。我还记得一幕:爷爷躺在床上突然叫了两声「惨呐,惨呐」。我不知道他是太痛了还是条件反射。他已经吃不下药了,好几天吃不下东西。周日回家前我跟堂哥说,下周再回来看他,堂哥说:「不知道能不能到下周呢」。

周三早上,爷爷去世了,在他自己盖的老房子里。

后来父亲跟我们说,周二那天就感觉爷爷呼吸都不一样了,于是几个人把爷爷搬到老房子里。老爷子到老房子后似乎安心了些。

但爷爷最挂念不下的还是奶奶。

周三早上,父亲和大伯坐在爷爷旁边。父亲问爷爷:「你还有什么要交代的吗阿爹?」爷爷此时已经说不出话了。父亲接着说:「如果你挂念的是阿姆(奶奶)的话,我们兄弟姐妹一定会照顾好她的。你就放心吧。」

爷爷的眼角流下了点眼泪,那是父亲和大伯第一次看到爷爷的眼泪。

父亲把爷爷的眼泪擦掉,过了一会爷爷的眼角又有点湿润了,大伯帮他擦干净。后来他们出来坐了一会,让爷爷休息一下。过了不到十分钟,大伯进去看了一下爷爷,爷爷已经走了。他今年九十五岁,从疾病恶化到离去大概两个月的时间,在他自己盖的房子里儿子的陪护下安静地离去。我觉得这是最好的归宿。

小记备份:从账本说起

毕业后工作一段时间以来感觉自己的花销越来越不可控,之前听闻一个朋友说毕业后第一年基本是存不下钱的,当时还不以为然,结果后来真的应验了。于是在今年国庆后正式开始记账。作为整天与纯文本打交道的程序员自然更青睐于纯文本的记账工具,于是在看了 BYVoid 兄的这个系列文章以及 SKYue 兄的这篇文章后也开始用上了 Beancount+Fava

与之而来的问题是账本作为一种私密性极高的数据,我不希望在他人的服务器上有留下任何明文的数据。Dropbox 或者类似的网盘同步显然不合适,棱镜计划的存在让我放不下心。虽说自己的数据并没有涉及到犯罪,但是这些监控行为在价值观上也与我相悖。账本一旦有他人获得明文数据后几乎可以勾勒出我从记账开始后的生活轨迹,我不希望除了自己以外有其他人能看到。墙的存在也是一个考虑因素,虽说在用上 Clash/Surge 后已经可以做到在中国/国际互联网上无缝自由穿梭,但始终会有顾虑。

在 BYVoid 兄的文章 4 中提到了用 Git+git-crypt 的组合,但是使用了 git-crypt 也有弊端。因为 git-crypt 加密后在 Git 的记录都是加密的二进制信息,这就带来了在多设备环境中 merge 的问题。如果在编辑前忘记把最新的 commit pull 下来,在解决 conflict 的时候就没法像明文数据那样比较。虽说可以看 commit 时候的 message 来区分,但是因为是账本信息 commit 的 message 不应该写得很具体,否则也会泄露隐私。

于是在试过几次解决 merge conflict 后我放弃了这个方案,转而使用 P2P 同步的方式在多设备同步。目前我已经切换到 Syncthing 并且(在折腾了一段时间搞不懂它的同步逻辑失败多次后)稳步运行了起来。目前账本的信息保存在家里的电脑、家里的树莓派和自己的笔记本上,这样每次修改账本都可以几乎实时同步到另外几台设备上。

但是在听了《内核恐慌》的 56 期后了解了备份的 3-2-1 原则,想到事实上数据做了同步但是并没有做到很好的备份,而如果家里电脑、树莓派、笔记本一起挂掉(考虑到自己瞎折腾的频率和水平这种可能性并不低)那我的账本就消失了。于是开始着手于完成那个 1,即一份数据在远程。但是如我在上文提到的不能明文存储在他人服务器,在存储到另一台服务器的时候则需要先加密后上传。

(下文偏技术向)

首先我们需要准备几个东西:

  1. 一个 GPG 密钥
  2. 一个远程服务的帐号(我用的是 Backblaze B2
  3. 一台 24*7 运行的设备(非必需)

一、准备 GPG 密钥

首先生成一个 GPG 密钥:

gpg --full-generate-key

一路选默认就可以,如果你之前已经有一个 GPG 密钥,那么可以导入。

gpg --import /path/to/keyfile

之后信任这个密钥

gpg --edit-key YOURKEYFINGERPRINT

如果你导入了你的密钥,按一下 Tab 后应该就会出现了,或者可以用 gpg --list-keys 找到你的密钥,输入 pub 的第二行就好。之后键入 trust。因为是我自己生成的密钥,我就选了 I trust ultimately

二、注册个 Backblaze 的帐号

略……同时创建好一个 B2 的 bucket。

三、安装工具

首先要有 Python 环境,如果你是在 Debian/Ubuntu 上也直接可以通过 apt 安装 backblaze-b2,或者在其他设备可以通过 pip 来安装,具体可以参考官方文档

sudo apt install backblaze-b2 -y / pip3 install b2

安装往后把 backblaze-b2 或者 b2 路径添加到 PATH 里,一般已经自动添加好了。

之后授权 b2 绑定到自己帐号,具体可以看官方文档

b2 authorize-account [<applicationKeyId>] [<applicationKey>]

准备工作就完成了,接下来写个自动化脚本定时跑备份就好了。

四、备份

首先压缩成一个文件,因为只是作为备份而且 Backblaze 有10G 的免费空间,我们尽量把文件压缩到最小。另外可能账本中有些文件是不想包含在压缩包里的,比如编辑器的配置,或者 Git 的记录,可以把它们剔除掉。然后我们用我们的密钥加密这个压缩文件。之后上传到 Backblaze B2 上。

跑脚本前先定义几个变量:

  1. LEDGER_DIR 是存放我们账本的文件夹的上级目录,比如账本在 /home/user/Private/Ledger,那么这个参数就是 /home/user/Private
  2. LEDGER_NAME 即账本文件夹的名字,比如上面的例子就是 Ledger
  3. NOW 就是现在的时间,因为定时备份脚本是把历史都备份起来,所以通过时间命名文件可以知道该备份是何时生成的。可以通过 $($(which date) --iso-8601=seconds) 获得。
  4. GPG_PUB_KEYGPG 密钥的 Fingerprint,即 edit-key 时的那串字符。
  5. BACKBLAZE_BUCKET 是在 B2 上创建的 bucket 名字。
  6. BACKBLAZE_REMOTE_FILE_DIR 是在 bucket 里备份账本的文件夹的名字。

(我在上文或者下文用了很多 $(which xxx),这样可以获得 xxx 程序的绝对位置。因为不知道为什么在 crontab 上有时不这样写会有问题。)

然后跑下面这段脚本。

$(which tar) --exclude=".vscode" --exclude=".git" --create --directory $LEDGER_DIR $LEDGER_NAME | $(which gzip) --best | $(which gpg) --encrypt --recipient $GPG_PUB_KEY --output /tmp/$LEDGER_NAME.$NOW.tgz.gpg

exclude 很好理解,剔除掉部分文件,这里的 --create 即创建一个压缩文件,--directory 是我们先移动到存放我们账本的文件夹的上级目录,之后压缩我们的账本。如果不使用这个参数那么我们的压缩文件会把整个路径的文件夹都放进来,虽然不会把整个路径下所有的文件到包含进来但是就不太好看了。然后我们用 Gzip 进一步压缩文件到最小体积,再交由 GPG 加密,保存到 /tmp 文件夹下。最后就是上传到 Backblaze B2 上。

$(which b2) upload-file $BACKBLAZE_BUCKET /tmp/$LEDGER_NAME.$NOW.tgz.gpg $BACKBLAZE_REMOTE_FILE_DIR/$LEDGER_NAME.$NOW.tgz.gpg

这样就大功告成了。完整的脚本地址我已经存在 GitHub 上,chmod +x backup_ledger.sh 给予可执行权限后在 crontab 里设置定时任务就好了。比如每 3 个小时配分一次的话:

0 */3 * * * /path/to/backup_ledger.sh >/dev/null 2>&1

以上就是我的部分备份工作流。当然这样不止可以备份账本,还有其他重要的私密文件,比如录音录像这些也可以这样保存。这样也可以做到在保护隐私的同时保护数据安全。

(最后希望 Backblaze 不要被墙_(:3」∠)_