Fix Synology DSCam behind an nginx reverse proxy

If you use DSCam through an nginx reverse proxy you might notice that new releases of Synology Surveillance Station and the DSCam app may see an endless loop when trying to view live or recorded footage. These seem to have come out late July/early August 2019.

I'm still not really sure when the changes where implemented but it affects both the web app as well as DSCam - I've only been able to test this on Android, but considering the issue is there for both Android and web, the issue may be present on iOS too.

It looks like Synology recently moved Surveillance Station streams to to use websockets. That's not a bad thing, but it isn't documented anywhere, and if you aren't specifically allowing websockets through your nginx conf things aren't going to work.

The issue was first spotted when I tried viewing my cameras from my phone. After a bit of troubleshooting and looking at nginx logs I noticed that the endpoint looked different, feeds were being served from /webapi/.

Looking at the issue on web I could open up the Dev Console, seeing a 502 error.

WebSocket connection to 'wss://sub.domain.io/ss_message_task/?SynoToken=ebaxoxJ79XogQ&ClientType=webclient' failed: Error during WebSocket handshake: Unexpected response code: 502

The nginx conf for this specific subdomain is very basic, it simply runs a proxy_pass to my Surveillance Station and nothing else. After a quick Google I see that nginx needs you to specify how it handles websockets.

I'm replacing the actual domain used here with sub.domain.com for obvious reasons.


Here's my nginx conf with the fix implemented and how to do it.

I'm running Ubuntu 18.04 LTS, the fix should be the same or very similar for other OS types.

server {

        server_name sub.domain.com;

    location / {

      proxy_set_header        Host $host;
      proxy_set_header        X-Real-IP $remote_addr;
      proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header        X-Forwarded-Proto $scheme;

      proxy_pass                http://192.168.1.12:9900;
      proxy_redirect default;

        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;

    }






    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/sub.domain.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/sub.domain.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot


}
server {
    if ($host = sub.domain.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


        server_name sub.domain.com;
    listen 80;
    return 404; # managed by Certbot


}

The fix here is adding the below to your location / { block.

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;

Let's make sure that nginx restarts successfully:

sudo nginx -t

If there are no errors reported we can go ahead and restart nginx:

sudo service nginx restart

All done! Browse to Surveillance Station like you normally do and check if you're able to view streams. I was able to do so immediately after making the changes, you may need to clear app/site caches though.

I found this solution via GitHub with a useful comment from rudolfschmidt.