Sep 2026 · kindle, jailbreak, tailscale, self-hosting
The native Kindle keyboard is a crime against note taking, and pulling highlights out over USB is archaeology. So I jailbroke a 2015 Paperwhite, put it on my tailnet with userspace Tailscale, and now jacinto steals my reading notes into Obsidian every ten minutes. No cable, no touching the device. Same pattern as the pentest: sensor on one side, Pi on the other.
My Paperwhite 3 (codename Coyote, 7th gen, 2015) sits on firmware 5.16.2.1.1, the last build Amazon ever gave it. That abandonment is what makes the jailbreak possible: LanguageBreak (nov 2023) works up to exactly that firmware. Demo mode, a secret two-finger gesture, and a payload whose filename is literally the exploit, dropped byte-identical on FAT32. A drag-and-drop file manager breaks it silently; the .demo folder is hidden. Full backup first: the jailbreak wipes everything.
Kindle on wifi with fresh firmware equals dead jailbreak. Before any network, the OTA binaries die: renameotabin renames otaupd and otav3 to .bck in /usr/bin. No KUAL installed, so I ran it through the bridge emergency hook, a script that runs as root at boot. Log says "OTA BLOCKED OK".
tailscale_kual runs tailscaled in userspace mode, no TUN device needed — good,
because a 3.0.35 kernel from 2015 has none. Static ARM binaries. The killer
feature: tailscale up --ssh gives integrated Tailscale SSH, zero
dropbear, and the node shows up as "kindle" on my tailnet. One lesson: the auth
key must be reusable; the first single-use one burned itself when the wifi slept
mid-registration. And screen off means wifi asleep means node offline. The
Kindle is not a 24/7 citizen.
First persistence attempt: an upstart job with respawn that waited up to ninety seconds for wifi. Result: white screen after reboot. The framework never renders the UI, but the system stays alive underneath and the USB volume mounts fine. Recovery ran through the same bridge hook: remove the job, kill tailscaled, reboot. Lesson: no extra services on Kindle upstart; the framework does not tolerate a job that hangs.
Final design: nothing at boot. KOReader's launcher carries a hook: if tailscaled is not running, it starts the autostart in the background. Screen on, wifi active — the right moment, because it is exactly when you are reading.
# koreader.sh, right after the FW version check
if ! pidof tailscaled >/dev/null 2>&1; then
TS_AUTOSTART="/mnt/us/extensions/tailscale/bin/tailscale-autostart.sh"
if [ -f "${TS_AUTOSTART}" ]; then
logmsg "tailscale: launching autostart (bg)"
nohup sh "${TS_AUTOSTART}" >/dev/null 2>&1 &
fi
fi
The autostart is an idempotent watchdog: start tailscaled userspace,
tailscale up --ssh, retry with backoff. The whole pipeline lives in a
private repo, including a patch script that re-applies the hook after KOReader
updates, with a byte-identical roundtrip on remove.
KOReader stores highlights and notes in the book sidecar
(documents/<book>.sdr/metadata.pdf.lua): an annotations table with page,
chapter, color, note and timestamp. jacinto runs a cron every ten minutes:
tailscale ping kindle, and if online, scp the sidecars down — rsync
does not exist in the Kindle busybox. The mini pulls them from jacinto and a
parser merges them into the vault with idempotent dedup.
End to end, live: opened KOReader with the Kindle unplugged. The hook fired, tailscaled came up, the node answered with a direct LAN pong in 13 ms, no DERP relay. ssh root@kindle from the laptop, banner SSH-2.0-Tailscale. jacinto's log: "kindle online, scraping... done: 3 sidecars". The vault sync: "sync OK: 3 sidecars -> vault", unchanged, idempotent.
The fleet grew a limb. Same lesson as always: self-hosting is a chain of small, boring decisions, and the most reliable ones are the ones that run while you sleep. My highlights walk to my vault on their own now.