Offline Device-to-Device File Sharing

I was recently travelling abroad and needed to transfer a large file from my Android phone to my wife’s iPhone. Waiting in the security queue in the airport with a patchy internet connection, no computer or USB cable, I was stumped. I was sure there were plenty of shady devs on the Play Store queuing up to offer file-sharing apps crammed full of ads and other abusive behaviour or worse… but I hoped to avoid all that.

After a few minutes a thought came to me, what about running a Wi-Fi hotspot and web server on my phone for my wife’s to download from?

Enter Termux and Caddy #

Termux is a nifty Android app that provides a terminal emulator to a Linux environment where you can install APT packages as normal. It’s also available through F-Droid, which runs reproducible builds for a ton of useful FOSS apps from source.

Caddy is actually the web server running this very website. It’s an open-source web server with some very helpful automatic TLS magic, useful workflows for local development and (fairly) easy configuration.

Getting Started #

Packages in Termux are typically installed via pkg as a wrapper around apt so let’s get Caddy installed with pkg install caddy:

Screenshot of Termux installing Caddy
Screenshot of Termux installing Caddy

â„šī¸ Warning

Before proceeding turn on airplane mode, then re-enable your Wifi hotspot with a secure password. Otherwise you’ll potentially share these files with anyone on the same network as you.

Without root, Termux does have some limitations as to what it can access on your phone and these became more restrictive with Android 11 (useful docs here). If that’s TL;DR, run termux-setup-storage and you should be prompted for the permissions needed to give Termux access to read files in your Downloads folder (you can obviously share files from other places but that was all I needed).

We can then launch Caddy. In a proper production setting, we’d create a config file or use the admin API for Caddy but for this scenario (I was getting closer to the front of the queue!) it was sufficient just to use the file-server CLI option.

caddy file-server `
  --root ./storage/downloads `
  --listen :8080 `
  --browse

But wait! Don’t blindly copy paste commands from the internet! Let’s check what this does and understand it:

  • caddy: the Caddy server executable,
  • file-server: spins up a simple but production-ready static file server,
  • --root ./storage/downloads: tells Caddy which directory to serve to clients,
  • --listen :8080: the default port 80 is reserved and not usable without root access so we’ll use 8080 instead,
  • --browse: enable directory listing to show all the files available (if no index file is present)

If you’re trying to troubleshoot the setup, the --access-log option is also handy to output any requests coming in.

So let’s fire up the hotspot, connect the iPhone to it and see what we get. First we’ll need to know the IP address of the Android phone. I’m sure it’s simple to find the gateway IP from the iPhone but I chose to do it from the Android and ran into another interesting limitation. Normally I’d use ip addr but that gives a permission error. Instead the older ifconfig tool can give partial information (with a warning). There was further discussion in termux/termux-app#2993.

Termux screenshot of ip addr and ifconfig output with permission errors
Termux ip addr and ifconfig output with permission errors

Once we’ve got the IP, we can browse to it from Safari on the iPhone, for example, http://192.168.178.21:8080/ (replacing the IP address with the one we found above) and download away!

Screenshot of Caddy’’s file server browser

Tidy Up #

Turn it off when you’re done, this isn’t secure.

Seriously, you’re sharing your downloads folder with any devices on the same network as you 🙅. Only use it with the trusted devices on your password-protected hotspot.

To terminate the Caddy server, just hit the CTRL button and then type C.

Abort key sequence to shutdown Caddy within Termux
Abort key sequence to shutdown Caddy within Termux

Future Explorations #

If you’re running Tailscale, Caddy can get HTTPS certificates from the local Tailscale daemon so this setup can work securely across devices on different networks. Something like this worked for me from a Linux desktop environment but I’ve not explored it on Android:

caddy file-server `
  --root ./ `
  --domain machine-name.domain-alias.ts.net `
  --browse

Perhaps even cooler (if you want to go deeper into Tailscale’s ecosystem) is Taildrive, an alpha feature letting you create a WebDAV file server that can be accessed from another client. Bonus here is that it will presumably allow a client to read and write (Caddy file-server is read-only).