Self Hosting to the Xtreme | Server on Mobile?!
How I got a server to run on Android without rooting it.
Why?
Three words — Reducing Server Cost. Recently, I wrote a telegram bot which sends jokes every hour. It does so by fetching them from the r/Jokes
subreddit RSS feed. This bot is hilariously called chutkulabot, where chutkula means joke in Hindi. The inspiration was the boring atrocities of the isolative repetition during the COVID-19 lockdown.
Now as we know, telegram bot servers are very lightweight (especially for this utility). Initially I had deployed the bot to heroku but the problem was that after half an hour of inactivity, the dynos go to sleep, so running an hourly cron was impossible unless I used a service like kaffeine, which makes sure your dynos are always active by sending regular requests. The problem here was that you only get a 1000 free dyno hours a month in the heroku free tier, and frankly the hobby cluster was overkill. I had to think of a more minimal way to host the bot.
How the Bot Works
The bot is written in go. It is a simple server which listens to telegram messages and macros directed towards it and responds accordingly. Users can subscribe to the jokes and once they do, their timestamp is noted. Then the bot fetches the jokes RSS feed hourly, looks for chats which have an out of date timestamp and sends them the latest jokes to consume. You can take a look at the source repository to understand more about some of the cool functionalities that it has.
So the bot has some of the following things:
- The Feed Parser, which is responsible for fetching and formatting the RSS feed.
- The Transit Layer, which is our bot backend along with a series of interfaces responsible for sending and receiving messages.
- The database, MongoDB in this case, used for storing and fetching chat timestamps in order to keep the feed in sync with the requested chat.
How I got it to work on Android
Let us dive deeper to see what it takes to run a server on android.
The Environment
What do you need when you begin with a particular deployment?
Give me a terminal and an internet connection and I can conquer the world.
Android has an application called termux, which can be used to open a shell to your system. Keep in mind, the mobile phone that you have in your hand runs the linux kernel, so you can of course use all of your favourite linux apps.
Now writing commands using just your mobile phone is hard, but you can ssh into your phone! Just run the following command:
# use the pkg package manager to install openssh
pkg install openssh# start the ssh daemon
sshd
Make sure that your laptop and your phone are connected to the same network. To ssh into your mobile, we need the following details:
- Your local IP address
- Your username. Keep in mind that termux does not give you root acccess on your phone, it creates a user for you and gives you a
$HOME
folder to work with. - The port your ssh daemon is running on. Since you don’t have root access then it won’t be the default port (that is 53), but rather another port which openssh will run on. Usually this port is 8022.
# to get the IP address
ip addr | grep 192# to get the username
uname -a# create a password for this username
passwd <output of the previous command>
You will get a local IP address (for example: 192.168.0.10). This is the internal IP of your mobile phone which can be used to connect with your mobile using ssh. Now head over to the terminal on your laptop and ssh into your phone:
# ssh using your username and local ip on port 8022
ssh <username>@<ipaddress> -p 8022
If everything goes well then you will be inside your mobile phone, using the comfortable terminal of your laptop and now you can really work with it without squinting on your small touch keyboard. A recommend installing tmux on your termux as well, so that you can attach and detach to the running session of your server.
The Compilation Process
A lot of you might have compiled code before. In C and C++ you can use the GNU compilers or clang. Go has its own compilation mechanism. If you want to know how it works, check out this amazing article. Go binaries are self contained, which means that if you have a static go binary, you don’t need the project dependency source code to run it. Build once and ship it anywhere.
The go build command offers two environment variables to define the OS and architecture to build for (GOOS and GOARCH). To find the OS and architecture for your mobile phone, you can run the following on termux:
dpkg --print-architecture
This command will print out the architecture which your mobile uses, which is very important for making the binary for your platform. Some architectures include x86
, arm
, aarch64
which is just a 64 bit variant for ARM (also known as arm64
. My mobile uses aarch64 architecture so I needed to cross compile for that. The OS is of course linux
for my mobile. Although android
is also a valid environment variable for the go build command.
We need the Android NDK for cross compilation. It is essentially a toolkit that helps you with native android support for C and C++. You can build a toolchain for go as well, by following these steps on your development machine:
- Download the NDK toolchain from here, and place it in the
/dev
folder and run the following command for whichever Android version you have to make your platform NDK.
export NDK_ROOT=~/dev/ndk-toolchain
./android-ndk-r10c/build/tools/make-standalone-toolchain.sh --platform=android-30 --install-dir=$NDK_ROOT
- Compile your go program using this NDK toolchain.
CC=~/dev/ndk-toolchain/bin/aarch64-linux-android30-clang \GO111MODULES=on \GOOS=android \GOARCH=arm64 \GOARM=7 \CGO_ENABLED=1 \go build -v -o ./bin/chutkulabot-android -x .
Notice that in the CC environment variable for the go build command, I have specified which compiler to use for the target binary that I want. Out of all of the compilation toolkits, I selected the ARM 64 bit clang compiler, which fits my architecture. I mentioned my OS as android and my architecture as arm64
, and this successfully builds the binary I want.
Now that I have my binary, I can make a release on GitHub with this binary added to the resources. The only reason I did this was so I could get the updated binary to my mobile device on-the-go using wget.
Actually Running the Binary
This is the easy part. Now the server always remains alive and shows a lot of logs. I wanted to be up to date with these logs without having to daemonize everything, so I decided to use tmux which SSH’ed into my mobile:
# Install tmux
pkg install tmux# Create a new tmux session
tmux new -s mysession
I then gained access to the tmux shell. The next steps involved getting the binary and simply executing it. I used wget to download the binary from the GitHub release, but you can use curl as well:
# install wget
pkg install wget# download the binary
wget <binary URL># running the binary
./chutkulabot-android
And voila. The bot started running on my mobile phone. It even got connected to MongoDB. When not quite. One of the problems I faced was that if I used a MongoDB URI of the form mongodb+srv
, it simply refused to connect to the database, but if I removed the +srv
part, it started working like a charm. I am yet to figure out why this happened, but I have created an issue on the project repository if you guys want to take a look at it.
Now that the bot is running, I can simply detach from the tmux session by pressing Ctrl + b + d
. and exit out of my SSH session. Now you can open the termux app on your phone and attach to the session to see the logs:
tmux a -t mysession
I always leave termux open in the background and connected to the internet. Both of these are not an issue for me because firstly termux is a very lightweight application (considering soydevs already have hundereds of background processes running on their mobile devices) and secondly because I always stay connected to the internet anyway.
Conclusion
Mobile devices have evolved to the point there they have more resources than they actually need. My mobile phone (which is a OnePlus 5T) has 8 GB of RAM, and I don’t even play games like PUBG where I am actually using it. You can deploy simple workloads on your mobile itself. No need to pay for hosting. It is time that people actually notice what kind of power they have in their hands with their mobile phones and start intelligent resource utilization for their workloads.
Now before you call me crazy, I do not recommend hosting very important or critical workloads on a mobile phone. This blog just serves to be an insight of what we can do if we want to. Paying for VPS or cloud services is not bad. It is the backbone of the data industry these days. You just gotta pick your battles and decide when you want to go for a self hosted system rather than a public VPS.