Synology DSM - reverse proxy config using NGINX.

Where you have Synology/DSM exposed to the internet (and using their DDNS) but also some other web servers or services on your internal network that you wish to expose through the Synology acting as a reverse proxy then this is one way to configure Nginx on DSM to pass it thru.

In fact, there's not much DSM specific about this -- its all really about NGINX -- but my use case is on Synology/DSM thats all and any Linux would be similar.

Summarising the setup:

  1. Synology/DSM exposed to the internet and available on something like http://yourname.synology.me
  2. You'll likely have other services available a subfolders of that e.g. http://yourname.synology.me/cam (for surveliancestation access from the mobile app) and want to follow a similar pattern.
  3. You also have some other web server on your internal network that you want exposed to the internet using the same pattern of a path under the synology.me DDNS url. That service on your internal network might be for example the url: http://192.168.0.99/blahblah -- clearly the internal ip address and url path will be specific to your setup, or maybe the path is just the root on the other server

One way would be using an alternative port -- either direct on your internet facing router as it likely has a port forwarding config, or on the Synology using the DSM and the Application Portal / Reverse Proxy configuration in control panel.

BUT I dont like the fact that you would see for example http://yourname.synology.me:1234 as the url for your internal service when exposed to the internet -- I prefer to see something more descriptive and reflect the actual backends path e.g. http://yourname.synology.me/blahblah/

The solution is to configure the already present NGINX service on DSM and add knowledge for your new backend and of course without disrupting the existing configs for all the usual services managed by DSM and without having to loose that config each time DSM control panel is touched.

You will need ssh access to a the Synology and know how to edit files in Linux. Then...

  1. Connect to your Synology and locate the path /etc/nginx.
  2. Check the file nginx.conf and look for the server section listening on port 80 and check it has the include we will make use of...
    server {
         listen 80 default_server;
         listen [::]:80 default_server;
         ...
         include conf.d/www.*.conf;
    
  3. the other includes for app.d directory are (I assume) the Synology application mappings and we'll not touch or use that to try and prevent this config getting lost on any upgrade or control panel changes.
  4. that include statement is basically saying any file in conf.d subfolder matching www.*.conf will get included into the nginx config ...I believe simply as inline text, so it inherits the context of the server config it is included within.
  5. there is same include in the port 443 server section ...so the same included file will apply to both cases
  6. exit the editor and create the file we expect to work, say conf.d/www.blahblah.conf
  7. it will look something like this:
location ^~ /blahblah/ {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Host $host/blahblah;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://192.168.1.99/blahblah;
}

Key points to note in that config file as follows:

  1. location specifies the match on the subpath in the incoming url we want to match
  2. proxy_pass is the main work and simply says pass this request to the specified backend ...any further subpath or args in the url after the bit matched by location are simply appended to what we set here.
    1. the various X-Forwarded... headers are a standard http way to tell the web site were forwarding to how it should build any return addresses or internal links ... so any links in the backend to itself (e.g. http://192.168.1.99/blahblah/something_else in this contrived example) would actual be returned as references that make sense to the original caller -- including the same http or https that they use to access in first place.

To restart the nginx service try this synoservice --restart nginx although I had some odd behavior and it doesnt seem to work every time!

Note, whether the X-Forwarded... headers are honored or not of course really depends on the other backend itself - if it doesn't then the initial page request will likely work but then returns to the caller on the internet references to subsequent pages as local address to the resource which clearly wont work.

There may be a way in NGINX to have it process response content and change links itself regardless of backend using sub_filter but that is for another post.