Category Archives: Tech

小记备份:从账本说起

毕业后工作一段时间以来感觉自己的花销越来越不可控,之前听闻一个朋友说毕业后第一年基本是存不下钱的,当时还不以为然,结果后来真的应验了。于是在今年国庆后正式开始记账。作为整天与纯文本打交道的程序员自然更青睐于纯文本的记账工具,于是在看了 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」∠)_

小记:搬家

如果你是从 RSS 来的,这里说的搬家不是肉身搬家,是服务器迁移啦。

之前在一篇文章的评论里青箬笠同学吐槽过访问我的 blog 的速度太慢,其实我也知道,但苦于找不到理想替代服务商所以一直没搬。网上讨论得热门的 DigitalOcean 和 Vultr 我都用过,感觉速度上比 Linode 还不如。仅就访问速度来看最理想的服务器当然还是阿里云,而且其实我也有一台阿里云主机是当时打折时入手的(事后证明来之易则弃之不惜),但是对备案什么的实在抵触,何况大多数文章已经会搬到豆瓣日记就没必要把鸡蛋都丢在国内了。

前两天在网上冲浪的时候突然逛到了这个帖子,才知道原来 AWS 也有做入门级市场,那还犹豫什么?于是马上开了一台。我选的是美国西海岸的主机,至于为什么不选更近的东京新加坡,只是感觉服务器这东西就应该搭在那里罢了。

AWS 直到现在还没有支持 Ubuntu 18.04,不过选了 16.04 的用户在连上主机的时候会有提示可以升级,五分钟左右就可以搞定。一开始还是遇到了一个比较麻烦的问题—AWS 默认的用户叫 ubuntu,对于一个强迫症兼不折腾会死星人必须要换成自己的名字。于是重新创建 sudo 用户,但是用 ssh-copy-id 的时候提示 Permission Denied,找了半天才发现原来 AWS 已经把密码登录关闭了。解决了这个问题后就是和 Linode 一样的设置方式啦。

搭建 WordPress 已经可以在网上找到无数的脚本了,但我还是更倾向于自己一步一步慢慢来。首先还是按照 Linode 上的这篇搭建好 LAMP 服务,之后再参照这篇设置好 WordPress。初学者在这个过程中碰到的最大的问题大概就是 Apache2 的配置问题,如果遇到问题可以参考我的配置。我是把根域名重定向到了 www 下,所以可以根据自己需要将第二个 block 删去,之后只要把目录、域名、email 改成自己的就行了。成功访问后建议先装上证书再开始配置,毕竟在配置过程中要输入数据库的密码。

之后要把自己在 WordPress 上的文章、评论、多媒体等搬过去,我用的是 UpdraftPlus 这个插件,备份的时候把所有的勾都点上,上传到 Google Drive,然后在新的服务器站点重新装上这个插件,授权访问 Google Drive 再恢复就可以了,你会发现所有的数据都原封不动地在原地,就像没有换过服务器一样。

例行做完这一切就完成站点搭建了,但还剩下一个问题—怎么能确保自己的服务器定时备份。Linode 上已经原生支持定时备份,非常好用,但 AWS 上只有 snapshot 而不原生支持定时备份。难道我要每天登上 AWS 后台点击一下吗?显然太愚蠢了。只要有一台服务器就有无限可能。于是再次借助网上冲浪我找到了完美的解决方案。

我们可以参照这篇文章来完成自动创建新的 snapshot 同时定时删除旧的,创建新的好理解,但为什么要删除旧的呢?因为亚马逊的每个 snapshot 都要花钱的,虽然是按照容量计费,同时亚马逊会对每个 snapshot 只做增量备份,但积少成多呀。既然都自己搭建服务器了当然要找一个一劳永逸的方法啦(虽然基本上没过多久就又开始折腾了)。

脚本里有一点需要改进的地方,我的服务器在 crontab 运行时无法识别 aws 这条命令,所以要把第 12、25、29 行的 aws lightsail 改成 /usr/local/bin/aws lightsail1。之后设置成每天运行就可以啦。

和 Linode 相比 Lightsail 没有 Swap Partition,所以同样是 1G 内存 AWS 会更加吃力,不过我也不需要跑很多程序,同时访问速度 AWS 还是相当喜人的,实测在电信下 scp 可以到 5MB/s 的速度,再也不愁访问速度啦。

折腾完这些就是真正完成服务器的搭建了,同为 blog 圈的朋友无须赘述我们对个人 blog 的执着,只是觉得这一步步下来的确像是一种仪式感十足的祭奠。我也会在 RSS 上订阅许多个人 blog,然后在发现许久不更新后感到惋惜,像是看到一座座陌生的墓碑一样,回看旧文如灵魂对读者的唠叨。既然总要相忘于江湖,这执着又能称得上浪漫吗?

外人大概很难懂,所以是外人。

  1. 可以用 which aws 来获取路径。