This is Part 2. Part 1 is here.
In the first part a HD stream was created from the raspberry pi, turned into RTMP with ffmpeg, and then published and consumed through nginx. In this part I'll add an external host that can proxy this stream to the outside world. It prevents any connections to this stream to my home internet connection.
We need a couple of things:
Once it starts it'll create that tunnel so the external host can proxy though to the raspberry pi. If the connection ever drops it'll restart, and if nginx ever restarts it'll make sure the tunnel is restarted also.
And that's it. There is some improvement to be made around caching so when two or more viewers are watching the stream only one *.ts file is transferred, for now though keep it simple.
In the first part a HD stream was created from the raspberry pi, turned into RTMP with ffmpeg, and then published and consumed through nginx. In this part I'll add an external host that can proxy this stream to the outside world. It prevents any connections to this stream to my home internet connection.
We need a couple of things:
- An external host that you can ssh into with a public key from the raspberry pi.
- An nginx instance running on your external ssh host
Next we need to create a couple of things which is what I'll cover below:
- Script on the external host which will keep the SSH connection alive
- Systemd unit that will restart the ssh tunnel if dropped
- Nginx config to use the SSH tunnel to connect to the nginx instance running on the raspberry pi.
So why do it this way? There's one thing I didn't want - When no one is viewing the stream I do not want the stream to consume my home internet upload bandwidth. If I wasn't concerned with this I'd just publish to an S3 bucket instead.
Keep Alive script
This short script will keep some random traffic flowing over the tty part of the SSH connection alive so that the port mapped connection stays up.
For this I'm using a script I've used in other places that just outputs a random set of words every few seconds to keep the connection up. If I don't do this the ssh connection will drop the connection after a timeout when the terminal has had no traffic, if it does drop the connection will re-establish thanks to systemd.
This is the contents of ${HOME}/keepalive.sh on the external host:
DICT=/usr/share/dict/words RANGE=$(wc -l ${DICT} | cut -d\ -f1) while true; do sleep 5 number=$(awk 'BEGIN{srand();print int(rand()*'${RANGE}')}') # or shuf, or jot, but awk is everywhere let "number %= $RANGE" sed ${number}'!d' $DICT done
It's pretty simple, but the logic is:
- Get the number of words in the dictionary file on the local system
- Wait for 5 seconds
- Using awk, get a random number up to number of lines in the dictionary
- Display that word
- Go to step 2.
SSH Tunnel Systemd Unit
This one is also pretty simple, it belongs on the raspberry pi running the webcam. This service will:
- Wait for nginx to start
- Open a ssh connection to the external host
- Create a tunnel over that ssh connection from the local nginx server to a port on the external host that the external nginx host can proxy to.
- Start the keepalive.sh script above
You need to create a file called /etc/systemd/system/sshtunnel.service with this contents (remember to update the ssh line with your external user and host name):
[Unit] Description=sshtunnel After=nginx.service After=systemd-user-sessions.service After=rc-local.service Before=getty.target [Service] ExecStart=/usr/bin/ssh externaluser@externalproxyhostname -R 8080:127.0.0.1:80 /home/dime/keepalive.sh Type=simple Restart=always RestartSec=5 StartLimitIntervalSec=0 User=pi Group=pi [Install] WantedBy=multi-user.targetOnce the config is in place you need to enable it with:
systemctl enable sshtunnel
Once it starts it'll create that tunnel so the external host can proxy though to the raspberry pi. If the connection ever drops it'll restart, and if nginx ever restarts it'll make sure the tunnel is restarted also.
Nginx configuration for the external host
Assuming you might have an existing nginx setup externally, you'll need to add a section like this to your existing nginx conf:server { # in any existing server config # Streaming webcam location location /window/ { proxy_pass http://127.0.0.1:8080/; } }
And that's it. There is some improvement to be made around caching so when two or more viewers are watching the stream only one *.ts file is transferred, for now though keep it simple.
Starting
Once it's all in place you need to `systemctl restart nginx` on the raspberry pi webcam, this will:
- Restart nginx
- Restart the webcam stream
- Start the sshtunnel service
If all goes to plan you should now be able to access your webcam via your external proxy at
http://externalproxyhostname/webcam/