自定义 Anki 2.1 同步服务器

Anki 是一款卡片式的记忆软件,基于艾宾浩斯遗忘规律而进行复习。用户通过创建自己的卡片或者通过他人共享的卡片进行学习([Anki 怎么用](<https://www.zhihu.com/question/28335314>))。通过 AnkiWeb 可以将卡片在多端同步,但是由于它的服务器在国外,所以同步起来颇慢,本文将介绍如何在自己的云服务器(阿里云,CentOS 7)中创建自己的 Anki 同步服务器。

Anki 有 2.0 和 2.1 两个主要版本,它们的区别类似于 Python 2 和 Python 3,有较大的不同,部分插件也不兼容,所以建议使用较新的 Anki 2.1 版本,本教程介绍 2.1 版本下的同步服务器的搭建。

准备工作

首先需要安装 Python 3 和 pip3,它们的安装教程请见 CentOS Python2 和 Python3 共存

之后创建一个 anki 用户账户

1
2
adduser anki
passwd anki

之后的工作由于使用 anki 用户会比较麻烦,所以建议在权限较高的用户下操作。

下载和安装

从 Github 克隆 Anki Server 的项目:

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

进入 anki-sync-server 目录,安装一些依赖并且新建一个 anki 账户(为了防止兼容性问题可以将账户设置为邮箱地址):

1
2
3
4
sudo pip3 install webob
sudo pip3 install decorator
sudo python3 ankisyncctl.py adduser anki@example.com
Enter password for anki@example.com:

如果无法运行 ankisyncctl.py,可能是由于有依赖没有安装,可以根据出错信息自行搜索安装。

修改 server 启动配置 ankisyncd.conf 中的 host 为主机的内网 IP 地址,其他项目不需要改动:

1
2
3
4
5
6
7
8
9
[sync_app]
host = 127.0.0.1 # 注意,使用内网 IP 地址
port = 27701
data_root = ./collections
base_url = /sync/
base_media_url = /msync/
auth_db_path = ./auth.db
# optional, for session persistence between restarts
session_db_path = ./session.db

服务将会在 27701 端口(即上方的 port 项)运行,你需要在服务器的安全组中添加 27701/tcp 端口,并且在服务器中设置防火墙放行此端口,或者使用 nginx 进行代理,通过 80 端口转发。

直接使用 27701 端口

1
2
sudo firewall-cmd --zone=public --permanent --add-port=27701/tcp
sudo firewall-cmd --reload

使用 nginx 代理

使用 nginx 代理时,可以通过域名进行访问,需要添加二级域名解析(*.example.com)

1
2
3
4
5
6
7
8
server {
listen 80;
server_name anki.example.com
location / {
client_max_body_size 0;
proxy_pass http://127.0.0.1:27701
}
}

然后重新加载 nginx。

测试是否可以启动:

1
python3 -m ankisyncd

所有的日志都将在控制台输出,按 Ctrl-C 停止运行,此时可以使用手机或者电脑配置之后测试是否可以正常同步,注意,同步之前请先备份牌组,第一次同步时请选择“上传”到 Web 服务器,否则可能会丢失内容。客户端的配置方法如下。

客户端配置

Windows 和 MacOS 客户端

在 Anki 客户端的 工具->附加组件中,点击“查看文件”,打开插件目录,在其中新建一个名为 ankisyncd 的文件夹,并且在其中添加 __init__.py,输入以下内容:

1
2
3
4
5
6
7
8
import anki.sync, anki.hooks, aqt

addr = "http://anki.example.com/"
# 注意,addr 的网址必须以 / 结尾,如果你的服务器没有开启 SSL,请使用 http://
anki.sync.SYNC_BASE = "%s" + addr
def resetHostNum():
aqt.mw.pm.profile['hostNum'] = None
anki.hooks.addHook("profileLoaded", resetHostNum)

在客户端中退出同步账号,然后重新启动 Anki 客户端,之后使用你创建的账号(例如 anki@example.com)登录,就可以同步了。

AnkiDroid 安卓客户端

注意,Anki 的 iOS 客户端不支持自定义同步服务器。

在 设置->高级设置->自定义同步服务器中,将“使用自定义同步服务器”勾选上,设置同步地址(例如 http://anki.example.com/)和媒体文件同步地址(例如 http://anki.example.com/msync/),然后在 设置->AnkiDroid常用设置 中,登录你创建的 AnkiWeb 账户,在主界面中下拉就可以同步了。

参考网站:自建Anki同步服务器