Termux PHP Server (8090) — Mobile‑ready, Autostart, LAN + Internet

One‑click setup to serve /storage/shared over localhost + LAN, and optionally via internet through Cloudflare Tunnel. Boot‑autostart, background keep‑alive, responsive UI with copy buttons.

1) Prerequisites (run once)

For stability, disable battery optimization for Termux in Android settings. A wake‑lock is used to reduce background kills.

2) One‑shot Setup Script (copy and run in Termux)

This will: update/upgrade, install PHP, set up storage, create supervised services (runit) for auto‑restart, add helper scripts, enable boot autostart, and start everything on port 8090.

#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail

SERVER_PATH="/storage/shared"
PORT="8090"
ENABLE_CLOUDFLARED="1"  # 1: also enable internet access via Cloudflare; 0: LAN/localhost only

echo "[1/9] Updating Termux packages..."
pkg update -y && pkg upgrade -y

echo "[2/9] Installing core packages..."
pkg install -y php termux-api termux-services coreutils procps openssl-tool curl wget

echo "[3/9] Enabling shared storage (grant permission if prompted)..."
termux-setup-storage || true

echo "[4/9] Preparing directories..."
PREFIX_DIR="$PREFIX"
mkdir -p "$HOME/bin" "$HOME/.termux/boot" "$HOME/.logs" "$PREFIX_DIR/var/service"

echo "[5/9] Creating runit service for PHP server..."
# Service: php-8090
mkdir -p "$PREFIX_DIR/var/service/php-${PORT}/log"
cat >"$PREFIX_DIR/var/service/php-${PORT}/run" <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
export SERVER_PATH="/storage/shared"
export PORT="8090"
exec 2>&1
cd "$SERVER_PATH" || exit 1
exec php -S 0.0.0.0:"$PORT" -t "$SERVER_PATH"
EOF
chmod +x "$PREFIX_DIR/var/service/php-${PORT}/run"

cat >"$PREFIX_DIR/var/service/php-${PORT}/log/run" <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
# Log with timestamps to ~/.logs/php-PORT
LOGDIR="$HOME/.logs/php-8090"
mkdir -p "$LOGDIR"
exec svlogd -tt "$LOGDIR"
EOF
chmod +x "$PREFIX_DIR/var/service/php-${PORT}/log/run"

echo "[6/9] Creating helper scripts..."
cat >"$HOME/bin/start-php-server.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
SERVER_PATH="$SERVER_PATH"
PORT="$PORT"
LOG="\$HOME/.php-server.log"
PIDFILE="\$HOME/.php-server.pid"
# Keep CPU awake
command -v termux-wake-lock >/dev/null 2>&1 && termux-wake-lock || true

if command -v sv >/dev/null 2>&1 && [ -d "$PREFIX_DIR/var/service/php-\${PORT}" ]; then
  sv up "php-\${PORT}" || true
else
  # Fallback: unmanaged background
  if [ -f "\$PIDFILE" ] && kill -0 "\$(cat "\$PIDFILE")" 2>/dev/null; then
    kill "\$(cat "\$PIDFILE")" || true
    sleep 1
  fi
  pkill -f "php -S 0.0.0.0:\${PORT}" 2>/dev/null || true
  cd "\$SERVER_PATH"
  nohup php -S 0.0.0.0:"\$PORT" -t "\$SERVER_PATH" >> "\$LOG" 2>&1 &
  echo \$! > "\$PIDFILE"
fi

IP=\$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++){if(\$i=="src"){print \$(i+1); exit}}}')
: "\${IP:=127.0.0.1}"
{
  echo "Local:  http://127.0.0.1:\${PORT}"
  echo "LAN:    http://\${IP}:\${PORT}"
} | tee "\$HOME/.php-server.urls"
echo "PHP server is up."
EOF
chmod +x "$HOME/bin/start-php-server.sh"

cat >"$HOME/bin/stop-php-server.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
PORT="$PORT"
PIDFILE="\$HOME/.php-server.pid"
if command -v sv >/dev/null 2>&1 && [ -d "$PREFIX_DIR/var/service/php-\${PORT}" ]; then
  sv down "php-\${PORT}" || true
