├── .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 | 4 | 5 | 6 | /usr/bin/anki 7 | 8 | 9 | 10 | 11 | /usr/bin/xterm 12 | 13 | 14 | 15 | 16 | 17 | 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 | --------------------------------------------------------------------------------