In an effort to gain independence from Big-Data, I have been setting up a locally hosted image server for our family. The crucial components are:
Immich - The image server and mobile+desktop gallery
ImmichFrame - The digital picture frame which syncs with an Immich album
Tailscale - Magic network glue. The VPN to have all devices on the same network.
Frameo Digital Image frame - Used because of access to the android system through adb
This is post is about getting the Frameo device working with Tailscale and ImmichFrame. There are other resources about setting up Immich and ImmichFrame. But for those curious: Both can be setup as Docker containers.
The frame
Baby helping me hack the Frameo. (screenshot of ImmichFrame on my phone)
Device needs to be setup on boot to run ImmichFrame. Usually on Linux this is done with a systemd service. But we don't have that luxury. Cron jobs are non existent on Frameo. I observed many system files get wiped on boot. Probably a security feature. After poking around, I found a boot persistent file:
/system/bin/run_iotv.sh
We'll take over this file so any changes made to the Frameo device will be repeatable after boot. With this in out back pocket, let's continue to add Tailscale, WebView, and some watchdog, logging utilities, and finally Tailscale enabled ssh remote access.
The Frameo device runs an older Android 6 Rockchip system. Its kernel does not provide a usable TUN device, so the normal Tailscale VPN mode cannot work. Instead, Tailscale runs in userspace mode and a local port forward makes the remote Immich server look like a local service to ImmichFrame.
TUN is a virtual network interface provided by the operating system kernel. A VPN program writes IP packets into a TUN interface, and the kernel then treats those packets like traffic from a normal network adapter. This allows applications to use Tailscale IP addresses directly, with normal routing handled by the operating system.
In a standard Tailscale installation, the daemon creates or uses a TUN device, adds routes for the Tailscale network, and transports those packets through the encrypted tailnet. Applications do not need to know that a VPN is involved.
Since this Frameo device runs Android 6 on an older Rockchip kernel, the kernel was built without usable TUN support, commonly indicated by a missing `/dev/net/tun` device or missing `CONFIG_TUN` support. Without TUN, Tailscale cannot install the normal VPN interface and Android applications cannot directly route to addresses such as Tailscale IP address like `100.119.121.28`.
Tailscale's `--tun=userspace-networking` mode works around that kernel limitation. Instead of creating a kernel network interface, `tailscaled` provides a userspace network stack. But how to connect this to the immich frame appilcation?
Photos, frame, and album updates are entirely locally hosted. Photos we want to share are added them to an album on our Immich server. ImmichFrame, (a seperate service) syncs with Immich and servers the album contents to all digital frames.