Set Up a Local HTTPS Reverse Proxy on Android with Termux and Caddy

13 min read Learn step‑by‑step how to run a local HTTPS reverse proxy on any Android device using Termux and the Caddy web server – no root required, with full configuration and troubleshooting guidance. October 13, 2026 12:30 How to Set Up a Local HTTPS Reverse Proxy on Android with Termux and Caddy

Before you start

Running a reverse proxy on Android does not need root, but you do need a few basics in place:

  • A device running Android 7.0 (Nougat) or newer – older versions may lack the required TLS libraries.
  • At least 200 MB of free internal storage for Termux and the Caddy binary.
  • Wi‑Fi connection (cellular data works but you’ll need a stable local network for testing).
  • Google Play access or the F‑Droid repository to install Termux.
  • USB debugging enabled only if you plan to pull logs with adb logcat – not required for the core steps.
Warning: The proxy will listen on a port that is reachable from other devices on the same Wi‑Fi network. Do not expose it to the public internet unless you understand the security implications.

What a reverse proxy does and why HTTPS matters

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:

  • Running a local development server (Node.js, Flask, etc.) and accessing it securely from other devices.
  • Exposing a home‑automation API without opening ports on your router.
  • Testing apps that require HTTPS endpoints while you only have HTTP services.

Step 1 – Install Termux and update its package repository

  1. Open the Google Play Store (or F‑Droid) and install Termux.
  2. Launch Termux. The first run will download its minimal Linux environment.
  3. Update the package list and upgrade existing packages:
    pkg update && pkg upgrade -y
  4. Install a few helper utilities that Caddy will need later:
    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.

Step 2 – Download and install the Caddy binary

  1. Determine your device’s CPU architecture. Most modern phones use arm64, but some older devices are arm (32‑bit). Run:
    uname -m
    The output will be aarch64 (arm64) or armv7l (arm).
  2. Visit the official Caddy download page from the terminal and fetch the matching zip file. Replace 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.)
  3. Extract the binary:
    tar -xzf caddy.tar.gz caddy
  4. Make the binary executable and move it to a directory that Termux includes in $PATH:
    chmod +x caddy
    mv caddy $PREFIX/bin/
  5. Verify the installation:
    caddy version
    You should see something like v2.8.4.

Step 3 – Create a self‑signed TLS certificate (or use Let’s Encrypt)

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.

  1. Create a directory to store the cert and key:
    mkdir -p ~/caddy/certs
  2. Generate a private key (2048‑bit is sufficient for local testing):
    openssl genrsa -out ~/caddy/certs/local.key 2048
  3. Generate a certificate signing request (CSR) with a common name that matches the host you will use. For a local network you can use the device’s IP address or a custom name like myphone.local:
    openssl req -new -key ~/caddy/certs/local.key -out ~/caddy/certs/local.csr -subj "/CN=myphone.local"
  4. Self‑sign the CSR for 365 days:
    openssl x509 -req -days 365 -in ~/caddy/certs/local.csr -signkey ~/caddy/certs/local.key -out ~/caddy/certs/local.crt
  5. Set restrictive permissions so other apps cannot read the private key:
    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.

Step 4 – Write a Caddyfile that defines the reverse proxy

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:8443 – the hostname and port the proxy will listen on. Change myphone.local to the name or IP you prefer.
  • tls – points Caddy to the self‑signed certificate and private key we created.
  • reverse_proxy 127.0.0.1:8080 – forwards every incoming request to a backend service running on the same device at port 8080. Replace 8080 with the actual port of your app (e.g., a local Flask server).
  • header_up lines preserve the original Host header and add the client IP, which some backends rely on for routing or logging.

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 { ... }

Step 5 – Start Caddy and keep it running in the background

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.

  1. Navigate to the folder that contains the Caddyfile:
    cd ~/caddy
  2. Launch Caddy with the custom config file:
    nohup caddy run --config Caddyfile > caddy.log 2>&1 &
  3. Detach the job so it stays alive after you exit Termux:
    disown
  4. Verify that the process is running:
    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.

Step 6 – Test the proxy from the same device

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:

  1. Find the Android device’s local IP address:
    ip addr show wlan0 | grep inet
    You’ll get something like 192.168.1.42/24.
  2. On the client device, open a browser and navigate to https://192.168.1.42:8443. Accept the security warning (or import the cert as described earlier).
  3. If you see the expected page, the reverse proxy is working.

Troubleshooting common issues

1. Caddy fails to start – “bind: address already in use”

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.

2. Browser shows “Your connection is not private” and refuses to load

Because the certificate is self‑signed, browsers block it by default. You have two options:

  • Manually add an exception (click “Advanced” → “Proceed to site”).
  • Import the local.crt into Android’s trusted credentials: Settings → Security → Encryption & credentials → Install from storage.

3. Requests are reaching the proxy but not the backend service

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.

4. “curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL”

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.

5. Proxy works locally but other devices cannot connect

  • Check that the Android Wi‑Fi network is not set to “AP Isolation” – some routers block inter‑device communication.
  • Make sure the Android device’s firewall (if any) allows inbound traffic on the chosen port. On most stock Android builds this is open by default.
  • Verify the client is using the correct IP address; DHCP can change it after a router reboot.

Advanced optional tweaks

  • Automatic certificate renewal: If you later expose the proxy to a public domain, replace the tls block with tls {}. Caddy will fetch and renew Let’s Encrypt certificates automatically.
  • Multiple backends: Add additional 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
    }
    
  • Logging: Enable access logs for debugging by adding log { output file ~/caddy/access.log } inside the site block.
  • Running as a Termux service: Install the 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.

Safety and performance considerations

  • Running a server continuously will keep the CPU awake and prevent deep sleep. Use termux-wake-lock only when you truly need the proxy to stay up while the screen is off.
  • Self‑signed certificates are fine for local testing, but never use them for production traffic that traverses the internet.
  • Because the proxy terminates TLS, the private key resides on the device. Keep the ~/caddy/certs folder private (chmod 600) and avoid sharing the directory via file managers.

Wrap‑up

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.

User Comments (0)

Add Comment
We'll never share your email with anyone else.