Resource icon

Tutorial Synology Reverse Proxy under the hood

Introduction
Rusty made a fabulous beginner friendly tutorial on how to configure reverse proxy configurations using the UI: Tutorial - Synology Reverse Proxy.

This tutorial is aimed for advanced users: if you feel uncomfortable with working in the shell (or if you don't know what it means) this tutorial is probably not suited for you.

It covers the limitations of the reverse proxy configurations created in the UI and how to bypass them.
Though, it is not going to illustrate how to actualy write nginx configurations (which is used under the hood).

Update Changelog
04.11.2021 Distinguish DSM6 Application Portal and DSM7 Login Portal.
04.11.2021 Distinguish DSM6 and DSM7 commands, add commands to get current status or restart nginx.


DSM6: How the reverse proxy in the Application Portal works

All reverse proxy configurations from the Application Portal -> Tab "Reverse Proxy" end up beeing rendered in the file /etc/nginx/app.d/server.ReverseProxy.conf.

Since changes in the UI result in a immediatly fresh rendered file, all manual changes to that file will be lost... so better not touch it ;)

For every reverse proxy entry in the Application Portal, it renders such a block into the file:
NGINX:
server {
    listen ${source port};                # if ${source protocol} is http
    listen [::]:${source port};           # if ${source protocol} is http
    listen ${source port} ssl;            # or if ${source protocol} is https
    listen [::]:${source port} ssl;       # or if ${source protocol} is https
    listen ${source port} ssl http2;      # or if ${source protocol} is https and ${source port http2} is enabled
    listen [::]:${source port} ssl http2; # or if ${source protocol} is https and ${source port http2} is enabled

    server_name ${source hostname};

    ssl_certificate ${path to fullchain.pem for the assigned certificate in the cert manager};   # if ${source protocol} is https
    ssl_certificate_key ${path to privkey.pem for the assigned certificate in the cert manager}; # if ${source protocol} is https
    add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload" always;  # if ${source port hsts} is enabled

    allow ${source port access control}   # if ${source port access control} is enabled and a profile is selected

    location / {
        proxy_connect_timeout 60; # can be configure in advanced tab
        proxy_read_timeout 60; # can be configure in advanced tab
        proxy_send_timeout 60; # can be configure in advanced tab
        proxy_intercept_errors off; # can be configure in advanced tab
        proxy_http_version 1.1; # can be configure in advanced tab
        proxy_set_header        Host               $http_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 ${destination protocol}://${destination host}:${destination port};
    }

    error_page 403 404 500 502 503 504 @error_page;

    location @error_page {
        root /usr/syno/share/nginx;
        rewrite (.*) /error.html break;
        allow all;
    }
}

