Proxy for the Websocket WQHD Videostream

Q: I have a 9008 and 9408 in operation. With the 9008, I have always been able to use an Apache proxy to assign an arbitrary domain to the MJPG stream. Is it generally no longer possible to use the stream via proxy?

A: You can use the following NGINX proxy configuration to forward and expose your cameras video stream securely to the internet. Start by downloading or cloning the repository:

git clone https://github.com/mpolinowski/docker_ws_video_proxy.git

NGINX Configuration

The important files inside this repository are:

.
├── certs
│   ├── nginx-selfsigned.crt
│   └── nginx-selfsigned.key
├── conf.d
│   ├── mjpeg-proxy.conf
│   ├── ws-proxy.conf
│   └── wss-proxy.conf
├── nginx.conf

TLS Certificates

Note that the repository contains a self-signed TLS certificate and key. This can be used for testing - or simply generate a fresh one using the OpenSSL CLI tool:

cd docker_ws_video_proxy/certs
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out nginx-selfsigned.crt -keyout nginx-selfsigned.key

But also note that Google Chrome is going to refuse a self-signed certificate for Websocket connections. You will have to replace them with CA signed certificates if you want to setup a secure connection.

NGINX Main Configuration

The main configuration file for the NGINX proxy is nginx.conf. Here you can choose what kind of proxy you want to setup - comment out all configuration files here that you do not want to use:

docker_ws_video_proxy/nginx.conf

# MJPEG proxy
include /etc/nginx/conf.d/mjpeg-proxy.conf;
# Secure MJPEG proxy
# include /etc/nginx/conf.d/mjpeg-secure-proxy.conf;
# Websocket proxy
# include /etc/nginx/conf.d/ws-proxy.conf;
# Secure websocket proxy
# include /etc/nginx/conf.d/wss-proxy.conf;

Server Configuration

Next are the server configuration files themselves - for example the MJPEG Proxy server:

docker_ws_video_proxy/conf.d/mjpeg-proxy.conf

Here the upstream host is always your IP cameras local IP address or domain name followed by the HTTP port - e.g. 192.168.2.120:80:

upstream mjpeghost {
    # IP and http port of your camera
    server 192.168.2.120:80;
}

The Server Block allows you to set the port on which you want NGINX to re-stream your camera's video, e.g. 8888. The server_name is the IP address or domain name of the NGINX host system. In the example below I am re-streaming the video to localhost - this way it is only accessible on the NGINX host itself using the address http://127.0.0.1:8888. And lastly there is the proxy_pass where you can adjust the MJPEG URL according to your needs. The example uses the /13 stream - which is the smallest one. Change it to /12 or /11 when needed. And, of course, you need to add your own username and password:

server {
    listen 8888;

    # IP of your proxy server or localhost
    server_name 127.0.0.1;

    location    / {
        proxy_pass http://mjpeghost/livestream/13?action=play&media=mjpeg&user=admin&pwd=instar;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host:$server_port;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Port $server_port;
        proxy_set_header X-Request-Start $msec;
    }
}

Run the MJPEG Proxy

Use a volume mount into the NGINX container to over-write the default configuration. Make sure that /path/to/docker_ws_video_proxy point towards the repository you downloaded:

docker run --rm --network host -v /path/to/docker_ws_video_proxy:/etc/nginx --name proxy nginx:alpine

This will run the container attached to your terminal and destroy the container when you quit. The NGINX proxy is configured to send it's logs to STDOUT - so you will see all access attempts and error messages in your terminal. You can also run the container detached from your console:

docker run -d --network host -v /path/to/docker_ws_video_proxy:/etc/nginx --name proxy nginx:alpine

To test if it is working open a browser on your host machine and visit http://127.0.0.1:8888 - you should be able to see the MJPEG Stream of your camera - without the need to log in. This is a much more secure way to publish your cameras video to a public web page - as the user that will access this stream will not be able to see the login credentials or send any CGI commands to your camera.

Secure MJPEG Proxy

Now that we have the simple MJPEG streaming proxy up and running - let's make it a bit more complicated by adding TLS encryption. As mentioned above, the repository contains a self-signed TLS certificate and key. You replace those with your own - or even better - get a CA signed certificate, e.g. from Let's Encrypt.

The changes we have to make to the NGINX configuration are fairly simple. Start by selecting the correct configuration file:

docker_ws_video_proxy/nginx.conf

# MJPEG proxy
# include /etc/nginx/conf.d/mjpeg-proxy.conf;
# Secure MJPEG proxy
include /etc/nginx/conf.d/mjpeg-secure-proxy.conf;
# Websocket proxy
# include /etc/nginx/conf.d/ws-proxy.conf;
# Secure websocket proxy
# include /etc/nginx/conf.d/wss-proxy.conf;

Now open the configuration file and add your information - just like in the simple MJPEG example above - but note that the Server Block now holds the certificate and key file (which you should replace with your own - but the included certificate will work for testing):

# your SSL configuration
# ssl_certificate /opt/letsencrypt/live/my.domain.com/fullchain.pem;
# ssl_certificate_key /opt/letsencrypt/live/my.domain.com/privkey.pem;
ssl_certificate /etc/nginx/certs/nginx-selfsigned.crt; # Replace with the 2 lines above when using CA Cert
ssl_certificate_key /etc/nginx/certs/nginx-selfsigned.key;

Now stop the NGINX container - if it is still running - and re-start it:

docker run --rm --network host -v /path/to/docker_ws_video_proxy:/etc/nginx --name proxy nginx:alpine

Now you will have to use HTTPS to access your cameras live video https://127.0.0.1:8888/. When using a self-signed certificate your browser will warn you about that - just click to accept.

Websocket Proxy

Both the basic and secure websocket proxy configuration are mostly identical to the examples above. So you should now have any issues editing the configuration files.

But to access the websocket video stream you need a websocket client - like the one provided here:

You can embed this in your website and receive the stream from your NGINX proxy via it:

As mentioned in the TLS section above - you browser will not accept a websocket (wss) connection using a self-signed certificate. You will need to use a tool like certbot to generate a CA signed certificate and key for your proxy to be able to work with the secure websocket stream of your camera.