else
  if [ -f "\$PIDFILE" ] && kill -0 "\$(cat "\$PIDFILE")" 2>/dev/null; then
    kill "\$(cat "\$PIDFILE")" || true
    rm -f "\$PIDFILE"
  fi
  pkill -f "php -S 0.0.0.0:\${PORT}" 2>/dev/null || true
fi
echo "PHP server stopped."
EOF
chmod +x "$HOME/bin/stop-php-server.sh"

# Optional Cloudflare tunnel service and helpers
if [ "$ENABLE_CLOUDFLARED" = "1" ]; then
  echo "[7/9] Installing Cloudflared (optional for public URL)..."
  if ! pkg install -y cloudflared; then
    echo "Cloudflared package not available; internet tunnel will be disabled."
    ENABLE_CLOUDFLARED="0"
  fi
fi

if [ "$ENABLE_CLOUDFLARED" = "1" ] && command -v cloudflared >/dev/null 2>&1; then
  echo "Creating runit service for Cloudflared..."
  mkdir -p "$PREFIX_DIR/var/service/cf-${PORT}/log"
  cat >"$PREFIX_DIR/var/service/cf-${PORT}/run" <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
PORT="8090"
exec 2>&1
exec cloudflared tunnel --no-autoupdate --url "http://127.0.0.1:${PORT}"
EOF
  chmod +x "$PREFIX_DIR/var/service/cf-${PORT}/run"

  cat >"$PREFIX_DIR/var/service/cf-${PORT}/log/run" <<'EOF'
#!/data/data/com.termux/files/usr/bin/sh
LOGDIR="$HOME/.logs/cf-8090"
mkdir -p "$LOGDIR"
exec svlogd -tt "$LOGDIR"
EOF
  chmod +x "$PREFIX_DIR/var/service/cf-${PORT}/log/run"
fi

cat >"$HOME/bin/start-cloudflared.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
PORT="$PORT"
LOG="\$HOME/.cloudflared.log"
PIDFILE="\$HOME/.cloudflared.pid"
if ! command -v cloudflared >/dev/null 2>&1; then
  echo "cloudflared is not installed."
  exit 0
fi
if command -v sv >/dev/null 2>&1 && [ -d "$PREFIX_DIR/var/service/cf-\${PORT}" ]; then
  sv up "cf-\${PORT}" || true
  sleep 3
  # Try to extract latest URL from runit log
  LATEST_LOG=\$(ls -1t "\$HOME/.logs/cf-\${PORT}/" 2>/dev/null | head -n1 || true)
  if [ -n "\$LATEST_LOG" ]; then
    PUB=\$(grep -aoE 'https://[a-zA-Z0-9.-]+trycloudflare\.com' "\$HOME/.logs/cf-\${PORT}/\$LATEST_LOG" | tail -n1 || true)
  fi
else
  # Fallback unmanaged background
  if [ -f "\$PIDFILE" ] && kill -0 "\$(cat "\$PIDFILE")" 2>/dev/null; then
    kill "\$(cat "\$PIDFILE")" || true
    sleep 1
  fi
  pkill -f "cloudflared tunnel --url http://127.0.0.1:\${PORT}" 2>/dev/null || true
  nohup cloudflared tunnel --no-autoupdate --url "http://127.0.0.1:\${PORT}" >> "\$LOG" 2>&1 &
  echo \$! > "\$PIDFILE"
  sleep 3
  PUB=\$(grep -oE 'https://[a-zA-Z0-9.-]+trycloudflare\.com' "\$LOG" | tail -n1 || true)
fi

if [ -n "\${PUB:-}" ]; then
  echo "Public: \${PUB}" | tee -a "\$HOME/.php-server.urls"
  echo "Cloudflared public URL: \${PUB}"
else
  echo "Cloudflared started. Check logs for the public URL."
fi
EOF
chmod +x "$HOME/bin/start-cloudflared.sh"

cat >"$HOME/bin/stop-cloudflared.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
set -euo pipefail
PORT="$PORT"
PIDFILE="\$HOME/.cloudflared.pid"
if command -v sv >/dev/null 2>&1 && [ -d "$PREFIX_DIR/var/service/cf-\${PORT}" ]; then
  sv down "cf-\${PORT}" || true
