Secure webcam streaming with mjpg-streamer and stunnel 2

Last week I was trying to understand how to establish a secure connection with a webcam streaming server. The idea was to setup a kind of small homemade surveillance system to be used when I’m away.

I knew of mjpg-streamer and I used it years ago, but I’ve never tried to encrypt the communication channel before, so I thought it was time to go a step further.

After a quick search I found that several people talk well about stunnel, a proxy which provides TLS encryption for both client and server.

The combination of these two tools allowed me to reach my goal and now I will briefly show you a step-by-step guide to configure all the needed.

Server-side configuration

For the server side I used an old pc equipped with a full clean installation of Slackware64, at which I connected a Trust Spotlight USB webcam.

Let’s start by installing the mjpg-streamer and noip2 packages. This operation can be accomplished by using sbotools (as root):

# sboinstall mjpg-streamer noip2

The first one provides the video streaming service, the second one allows the server to be visible from outside the local network.

No-IP client setup

In order to use the No-IP service you’ve to register a free account. Once you have it, sign in, add a new host name and then logout.

Now we configure our server via noip2 (as root):

root@darkstar:/home/cristiano# noip2 -C

Auto configuration for Linux client of no-ip.com.

Please enter the login/email string for no-ip.com myusername
Please enter the password for user 'myusername' ********

Only one host [myserver.ddns.net] is registered to this account.
It will be used.
Please enter an update interval:[30]
Do you wish to run something at successful update?[N] (y/N) n

New configuration file '/usr/local/etc/no-ip2.conf' created.

Ok, the job is done. The last thing to do is to launch noip2 (as root):

# noip2

You can easily check that noip2 is running in background by using the command ps -A | grep noip2

Create the cerificates using OpenSSL

We want to create a self-signed certificate valid for two years. We can do this using OpenSSL:

mkdir stunnel && cd stunnel
openssl req -x509 -sha256 -nodes -days 730 -newkey rsa:2048 -keyout key.pem -out cert.pem

The last command requires a certain number of fields to be filled with some informations. Feel free to enter what you prefer except for the field Common Name which must be filled with myserver.ddns.net.

At the end of the procedure you will find two files called key.pem and cert.pem in the current directory.

Stunnel

Let’s create a configuration file called stunnel.conf with the following content:

key = key.pem
cert = cert.pem
client = no
debug = 7
verify = 2
CAfile = cert.pem
sslVersion = all

[mjpg-streamer]
accept = 4567
connect = 192.168.1.50:8000

The parameter verify = 2 tells stunnel to require and verifiy the certificate. A detailed explanation can be found here.

Now we can start stunnel (as root):

# stunnel stunnel.conf

Also in this case we can check that stunnel is running with ps -A | grep stunnel

Mjpg-streamer

We can launch the streaming service with the following command (as user):

mjpg_streamer -i "input_uvc.so -d /dev/video0 -n -q 80 -y -f 15 -r 640x480" -o "output_http.so -p 8000 -w /var/mjpg-www -c myuser:mypass"

For the input_uvc.so plugin we have the following parameters:

  • -d <device>: the video device to use (/dev/video0 in this case)
  • -n: don’t initialize dynamic controls of Linux-UVC driver
  • -q <quality>: the quality of the JPG compression to use (-q 80)
  • -y: use this if your camera doesn’t support MJPG, pictures will be captured in YUVY
  • -f <framerate>: the framerate in frames per second (-f 15)
  • -r <resolution>: the resolution (-r 640×480)

For the output_http.so plugin the parameters used are:

  • -p <port>: the port at which the service is available (-p 8000)
  • -w <path>: folder that contains webpages in flat hierarchy (no subfolders) (-w /var/mjpg-www)
  • -c <credentials>: protect the access with username and password (-c myuser:mypass)

When launched, mjpg-streamer should show you an output like this one below:

MJPG Streamer Version: svn rev: Unversioned directory
i: Using V4L2 device.: /dev/video0
i: Desired Resolution: 640 x 480
i: Frames Per Second.: 15
i: Format............: YUYV
i: JPEG Quality......: 80
i: TV-Norm...........: DEFAULT
o: www-folder-path...: /var/mjpg-www/
o: HTTP TCP port.....: 8000
o: username:password.: myuser:mypass
o: commands..........: enabled

And if you point your web browser to the local IP address of the server (i.e. 192.168.1.50:8000), you should see mjpg-streamer in action ;-)

Final remarks

What we have done until now is valid for a Slackware machine, but what if we want to use an embedded platform like the Raspberry Pi instead?

The steps to do are almost the same, but there are some small details we have to bear in mind.

First of all, here you can find the instructions to install the No-IP client on the Raspberry Pi.

To install stunnel, just do:

sudo apt-get install stunnel4

Regarding mjpg-streamer, the instructions to install it are listed here below:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git cmake libjpeg8-dev
git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
mkdir build && cd build
cmake ..
make
sudo make install
cd ..

To launch the video streaming service, just do the following:

export LD_LIBRARY_PATH=.
mjpg_streamer -o "output_http.so -w ./www -p 8000 -c myuser:mypass" -i "input_raspicam.so -quality 80 -fps 15 -r 640x480"

Just a note: here I used a Raspberry Pi 1 model B with the Raspberry Pi Camera v1.3, but I think you can certainly obtain better performances by using a more recent model, for example the Raspberry Pi 3.

Router configuration

In order to be able to communicate from outside your home network, you need to enable the port forwarding.

Depending on the router model, an appropriate configuration may be the following:

  • Service name: mjpg-streamer (choose the name you like)
  • External port: 4567 [TCP]
  • Internal port: 4567 [TCP]
  • Internal IP address: 192.168.1.50 (the server)

Client-side configuration

Now we consider the client-side configuration by analyzing two different cases.

Slackware (on the laptop)

In this case I used my laptop with Slackware64. I have installed stunnel, as explained above, and then I have configured it as shown here below:

key = key.pem
cert = cert.pem
client = yes
debug = 7
sslVersion = all

[mjpg-streamer]
accept = 127.0.0.1:8081
connect = myserver.ddns.net:4567

key.pem and cert.pem must be the same of those stored on the server.

We can launch stunnel (as root):

 
# stunnel stunnel.conf

And then we can point the web browser to 127.0.0.1:8081 to see the video flow!

Android (on the smartphone)

But in most cases, when you’re around, you don’t have your laptop with you. It’s more likely you bring with you a smartphone with an internet connection.

Here below I explain you with a short video how you can access your webcam using a smartphone.

You need to install Termux from the Google Play Store before to try it.

Ok, that’s all for now :-)

As usual, remarks and suggestions are welcome!

Did you like this post? Share it!
Share on email
Email
Share on twitter
Twitter
Share on facebook
Facebook
Share on linkedin
Linkedin
Share on print
Print

2 thoughts on “Secure webcam streaming with mjpg-streamer and stunnel

  1. Reply Alihan Sep 18,2019 05:29

    hi,

    thank you detailed explanations!

    How can we secure credentials transfering through url name?

    Is it true that creds snooping is possible by capturing http packets or dns queries?

    • Reply Cristiano Sep 18,2019 09:16

      Hi Alihan,
      thank you for your comment.
      As far as I know, HTTP packets without any protection are obviously traceable, but when you use stunnel the entire HTTP traffic should be obfuscated.
      Someone trying to inspect the HTTP traffic will not recognize anything!

Leave a Reply