What we see is the declaration of a server block, which is included in a http block (regardless whether http or https are configured) in the /etc/nginx/nginx.conf .

  • The listen directive will look different depending whether the https protocol and http2 are configured.
  • The ssl_certificate* directives are only used if the https protocoll is selected.
  • The Strict-Transport-Security header is only used if hsts is enabled for the source port.
  • The allow directive is only used if access control is enabled for the source port (can be used to allow/deny source ip's or cidr).

If you add websocket in the custom headers, following lines will be added to the location block:
NGINX:
proxy_set_header        Upgrade           $http_upgrade;
proxy_set_header        Connection        $connection_upgrade;

Hint: it is possible to add further custom headers using the UI, though be aware that only alpahnumeric character and the - character are allowed for the name.

If the reverse proxied application just requires additional headers, they can be set directly in the UI. Though, in many cases adding headers is still insufficient.

DSM7: How the reverse proxy in the Login Portal works
All reverse proxy configurations from the Login Portal -> Tab "Advanced" -> Reverse Proxy end up beeing rendered in the file /etc/nginx/sites-enabled/server.ReverseProxy.conf.

Once again: changes in the UI result in a immediatly fresh rendered file, all manual changes to that file will be lost...

For every reverse proxy entry in the Internet Portal, it renders such a block into the file:
NGINX:
server {
    listen ${source port};                # if ${source protocol} is http
    listen [::]:${source port};           # if ${source protocol} is http
    listen ${source port} ssl;            # or if ${source protocol} is https
    listen [::]:${source port} ssl;       # or if ${source protocol} is https
    # note: it seems the is no way to configure a ssl http2 listener in DSM7 anymore

    server_name ${source hostname};

    if ( $host !~ "(^${source hostname}$)" ) { return 404; }

    include /usr/syno/etc/www/certificate/ReverseProxy_*/cert.conf*; # if ${source protocol} is https
    include /usr/syno/etc/security-profile/tls-profile/config/ReverseProxy_.conf*; # if ${source protocol} is https

    add_header Strict-Transport-Security "max-age=15768000; includeSubdomains; preload" always;  # if ${source port hsts} is enabled
    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
    include conf.d/${name of acl config}.conf*;  # if ${source access control profile} is selected

    location / {
        proxy_connect_timeout 60; # can be configure in advanced tab
        proxy_read_timeout 60; # can be configure in advanced tab
        proxy_send_timeout 60; # can be configure in advanced tab
        proxy_intercept_errors off; # can be configured in advanced tab
        proxy_http_version 1.1; # can be configure in advanced tab
        proxy_set_header        Host                               $http_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 ${destination protocol}://${destination host}:${destination port};;
    }

    error_page 403 404 500 502 503 504 /dsm_error_page;

    location /dsm_error_page {
        internal;
        root /usr/syno/share/nginx;
        rewrite (.*) /error.html break;
        allow all;
    }
}

What we see is the declaration of a server block, which is included in a http block (regardless whether http or https are configured) in the /etc/nginx/nginx.conf.run .

  • The listen directive will look different depending whether the https protocol and http2 are configured.
  • The include directives will only be used if the https protocoll is selected, the included conf files will be responsible to actualy include certificate related directives
  • The Strict-Transport-Security header is only used if hsts is enabled for the source port.
  • The allow directive is only used if an access control is selected (can be used to allow/deny source ip's or cidr).
If you add websocket in the tab "custom headers", following lines will be added to the location block:
NGINX:
proxy_set_header        Upgrade           $http_upgrade;
proxy_set_header        Connection        $connection_upgrade;

Hint: it is possible to add further custom headers using the UI, though be aware that only alpahnumeric character and the - character are allowed for the name.

If the reverse proxied application just requires additional headers, they can be set directly in the UI. Though, in many cases adding headers is still insufficient.


And now the parts that are missing
- location other than /
- directives (~=nginx configuration items)

Why are those missing parts important? Well, some applications do require either a special location and/or directives beeing set in order to work behind a reverse proxy.

How to workaround the limitation
The main nginx configuration file /etc/nginx/nginx.conf by default provides three includes, which can be leveraged to hook custom reverse proxy configurations in.

In DSM6.2:
  1. /etc/nginx/conf.d/main.conf: can be used to configure high level blocks like http (=layer7 http/https based reverse proxy), stream (=layer4 TCP/UDP Port based reverse proxy) or mail. Just edit the existing file.
  2. /etc/nginx/conf.d/http.*.conf: can be used to configure one or more server block(s) (which are implicitly included in a http block) to create configurations, which allow custom location and directives! Create a new file matching the naming convention.
  3. /etc/nginx/sites-enabled/*: same as 2, though instead of a naming convention, every filename is valid.
In DSM7:
  1. /etc/nginx/conf.d/main.*.conf: can be used to configure high level blocks like http (=layer7 http/https based reverse proxy), stream (=layer4 TCP/UDP Port based reverse proxy) or mail. Create a new file matching the naming convention.
  2. /etc/nginx/conf.d/http.*.conf: can be used to configure one or more server block(s) (which are implicitly included in a http block) to create configurations, which allow custom location and directives! Create a new file matching the naming convention.
  3. /etc/nginx/sites-enabled/*: same as 2, though instead of a naming convention, every filename is valid.
These files are not managed by the Application/Login Portal's reverse proxy configuration, and as such not overwritten/replaced by generated configurations. This also means those configuration won't be listed there! So don't be surprised if you don't see them in the UI :)

After adding/modifying a conf file, it is recommended to test whether the configuration is valid. If you'd load an invalid configuration, the whole nginx will stop working, until the invalid configuration is fixed and reloaded. This will not only affect the reverse proxy part, but also the dsm ui and whatever else depends on the nginx!

Test configuration for validity:
  • DSM6: sudo nginx -t
  • DSM7: sudo nginx -t -c /etc/nginx/nginx.conf.run
Reload configuration:
  • DSM6: sudo nginx -s reload
  • DSM7: sudo nginx -s reload -c /etc/nginx/nginx.conf.run
Restart nginx:
  • DSM6: sudo synoservice -restart nginx
  • DSM7: sudo systemctl restart nginx
Status of nginx:
  • DSM6: sudo synoservice -status nginx
  • DSM7: sudo systemctl status nginx

If you find an application that does not work well with the Application Portal`s reverse proxy configuration from the UI, you typicaly want to add a new file in /etc/nginx/conf.d/http.${myapp}.conf and configure a server block.

Make sure to read the docs of the application and lookout for their reverse proxy recommendations for nginx.

Words of advice
  • Make sure you always test your configuration before you reload it!
  • Make sure to never reboot the NAS with an invalid configuration! Nginx does NOT(!) start with an invalid configuration, the same holds true for the DSM ui on port 5000!
  • When you stop working on a configuration and it is still invalid, make sure to rename it to NOT match the naming convention. If invalid configs exist in /etc/nginx/sites-enabled/*, make sure to move them out of the folder instead.
  • For https, make sure to check how hardend your configuraiton is: SSL Server Test (Powered by Qualys SSL Labs)
    • You will want to at least lock down the allowed ssl_protocols and ssl_ciphers based on the scan result of ssllabs.com

Enjoy!
Related resources



Similar resources

Synology Reverse Proxy Rusty
Tutorial on setting up revers proxy for various apps and services hosted on your NAS via built in RP
5.00 star(s) 6 ratings
Updated
Josh Adams on the Synology Community provides this useful how-to
0.00 star(s) 0 ratings
Updated
0.00 star(s) 0 ratings
Updated
How to monitor, control, damage check of disks in your Synology NAS jeyare
this resource is useful for all categories Syno NAS users, except I don't care segment
0.00 star(s) 0 ratings
Updated
A one-of-a-kind resume builder that keeps your privacy in mind
0.00 star(s) 0 ratings
Updated
Migrating existing Ubiquiti UniFi Controller to Docker in Synology NAS jeyare
Migrating existing Ubiquiti UniFi Controller to Docker in Synology NAS
0.00 star(s) 0 ratings
Updated
Native macOS Finder integration with Synology Universal Search Robbie
Using macOS Finder's native search engine with a Synology NAS
5.00 star(s) 2 ratings
Updated
Top