else
  if [ -f "\$PIDFILE" ] && kill -0 "\$(cat "\$PIDFILE")" 2>/dev/null; then
    kill "\$(cat "\$PIDFILE")" || true
    rm -f "\$PIDFILE"
  fi
  pkill -f "cloudflared tunnel --url http://127.0.0.1:\${PORT}" 2>/dev/null || true
fi
echo "Cloudflared stopped."
EOF
chmod +x "$HOME/bin/stop-cloudflared.sh"

echo "[8/9] Creating boot autostart script (requires Termux:Boot)..."
cat >"$HOME/.termux/boot/00-start-php-at-boot.sh" <<EOF
#!/data/data/com.termux/files/usr/bin/bash
# Runs on device boot (after unlock) via Termux:Boot
export PATH="\$HOME/bin:\$PATH"
ENABLE_CLOUDFLARED="$ENABLE_CLOUDFLARED"
# Keep CPU awake to reduce background kills
command -v termux-wake-lock >/dev/null 2>&1 && termux-wake-lock || true

if command -v sv >/dev/null 2>&1; then
  sv up "php-$PORT" || true
  if [ "\$ENABLE_CLOUDFLARED" = "1" ] && command -v cloudflared >/dev/null 2>&1 && [ -d "$PREFIX_DIR/var/service/cf-$PORT" ]; then
    sv up "cf-$PORT" || true
  fi
else
  "\$HOME/bin/start-php-server.sh"
  if [ "\$ENABLE_CLOUDFLARED" = "1" ] && command -v cloudflared >/dev/null 2>&1; then
    "\$HOME/bin/start-cloudflared.sh"
  fi
fi
EOF
chmod +x "$HOME/.termux/boot/00-start-php-at-boot.sh"

echo "[9/9] Starting services now..."
"$HOME/bin/start-php-server.sh"
if [ "${ENABLE_CLOUDFLARED}" = "1" ] && command -v cloudflared >/dev/null 2>&1; then
  "$HOME/bin/start-cloudflared.sh" || true
fi

LAN_IP=$(ip route get 1.1.1.1 2>/dev/null | awk '{for(i=1;i<=NF;i++){if($i=="src"){print $(i+1); exit}}}')
echo
echo "All set!"
echo "Localhost:  http://127.0.0.1:${PORT}"
echo "On LAN:     http://${LAN_IP:-<your_LAN_IP>}:${PORT}"
echo "Public:     See ~/.logs/cf-${PORT}/ or ~/.cloudflared.log (if enabled) for the trycloudflare.com URL."
echo "Autostart:  ~/.termux/boot/00-start-php-at-boot.sh (Termux:Boot required)."
echo "Root path:  ${SERVER_PATH} (directory is listed if no index.php/index.html)."

Server Root: /storage/shared

Port: 8090

3) Quick controls

$HOME/bin/start-php-server.sh
# Optional: public URL (https://*.trycloudflare.com)
$HOME/bin/start-cloudflared.sh
$HOME/bin/stop-php-server.sh
$HOME/bin/stop-cloudflared.sh

4) Status and logs

# Show saved URLs
cat ~/.php-server.urls 2>/dev/null || echo "No URL file yet."

# Tail PHP logs (runit)
tail -f ~/.logs/php-8090/current

# Tail Cloudflared logs (if enabled and supervised)
tail -f ~/.logs/cf-8090/current

# Fallback unmanaged logs
tail -f ~/.php-server.log ~/.cloudflared.log 2>/dev/null

# Check processes
ps -A | grep -E 'php -S|cloudflared' | grep -v grep

Directory listing is automatic if there is no index.php or index.html in a folder, including the server root.

5) Change port or path

Defaults: /storage/shared, port 8090. To change:

6) Uninstall / disable

# Stop services
$HOME/bin/stop-cloudflared.sh 2>/dev/null || true
$HOME/bin/stop-php-server.sh 2>/dev/null || true
# Remove runit services
rm -rf "$PREFIX/var/service/php-8090" "$PREFIX/var/service/cf-8090"
# Remove boot autostart
rm -f "$HOME/.termux/boot/00-start-php-at-boot.sh"
# Remove helper scripts
rm -f "$HOME/bin/start-php-server.sh" "$HOME/bin/stop-php-server.sh" \
      "$HOME/bin/start-cloudflared.sh" "$HOME/bin/stop-cloudflared.sh"
echo "Removed services and scripts. Packages remain installed."

Tips