Perhaps spurred on by my previous post, I recently got some questions regarding streaming video. Even a half-jokingly made request to write a blog post on the subject. I guess this sets a dangerous precedent, but my interest in the subject is piqued beyond return,
The subject of this particular request was, How do you stream a rtsp video feed over a 4G connection so that it is accessible on the big-boy internet? This question can be abstracted a little bit into “How do I access web services hosted through a 4G dongle device?” I won’t comment on whether this is a good idea or not. For now let’s delve into it out of academic interest.
So, what is the problem ?
Prima facie, this seems trivial. I mean there are hundreds of apps which basically do this already. The simplicity of these options might explain why it is difficult to find instructions on how to achieve similar results without using a service or app.
The first idea for anyone versed in self-hosting is to just forward the ports used by the stream and access the stream from any browser with the public IP. If your service provider doesn’t give you a static public ip, you can use a service like DuckDNS or No-IP to have a permanent address. This simple approach does seem possible depending on your service provider. It requires configuring the APN settings according to your ISP instructions and forwarding the ports à la old school. In case you are using an android phone as the 4G modem / router, it seems it needs to be rooted to enable ip-forward.
With some service providers / packages, things start to escalate. The factor that may complicate 4G-hosting is network address translations (NAT) or more specifically carrier-grade NAT (CGN) Basically, the ISP executes its own NAT and a single public IPv4 address is used for several devices (addressed with the WAN IPs distributed by the ISP). You are basically behind a router controlled by the ISP. What this network-mumbo-jumbo means is that your WAN IP isn’t accessible from the internet. This renders you unable to host services by just port forwarding. There some more discussion on this topic on the element14 forum and the same train of thought is also described here. We can however circumvent the port forwarding issue entirely. There are two common methods for this: VPN or tunneling.
The first option is based on Virtual Private networks (VPN). This wonderful technology allows you to create your own little Internet-accessible network playgrounds. You can even use something like PiVPN as your VPN server for maximum Pi-ness. Naturally, you need to be able to perform port forwarding where the Pi is hooked up for this option. Instead of pi-ing it out completely, I would recommend setting OpenVPN up on a VPS running e.g. Debian since it should be faster. The popular way to configure OpenVPN these days seems to be running curled scripts. Probably not the most secure way of installing software but here you can at least read the shell scripts before sudo-running. The two most popular scripts for setting up OpenVPN seem to be Nyr’s and Angristan’s. I chose the latter for my tests.
To test this out, I tried streaming and viewing an rtsp video stream in a VPN with two separate clients (the streamer on a 4G connection and the viewer on a broadband connection). I set up a OpenVPN server on a Linode Nanode but e.g. Vultr seems to have better offerings at the moment in terms of price. I used the install script to generate two .ovpn files, one for my phone (which was playing the role of the ip-camera) and one for my laptop (where the stream was viewed). The video stream from my phone was easily set up with SpyDroid and I used OpenVPN for Android to connect to my VPN. I also used termux to find out the ip-address of the tun0 interface on my phone. After starting the stream, I connected to the VPN on my laptop and used ffplay to view the stream (you could use vlc here).
ffplay -noinfbuf 'rtsp://<TUN-IP>:<PORT_NUMBER>'
At first, I thought I would need to fiddle around with iptables and client-to-client connection configuration. To my great disappointment everything worked out of the box (YMMV). The openvpn man-page has tons of information on setting up and configuring detail. There are of course a whole slew of commercial VPN service providers touting amaze-balls privacy features. I’m not sure if they can be configured to allow client to client connections though.
Once you have a VPN server that allows client to client connections, you can connect to it with the 4G-dongle-device and any clients on the VPN can access the 4G-dongle-device. Naturally this requires that your 4G-dongle-device supports VPN. If you are using an single board computer (SBC) with a 4G dongle you should be able to connect to your VPN server using openvpn. This option is likely better if you want to access the 4G-dongle-device from anywhere instead of having it publicly available.
Although, I would recommend the VPN route in most cases, there is a second option which I alluded to earlier, tunneling. Basically you can connect to a cloud service directly and tunnel through to reveal localhost to the Internet. Without mucking about with router settings. AFAIK these tunnels are mainly used for demoing websites and things like that. Easier to set up compared to a VPN and more accessible but less robust & versatile. Technology-wise, these options are usually based on dark reverse-proxy magic.
There are a couple of options out there. A more comprehensive (though maybe a bit out-dated) list can be found here. For some cases you can even set the tunnel up without relying on third party services. The three options I have found most useful are
Ngrok and pagekite require some form of registration whereas localtunnel doesn’t require registration but offers a more limited service. I would probably recommend localtunnel for most demo-scenarios since it is just so gosh-darn easy to set up (and doesn’t require sign-up). For this post, I decided to give ngrok and pagekite a stab as well.
I registered at the ngrok website, installed it (installation method depends on your package manager) and added the authentication token per instructions. After inital set up you can start tunneling by running
ngrok http <PORTNUMBER>
You’ll get a nice command line interface displaying the status and incoming requests. The free offering seems to always dispense a new random URL. You can see them on the ngrok dashboard though, which facilitates some level of management. You can even add password authentication in the free plan. Ngrok has a bunch of paid offerings with more features including reserved domains.
Ngrok can be easily told to forward non-local servers as well. You can just run.
ngrok http <IP-TO-FORWARD>:<PORTNUMBER>
Setting up pagekite is again a matter of curling a script (python2 this time) and running it.
python2 pagekite.py <PORTNUMBER> <DOMAIN_NAME>.pagekite.me
The script prompts you to accept their terms of service as well as providing an email address. The interesting part is that you get to decide your domain name straight-away.
The pricing of pagekite is a bit more nuanced compared to ngrok. The Feeling broke? offering is only valid for non-commercial use and it has a 0.25 GB transfer quota. They also offer a free service for Free Software developers Different paid packages are available up to $256 with a $2 resolution.
If you have a good 4G modem and your ISP does not do CGN, it is possible to host directly the old-fashioned way. If that is not the case, you are left with VPNs or tunneling. Unless you are doing sporadic one-off demos, it is probably worthwhile setting up a VPN on a VPS. This requires quite a bit more configuring especially if you need the stream to be accessible via a domain name (which I didn’t cover here). From the localhost tunnel options, I would recommend localtunnel for simple stuff and ngrok when more features are necessary.