Tailscale just posted a blogpost on getting tailscale to work on kindle. I had tried this before, but I had to make some major changes before it worked on my old kindle. Since jailbreaks are most useful on old tech anyway, I thought it was prudent to write a post highlighting what went wrong and what I had to fix.
I have a Gen 8 Kindle Basic from… 2015?
I have tried to get self-hosted reading forever, and the biggest issue was getting epubs on kindle. Calibre is so good, its basically jellyfin for books, but it needs a cable to connect to any device. You could use the content server, but I don’t think you can start it headless on a server. Also I don’t think you can do progress syncing, but I’m probably wrong. Even if that wasn’t an issue, the default kindle firmware doesn’t allow you to read epub files, which are probably the most ubiquitous. There is no open source application that you can use on an Android phone either. I kind of left this for almost 5-6 years, but still kept bringing it with me on every move.
Regardless, with the WinterBreak jailbreak released, it becomes a lot easier. After applying the jailbreak, I also installed the KUAL framework, and then the KOReader application. This also has an android application, and lots and lots of plugins. It also has a progress sync, but it syncs to a public server.
As I did this, I started thinking about my Currently selfhosted services. It should be easy enough to self-host Calibre-Web-Advanced, which also has a sync plugin (it’s basically a slightly modified version of the ProgressSync plugin that comes default with KOReader). It also provides an OPDS endpoint so I can get files onto the kindle.
But all this depends on the kindle being able to connect to the server.
I already use Tailscale for Self Hosting without a public IP address or domain, so I just had to get the kindle on the tailnet. I tried to use subnet-routing, but that only works for incoming connections, not outgoing.
That’s when I came across Tailscale for KUAL. I tried to install and run it, and it worked! … Almost. See mitanshu7/tailscale_kual#2. However, because my kindle kernel does not have the tun.ko kernel module compiled in, I could not use the fix in that issue. The socks5 proxy fix and some AI asking, it told me to instead use the http proxy setting. Note that this is a good time to start using the ssh plugin on the kindle to ssh in!
While the following changes also work for the KUAL plugin above, I realised that the koreader plugin for tailscale would probably be easier to work with. It does basically the same thing.
So I changed the lines
# Start daemon
nohup ./tailscaled --statedir=/mnt/us/tailscale/bin/ > tailscaled.log 2>&1 &in ./bin/start_tailscale.sh with
# Start daemon
nohup ./tailscaled --statedir=/mnt/us/tailscale/bin/ --tun=userspace-networking --outbound-http-proxy-listen=localhost:8080 --socks5-server=localhost:1055 > tailscaled.log 2>&1 &Now setting the HTTP proxy variable in Settings > Network > HTTP Proxy to http://localhost:8080 should have just worked. But when has life ever been so kind?
The CWASync plugin was not able to connect to the server in spite of the http proxy. The proxy itself worked, I checked by curling from the ash shell plugin with the http_proxy envvar set. The OPDS plugin and
There were no logs to crash.log either. With a lot of help from AIStudio I added logging to check why the connection was failing to my tailscale server. It initially looked like SPORE was the issue, but the error log string was not found in the Spore library. So I just greped the string in the common folder in koreader. This way, I finally realised that this was because the luasec library does not support https over a proxy. There was an attempt to add this feature, but it seems the original author never finished it.
So I asked AIStudio to vibe code the fix. It did surprisingly well, except it seemed that the initial connection to the http proxy was also going through ssl, which was not necessary. The easy way was to simply bypass when a local connection was required. Ideally it should implement noproxy support, but 🤷.
I added this fix to my fork of luasec.
To use it in my KOReader build, I just had to replace koreader/common/ssl/https.lua with the new file. Now everything works!
I don’t exactly know how to upstream this change. Should it go to luasec? Or should KOReader replace luasec with lua-http? Let your opinion be known on this issue.