Running a reverse proxy on Android does not need root, but you do need a few basics in place:
adb logcat – not required for the core steps.A reverse proxy sits between a client (your browser or another app) and a backend service (e.g., a local web server, an API, or a Docker container running on the same phone). It forwards incoming requests, can rewrite URLs, add headers, and most importantly terminate TLS connections. By terminating TLS on the proxy you keep the backend service simple – it can run on plain HTTP while the outside world talks to the proxy over HTTPS.
On Android this pattern is useful for:
pkg update && pkg upgrade -y
pkg install wget curl tar openssl -y
Why we run pkg upgrade: Caddy depends on the latest OpenSSL libraries for modern TLS 1.3 support. Skipping this step can lead to handshake failures on newer Android versions.
arm64, but some older devices are arm (32‑bit). Run:
uname -m
The output will be aarch64 (arm64) or armv7l (arm).ARCH with arm64 or arm accordingly:
wget -O caddy.tar.gz "https://github.com/caddyserver/caddy/releases/download/v2.8.4/caddy_2.8.4_linux_$(uname -m).tar.gz"
(If the exact version link changes, you can always replace v2.8.4 with the latest stable tag – the URL pattern stays the same.)tar -xzf caddy.tar.gz caddy
$PATH:
chmod +x caddy
mv caddy $PREFIX/bin/
caddy version
You should see something like v2.8.4.Caddy can automatically obtain certificates from Let’s Encrypt, but that requires the proxy to be reachable on a public domain name. For a purely local setup we generate a self‑signed certificate and tell Caddy to trust it.
mkdir -p ~/caddy/certs
openssl genrsa -out ~/caddy/certs/local.key 2048
myphone.local:
openssl req -new -key ~/caddy/certs/local.key -out ~/caddy/certs/local.csr -subj "/CN=myphone.local"
openssl x509 -req -days 365 -in ~/caddy/certs/local.csr -signkey ~/caddy/certs/local.key -out ~/caddy/certs/local.crt
chmod 600 ~/caddy/certs/local.key
When you later browse to https://myphone.local:8443 your browser will warn about an untrusted certificate – that is expected. You can add an exception or import the local.crt into Android’s trusted credentials for a smoother experience.
Caddy uses a simple declarative configuration file called a Caddyfile. Place it in a known location, for example ~/caddy/Caddyfile:
myphone.local:8443 {
tls ~/caddy/certs/local.crt ~/caddy/certs/local.key
reverse_proxy 127.0.0.1:8080 {
header_up Host {http.request.host}
header_up X-Real-IP {http.request.remote.host}
}
}
Explanation of the directives:
myphone.local to the name or IP you prefer.8080 with the actual port of your app (e.g., a local Flask server).If you want the proxy to listen on all interfaces (so other devices on the Wi‑Fi can reach it) replace the hostname with 0.0.0.0:
0.0.0.0:8443 { ... }
Termux does not have a native systemd, but you can use termux-service or the classic nohup pattern. The simplest approach for most users is nohup combined with disown so the process survives when you close the terminal.
cd ~/caddy
nohup caddy run --config Caddyfile > caddy.log 2>&1 &
disown
ps | grep caddy
You should see a line containing /data/data/com.termux/files/usr/bin/caddy.Optional – use termux-wake-lock before starting Caddy if you plan to keep the proxy alive while the screen is off:
termux-wake-lock
When you are done, release the lock with termux-wake-unlock.
Open a terminal inside Termux and run:
curl -k https://myphone.local:8443
The -k flag tells curl to ignore the self‑signed trust chain. You should see the raw HTML or JSON that your backend service returns.
To test from another device (another Android phone, a laptop, or a tablet) on the same Wi‑Fi:
ip addr show wlan0 | grep inet
You’ll get something like 192.168.1.42/24.https://192.168.1.42:8443. Accept the security warning (or import the cert as described earlier).This means another app is already listening on port 8443. Either stop that app or choose a different port in the Caddyfile (e.g., 8444) and update the client URLs accordingly.
Because the certificate is self‑signed, browsers block it by default. You have two options:
local.crt into Android’s trusted credentials: Settings → Security → Encryption & credentials → Install from storage.Confirm that the backend is actually listening on the address you specified. Use netstat -tlnp (install the net-tools package first) to verify the port is open. Also check that the backend is bound to 127.0.0.1 or 0.0.0.0 as needed.
This typically indicates a mismatch between the TLS version supported by Caddy and the client. Ensure your client supports TLS 1.2 or newer (all modern browsers do). If you are using an older Android version, consider adding tls_protocols tls1.2 tls1.3 to the Caddyfile.
tls block with tls {}. Caddy will fetch and renew Let’s Encrypt certificates automatically.reverse_proxy blocks under the same site definition to route different path prefixes to different services.
myphone.local:8443 {
tls ~/caddy/certs/local.crt ~/caddy/certs/local.key
reverse_proxy /api/* 127.0.0.1:5000
reverse_proxy /static/* 127.0.0.1:3000
}
log {
output file ~/caddy/access.log
} inside the site block.termux-services package and create a service definition at ~/.termux/boot/caddy.service to start Caddy automatically on device boot.
[Unit]
Description=Caddy reverse proxy
[Service]
ExecStart=$PREFIX/bin/caddy run --config $HOME/caddy/Caddyfile
[Install]
WantedBy=default.target
Then enable it with termux-service enable caddy.termux-wake-lock only when you truly need the proxy to stay up while the screen is off.~/caddy/certs folder private (chmod 600) and avoid sharing the directory via file managers.By following the steps above you now have a fully functional HTTPS reverse proxy running directly on your Android phone, powered by Caddy and managed from the lightweight Termux environment. The setup works without root, respects Android’s security model, and gives you a portable gateway for any local web service you want to expose securely. If you hit a snag, revisit the troubleshooting section, double‑check the port bindings, and remember that the biggest hurdles are usually certificate trust and network isolation settings.









