A sshd on port 22 hack for Termux on Android

I have always been somewhat skeptic, when it comes to Android. While it is based on the Linux Kernel the Userland is far from the average GNU/Linux system where geeks like me are familiar with for many years now.

I have yet to find some documentation about the way SELinux, the Linux kernel firewall and policy routing are used in Android. The only thing I know about this stuff from digging at the console so far is that they are indeed used.

This is where Termux comes into play. Termux is a console Application which features most of the familiar GNU userland utilities.

There is even an Openssh based sshd for login from a remote machine which is quite handy for console work and file-transfer (e.g. using sshfs).

Unfortunately Android uses a somewhat strange system for isolating applications from each other based on unix user-accounts. Thus, in contrast to our familiar desktop GNU/Linux systems it is not possible for a Termux shell to access data from other applications by default.

This mechanism has two major impacts on our ssh daemon:

  • it does neither make sense to select the desired user on login nor is it possible to switch users for a sshd run by the Termux user anyway
  • ssh (running with the termux userid) will be unable to bind to port 22

For both of those issues it would be nice to have a workaround. I needed to have ssh on port 22 because of a firewall limitation of the eduroam network where my phone is connected to most of the time.

To work around the second issue some kind of sudo mechanism would be needed. For a rooted phone or (even better) a free firmware like LineageOS, which I would recommend tu use, Termux provides a package called tsu which does exactly this.

Back to the sshd on port 22 hack. First I tried to enable file based capabilities (CAP_NET_BIND_SERVICE) on the sshd binary to be able to directly select 22 as the port to bind to. Unfortunately this failed to work likely because of some default SELinux settings I did not understand.

Thus I decided to go for an iptables based approach. Fortunately at least LineageOS does provide an iptables binary.

So here is my runssh script which will run sshd and redirect port 22 to port 8022 (the default Termux ssh port).


if [ "$UID" != "0" ]; then
  tsu -a -e -c $0
  exit 0

# we are supposed to be root here
# and are able to call iptables
if ! /system/bin/iptables -L PREROUTING -t nat -n |grep -q 8022; then
  echo "setting up redirect form port 22 to 8022"
  /system/bin/iptables -t nat -A PREROUTING -p tcp --dport 22 -j REDIRECT --to-port 8022