How it works
Android said no. We found a way.
Android apps can't run servers the usual way: no root, no Docker, no access to the video hardware from Linux. Here's how Homedroid gets around all three.
01 / LINUX WITHOUT ROOT
Servers disguised as libraries
Since Android 10, an app may only run programs that shipped inside its APK. So SSH, Caddy, Tailscale and FFmpeg are compiled for Android and packed in as lib*.so files, which Android happily unpacks and runs.
Everything else lives in Alpine Linux under proot, which translates system calls so Linux software believes it has a normal machine, while it's really inside the app's private folder.
# what Android sees
lib/arm64/libsshd.so
lib/arm64/libcaddy.so
# what you see
$ alpine
localhost:~# apk add htop
02 / DOCKER WITHOUT DOCKER
Container images, unpacked by hand
Docker needs kernel features no app can touch. But an image is just layers of tarballs. Homedroid pulls them from Docker Hub or ghcr.io itself, checks every layer's checksum and stacks them the way Docker would.
Hard links (forbidden in app storage) become copies; absolute symlinks get rewritten. That's how Immich and PostgreSQL run from their official images, on a phone.
# ghcr.io/immich-app/immich-server
manifest → linux/arm64
layers → sha256 checked
rootfs → runs under proot
03 / A VIDEO CHIP FOR JELLYFIN
A little shim with a big job
The phone's encoder is only reachable through Android's MediaCodec, which a Linux FFmpeg can't use. So Homedroid builds an Android FFmpeg with MediaCodec and quietly swaps it in.
Jellyfin asks for V4L2 hardware encoding; a tiny shim hands that job to MediaCodec and everything else to Jellyfin's own FFmpeg. Jellyfin never knows it's on a phone.
jellyfin → h264_v4l2m2m
shim → h264_mediacodec
# encoded by the phone's video chip
And a handful of small, documented patches to proot and FFmpeg make the rest of Linux feel at home on Android. Read the details →