A spare Android phone looks like the wrong answer to a server bill. It has a touch screen, aggressive battery management, vendor software, and none of the familiar assumptions that make a Linux host feel familiar. It also has an ARM processor, flash storage, wireless networking, a modem, and a battery already built in.
That tension is what makes this particular build useful to study. The source author moved several personal services from a Hetzner virtual private server (VPS, a rented virtual machine on a larger physical host) to a CMF Phone 1 with eight ARM cores, 8 GB of memory, and 128 GB of storage. The interesting part is not the novelty of serving pages from a phone. It is the decision to keep Android responsible for hardware while layering ordinary deployment discipline above it.
The result runs web applications, a managed Chrome workload, a finance tracker, and screen sharing. It can recover after a reboot, deploy pinned artifacts from a workstation, and remain reachable when its underlying network changes. That does not make every retired handset a sensible host. It does show where the boundary sits between a weekend trick and maintainable personal infrastructure.
Android is the hardware contract, not the enemy
The author’s first attempt was the clean-looking one: replace Android with postmarketOS and turn the handset into a conventional Linux box. The device port booted, but key hardware support was missing, including Wi-Fi, Bluetooth, and hardware acceleration. Recovery then required restoring Nothing OS with vendor flashing tools after the phone reached a black-screen state.
That failure exposes the first design lesson. A phone vendor has already done the unpleasant integration work for its display, modem, power controls, wireless radios, graphics processor, and battery. A general Linux distribution may offer a familiar userspace while giving up precisely the device support that makes the hardware valuable.
Keeping stock Android divides responsibility more sensibly:
- Android handles devices. Vendor drivers continue to manage radios, charging, thermals, graphics, and sleep states.
- Termux supplies administration. OpenSSH, package management, Caddy, runit, and familiar shell tools live in an Android application environment.
- Tailscale supplies a stable private route. The host keeps one private address as it moves between networks.
- Termux:Boot restores services. Startup hooks bring the supervisor back after Android restarts.
- Health checks prove recovery. Local and public probes verify more than the fact that a process exists.
Termux is not a virtual machine. Its programs use Android’s Linux kernel and a Bionic-based userspace (Bionic is Android’s standard C library, rather than the glibc commonly found on desktop Linux). That difference prevents many ordinary Linux application images from running directly. It also leaves Termux well suited to the smaller job of being the host control layer.
Battery management needs deliberate correction because Android is designed to suspend background work. In the documented build, configuration applies a persistent wake lock, disables idle modes, exempts Termux and Tailscale from background restrictions, prevents Wi-Fi suspension, and configures the VPN as always on. Those settings are source-specific, not a promise that every Android version exposes identical controls.
Compatibility matters more than pretending this is Docker
Most of the author’s applications already existed as ARM64 OCI images (Open Container Initiative images, a standard package format for container filesystems and startup metadata). The first compatibility layer was proot-distro, which makes a Termux process see a Debian root filesystem without requiring a custom kernel.
PRoot translates filesystem and process operations in userspace. That makes it convenient, but it does not create the isolation boundary associated with a container runtime. The application still shares Android’s kernel, network namespace, and Termux user identity. For modest web services, the source reports that this approach worked. The browser workload was different because launching processes, loading libraries, reading profiles, and moving capture data repeatedly crossed the translation layer.
The eventual design rooted the phone and entered the same Debian filesystems through chroot (a Unix facility that changes the apparent root directory for a process). Native system calls removed PRoot from the hot path. Runit still controlled lifecycle from Termux, and application data stayed separate from replaceable runtime files.
The deployment model is notably restrained. A workstation resolves each application image to an exact digest, exports its filesystem, and lets Ansible verify and install it on the handset. A small privileged helper prepares a private mount namespace, binds required paths, enters the filesystem, drops privileges, and launches the original entrypoint. Neither Docker nor a compiler has to live on the phone.
That architecture provides compatibility, not hostile-workload containment. Private mount namespaces make mounts and cleanup predictable, but every resident still trusts the shared Android kernel and network stack. Anyone adapting the idea should classify services accordingly. A personal dashboard is a different risk from accepting arbitrary third-party code.
The operations work is what makes the experiment credible
A clever boot sequence is not infrastructure until another machine can rebuild it. The source author moved versions, routes, power settings, service definitions, secrets, and checks into an Ansible-managed repository. Releases are pinned by digest or checksum, installed in versioned directories, and selected through an atomic current symbolic link.
That creates a practical release path:
- A release archive or OCI image becomes the input.
- Git records its exact checksum or digest.
- Ansible transfers verified files over SSH.
- Versioned directories preserve the previous artifact.
- Runit starts the selected release.
- Local and public checks decide whether deployment succeeded.
Rollback then means reverting a pin and applying the declared state again, rather than reconstructing a remembered sequence of shell commands. Reapplying the configuration does not replace unchanged runtime files or restart healthy services, according to the source.
Secrets receive similar separation. The phone has no checkout of the infrastructure repository. Encrypted Ansible Vault values remain on the workstation, and deployment renders only the runtime values each resident needs into Termux’s private storage. The described setup derives the vault password through a fixed challenge signed by a 1Password SSH agent, so the private key does not have to reach the handset.
Stateful data needs another lane. The finance application uses SQLite, and its database has automated off-device backups plus a tested restoration path. That detail matters more than the novelty of the hardware. Application artifacts can be rebuilt; financial records cannot. A credible phone server needs an answer for both.
Outbound tunnels make the network portable
Home internet rarely behaves like a server rack. Addresses may change, inbound ports may be blocked, and moving the handset to another connection should not require editing every client. This build avoids exposing SSH and a collection of service ports through the router.
Public HTTP traffic uses a Cloudflare Tunnel. Cloudflared establishes an outbound connection, Cloudflare maps hostnames into that tunnel, and Caddy routes each request to a loopback service. Tailscale handles private administration. Because both paths begin with outbound connections, they can reconnect when the phone changes networks.
The remote-browser service needed special handling. It terminates its own TLS (Transport Layer Security, the encryption and identity layer used by HTTPS), and an old iPad pins the server identity. At home, a DNS-only record tracks the public address while one router port reaches the service. For roaming, the author wraps the complete TLS stream inside a WebSocket so Cloudflare forwards the outer connection without terminating the authenticated inner session.
That workaround adds latency. The source reports roughly one extra network round trip and an iPad connection around 60 milliseconds during an early test. Those are observations from this build, not general performance numbers for all phones or networks. The broader lesson is that ingress should match each application’s security and latency needs rather than forcing every service through one tunnel pattern.
What deserves monitoring
A phone has server-like failure modes plus mobile-specific ones. The documented dashboard collects utilization for all eight CPU cores, memory, storage, uptime, battery state, thermal data, service discovery, and local and public reachability. It also keeps bounded history and exposes a Vue interface only on the local network or tailnet.
For a similar host, I would watch at least these signals:
- Battery and charging state. A battery is useful backup power, but heat and long-term charging deserve attention.
- Thermal readings. Browser workloads can turn a quiet handset into a throttled one.
- Storage pressure. Flash capacity disappears quickly when logs, browser profiles, and old releases accumulate.
- Supervisor status. A running Android app does not prove its resident services are healthy.
- External reachability. Loopback success cannot detect a broken tunnel, DNS record, or router path.
- Backup freshness. Stateful applications need evidence that off-device copies still work.
This list is editorial guidance based on the architecture. The source documents the dashboard signals and a tested restore path, but it does not claim a universal monitoring policy.
Trade-offs
Hardware trust is the first cost. Rooting expands the boundary that must remain secure, while chroot environments should not be mistaken for isolated containers. Do not place mutually hostile workloads on this design.
Operational familiarity is another cost. There is no normal systemd host or Docker daemon. Android updates, vendor behavior, Termux packaging, and mobile power controls can introduce failure modes that a standard Debian VPS avoids.
Performance limits remain real. The source found PRoot unsuitable for its demanding browser path and eventually switched to rooted chroots. It also tried to bridge Debian graphics to the phone’s Mali GPU through VirGL and Android Vulkan, but reported corrupt pages and worse performance than the software-rendered path.
Data durability deserves the hardest line. Flash storage in one retired handset is not a backup plan. Anything irreplaceable needs automated off-device copies and a restoration procedure that has actually been exercised.
The practical conclusion
This design makes sense when the hardware is already owned, rootable, ARM64-based, and assigned to a small collection of trusted personal services. Its value comes from the battery, quiet operation, integrated radios, and reproducible configuration, not from pretending a phone is identical to a rack server.
I would keep the scope narrow: use Android for devices, Termux for host control, verified artifacts for applications, outbound networking for portability, and separate backups for state. If those constraints feel like needless work, keep the VPS. If the monthly bill buys little more than weak shared CPU, a carefully managed spare phone is a serious alternative.