配置Anki同步服务Ankisyncd,并使用Apache2反代实现https加密同步

使用Ankiweb同步卡片在我这里确实是有些慢,所以我自己尝试搭建了自己的Anki同步服务Ankisyncd,搭建好后又发现安卓版的Ankidroid只支持https同步,所以我又用Apache2对同步地址进行了反向代理。

文章前半部分其实还是老生常谈,最精华的,我觉得是反向代理那部分内容。这篇文章全文无图片,只有文字,可以看作是整个实现过程的思路和要点整理,我省去了很多前置步骤,例如许多命令我都是直接拿来用的,而它们在你自己的服务器中可能需要提前安装。 在文章最后会附上我所参考的资料,那里一般有完整、详细的说明,如果想自己搭建类似服务,遇到问题后建议先去浏览这些内容。 文章分成三部分,先介绍在服务器端怎样搭建Ankisyncd,之后介绍电脑版Anki和安卓版Ankidroid怎样配置,在Ankidroid同步失败后又介绍了在服务器端怎样用Apache2实现反向代理。我的服务器是阿里云的学生轻量应用服务器,系统版本是Ubuntu18.04。

服务器端

在服务器安装Ankisyncd[1]

大致过程如下[2]:

git clone https://github.com/tsudoko/anki-sync-server.git /usr/local/anki-sync-server

git submodule update --init

cd anki-bundled

pip3 install -r requirements.txt
# 可预先从requirements.txt中删去“pyaudio”,这个不是必装的。

pip3 install webob

修改/usr/local/anki-sync-server下的ankisyncctl.py文件,把开头的#!/usr/bin/env python改为#!/usr/bin/env python3 按教程,这样就算安装好了,但我第二步但那条命令git submodule update --init运行之后一直卡在Cloning into '/usr/local/anki-sync-server/anki-bundled'...这里,原因是github访问速度太慢。我一开始想的办法是把github的仓库文件克隆到gitee(码云),修改 /usr/local/anki-sync-server下的.gitmodules文件,把url改成码云的链接。我也在git里add和commit了,但还是卡在这里。后来我用了一个粗暴的办法,从github下载库文件后,直接上传到vps上,解压缩到anki-bundled文件夹里面。 安装完成。

启动Ankisyncd[3]

cd /usr/local/anki-sync-server
screen -S anki
python3 -m ankisyncd

之后在浏览器里访问“http://你的ip:27701”,浏览器页面上会显示一句“Anki Sync Server”。注意,如果访问不了,可能是需要在阿里云后台开放端口27701。 按Ctrl+A,D,退出会话,Ankisyncd会继续在后台运行。

管理用户

创建用户:

cd /usr/local/anki-sync-server
./ankisyncctl.py adduser 

回车后会提示输入密码。 其他操作:

Commands:
  adduser  - add a new user
 deluser  - delete a user
 lsuser - list users
 passwd  - change password of a user

电脑端Anki配置

Releases · tsudoko/anki-sync-server · GitHub了解到,Ankisyncd最新版本是2.1.0,支持的Anki版本是:Anki from 2.0.27 to 2.1.16;AnkiDroid 2.3 and up。也就是说,目前最新的Anki版本(2.1.38,2021年1月23日)是无法使用的。经测试,在2.1.38版本中用刚刚设定的账号和密码登录时会提示“用户名或密码错误”。我用的版本是2.1.15。从2.1.20开始就不正常、无法登录了(2.1.20还是2.1.21我给忘了,可以登录但同步有问题)。 Anki电脑版若要登录到自建服务器,需要安装一个插件。 打开“工具”——“附加组件”——“查看文件”,新建一个文件夹“AnkiServer”(随便命名),在新建的文件夹内新建文件__init__.py,填入如下内容:

import anki.sync, anki.hooks, aqt

addr = "http://127.0.0.1:27701/" # put your server address here
anki.sync.SYNC_BASE = "%s" + addr
def resetHostNum():
    aqt.mw.pm.profile['hostNum'] = None
anki.hooks.addHook("profileLoaded", resetHostNum)

把里面的ip地址换成你自己的服务器的地址。 重启Anki,点击同步按钮,输入用户名和密码即可正常同步。

安卓端Ankidroid配置

把上面的同步地址填入较新版本的Ankidroid(版本2.14.2),点击同步按钮会提示同步出错,因为那个地址是http的,而这种传输方式已被禁止。使用较低版本的Ankidroid(2.8.3),正常。 我不想使用旧版本的App,因此就需要让同步数据加密传输,即让同步地址由http变成https的。由于我的vps已经安装了Apache2,因此我使用Apache反向代理转发同步地址。 由于我对这块内容并不是很熟,所以下面的步骤当中肯定有冗余。 我的计划是,先配置一个不使用ssl的反向代理(使用80端口),然后用Certbot获取Let’s Encrypt证书(会自动生产一个新的conf配置文件,使用443端口)。

启用模块

a2enmod proxy
a2enmod proxy_http
a2enmod ssl

新建Apache配置文件

cd /etc/apache2/sites-available
vim your_domain.conf

在your_domain.conf文件中填入以下内容[4]


 ServerName anki.xiake.me

 
 ProxyPass http://127.0.0.1:27701/
 ProxyPassReverse http://127.0.0.1:27701/
 

 UseCanonicalName off
 ProxyRequests off
 ProxyPreserveHost on

保存后,启用配置

a2ensite your_domain-le-ssl.conf
systemctl reload apache2

在浏览器地址中填入你设置的域名,应该就能得到刚才访问那个ip地址一样的结果。

使用Certbot获得Let’s Encrypt的SSL证书[5]

certbot --apache -d your_domain

按提示操作即可,之后会得到一个新的conf配置文件,类似下面这样

 ServerName your\_domain

 
 ProxyPass http://127.0.0.1:27701/
 ProxyPassReverse http://127.0.0.1:27701/
 

 UseCanonicalName off
 ProxyRequests off
 ProxyPreserveHost on

SSLCertificateFile /etc/letsencrypt/live/your\_domain/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/your\_domain/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf

重新加载配置,之后在浏览器里就可以使用加密地址访问了。

a2ensite your_domain-le-ssl.conf
systemctl reload apache2

在Ankidroid中的设置

打开“侧边栏”——“设置”——“高级设置”——“自定义同步服务器”,选中“使用自定义同步服务器”,把“同步地址”和“媒体文件同步地址”分别设为:

https://your_domain/
https://your_domain/msync

而后返回主页,点击同步按钮,输入设定的用户名和密码,就可以同步了。

参考资料

[1] github仓库, ankisyncd
[2] 知乎专栏文章, (一 超详细自架 Ankisyncd 版)
[3] 博客文章, Anki同步服务器搭建教程
[4] Anki Community Wiki, HTTPS Encryption with Apache Proxy
[5] How To Secure Apache with Let’s Encrypt on Ubuntu 18.04