├── .gitignore
├── sync
├── cleanup
├── root
└── defaults
│ ├── autostart
│ └── menu.xml
├── .dockerignore
├── backup
├── Dockerfile
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .env
2 | docker-compose.yml
3 |
--------------------------------------------------------------------------------
/sync:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | curl localhost:8765 -X POST -d '{"action": "sync", "version": 6}'
3 |
--------------------------------------------------------------------------------
/cleanup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | sudo docker compose -f ~/anki-desktop-docker/docker-compose.yml down
3 | sudo docker compose -f ~/anki-desktop-docker/docker-compose.yml up -d
4 |
--------------------------------------------------------------------------------
/root/defaults/autostart:
--------------------------------------------------------------------------------
1 | # Set layout to avoid keybinding warnings
2 | setxkbmap -layout us &
3 |
4 | sudo chown -R 1000:1000 /config/app && \
5 | mkdir -p /config/app/Anki2 && \
6 | mkdir -p /config/app/Anki
7 |
8 | export DISABLE_QT5_COMPAT=1
9 | export LC_ALL=en_US.UTF-8
10 |
11 | anki
12 |
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git/
2 | .gitignore
3 | .dockerignore
4 | README.md
5 | backup
6 | cleanup
7 | sync
8 |
9 | # OS and editor junk
10 | .DS_Store
11 | *.swp
12 | .vscode/
13 | .idea/
14 |
15 | # Docker Compose/local build files
16 | docker-compose.yml
17 |
18 | # Runtime files
19 | config/
20 | *.log
21 |
22 |
--------------------------------------------------------------------------------
/backup:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Define the prefix, extension, and current date/time components
3 | prefix="/config/app/backups/"
4 | extension="apkg"
5 | current_date="$(date +'%Y_%m_%d_%H_%M_%S')"
6 |
7 | # Combine the components to create the file name
8 | file_name="${prefix}_${current_date}.${extension}"
9 |
10 | curl localhost:8765 -X POST -d '{
11 | "action": "exportPackage",
12 | "version": 6,
13 | "params": {
14 | "deck": "Default",
15 | "path": "'$file_name'",
16 | "includeSched": true
17 | }
18 | }'
19 |
--------------------------------------------------------------------------------
/root/defaults/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 |
19 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM lsiobase/kasmvnc:ubuntunoble
2 |
3 | ARG ANKI_VERSION=25.07.5
4 |
5 | # Install dependencies (fix openbox autostart error by installing python3-pyxdg)
6 | RUN apt-get update && \
7 | apt-get install -y \
8 | anki \
9 | wget \
10 | zstd \
11 | xdg-utils \
12 | libxcb-xinerama0 \
13 | libxcb-cursor0 \
14 | python3-xdg \
15 | && apt-get clean \
16 | && rm -rf /var/lib/apt/lists/*
17 |
18 | # Download, Extract, and Install Anki
19 | RUN dpkg --remove anki && \
20 | wget https://github.com/ankitects/anki/releases/download/${ANKI_VERSION}/anki-launcher-${ANKI_VERSION}-linux.tar.zst && \
21 | tar --use-compress-program=unzstd -xvf anki-launcher-${ANKI_VERSION}-linux.tar.zst && \
22 | cd anki-launcher-${ANKI_VERSION}-linux && ./install.sh && cd .. && \
23 | rm -rf anki-launcher-${ANKI_VERSION}-linux anki-launcher-${ANKI_VERSION}-linux.tar.zst
24 |
25 | # Create a config directory to be mounted and add symbolic links to Anki's real config directories
26 | RUN mkdir -p /config/.local/share && \
27 | ln -s /config/app/Anki /config/.local/share/Anki && \
28 | ln -s /config/app/Anki2 /config/.local/share/Anki2
29 |
30 | COPY ./root /
31 |
32 | EXPOSE 3000 8765
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Anki Desktop in Docker
2 |
3 | This project is inspired by [pnorcross/anki-desktop-docker](https://github.com/pnorcross/anki-desktop-docker), with a few tweaks. It provides a `Dockerfile` that uses [linuxserver/docker-baseimage-kasmvnc](https://github.com/linuxserver/docker-baseimage-kasmvnc) as the base image to run the desktop version of Anki inside a container.
4 |
5 | Why? Because it makes automating Anki (with addons like AnkiConnect) easier.
6 |
7 | The Anki desktop app runs in a browser (via VNC) on port `3000`. Your Anki data is stored in a volume mounted at `/config/app` inside the container.
8 |
9 | ---
10 |
11 | ## Requirements
12 |
13 | - **Docker**
14 | - **Docker Compose** (usually bundled with newer Docker versions)
15 | - **Ubuntu** (focus is on Linux, but Docker can work on Windows too with a slightly different setup)
16 | - **cron** (for scheduling tasks)
17 | - **AnkiConnect addon** (to enable scripting Anki via port `8765`)
18 |
19 | ---
20 |
21 | ## Files in This Repo
22 |
23 | ### `Dockerfile`
24 | Builds the container with Anki 25.02.7 You can change the Anki version, but compatibility may vary.
25 |
26 | ### `docker_installation`
27 | Contains commands to install Docker on Ubuntu.
28 |
29 | ### `cleanup`
30 | Helps clean up system resources. Anki seems to have a memory leak—on systems with only 1GB RAM, the container might become unresponsive after ~1 day. You can use `cron` to run cleanup every 12h.
31 |
32 | ### `backup`
33 | Uses `curl` to call AnkiConnect (on port 8765) to create a backup. Schedule this with `cron` for daily backups.
34 |
35 | ### `sync`
36 | Also uses `curl` to call AnkiConnect. It forces a sync and optionally reschedules cards (useful with FSRS + AnkiDroid combo).
37 |
38 | ---
39 |
40 | ## Docker Compose Setup
41 |
42 | Create a `docker-compose.yml` in the root of the repo:
43 |
44 | ```yaml
45 | services:
46 | anki-desktop:
47 | build:
48 | context: ./
49 | dockerfile: Dockerfile
50 | environment:
51 | - PUID=1000
52 | - PGID=1000
53 | volumes:
54 | - ~/.local/share/Anki2:/config/app/Anki2
55 | - ~/backups:/config/app/backups
56 | ports:
57 | - 3000:3000
58 | # Anki Connect port
59 | - 8765:8765
60 |
61 | ````
62 |
63 | * The **first volume** maps your local Anki data (on Ubuntu it's usually at `~/.local/share/Anki2`) into the container.
64 | * The **second volume** is for backups you extract via AnkiConnect.
65 |
66 | To get started:
67 |
68 | ```bash
69 | git clone
70 | cd anki-desktop-docker
71 | docker compose up --build -d
72 | ```
73 |
74 | Then open your browser and head to:
75 |
76 | ```
77 | http://localhost:3000
78 | ```
79 |
80 | ---
81 |
82 | ## AnkiConnect Configuration
83 |
84 | Make sure your AnkiConnect config (inside Anki) looks like this:
85 |
86 | ```json
87 | {
88 | "apiKey": null,
89 | "apiLogPath": null,
90 | "ignoreOriginList": [],
91 | "webBindAddress": "0.0.0.0",
92 | "webBindPort": 8765,
93 | "webCorsOrigin": "http://localhost",
94 | "webCorsOriginList": ["*"]
95 | }
96 | ```
97 |
98 | ---
99 |
100 | ## Cron Example
101 |
102 | Open your crontab:
103 |
104 | ```bash
105 | crontab -e
106 | ```
107 |
108 | And add:
109 |
110 | ```cron
111 | 0 8 * * * (~/anki-desktop-docker/sync && date) >> ~/sync.log 2>&1
112 | 0 9 * * * (~/anki-desktop-docker/backup && date) >> ~/backup.log 2>&1
113 | 0 10,22 * * * (~/anki-desktop-docker/cleanup && date) >> ~/cleanup.log 2>&1
114 | ```
115 |
116 | This sets up:
117 |
118 | * **8:00 UTC** — Sync
119 | * **9:00 UTC** — Backup
120 | * **10:00 & 22:00 UTC** — Cleanup
121 |
122 |
--------------------------------------------------------------------------------