Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Questions about HTTP Access/Mods may go here
Forum rules
1) This is a user forum for Synology users to share experience/help out each other: if you need direct assistance from the Synology technical support team, please use the following form:

https://account.synology.com/support/su ... p?lang=enu



2) To avoid putting users' DiskStation at risk, please don't paste links to any patches provided by our Support team as we will systematically remove them. Our Support team will provide the correct patch for your DiskStation model.
2mny
Trainee
Trainee
Posts: 13
Joined: Wed Nov 21, 2012 3:47 am

Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by 2mny » Sun Mar 06, 2016 8:41 am

Edit: Updated guide with a more permanent http redirect method.
Edit: With the release of DSM 6, the entire process changes and most steps can now be performed directly from DSM.

This is a guide for setting up web services that are hosted on various port numbers to be accessible through a sub-domain (*.example.com) and then protecting those services with SSL encryption using a free let's encrypt certificate. To set this up you will need:
  • your own domain
  • a virtual machine running your favorite linux distro that can mount the web root of your diskstation
  • web station enabled on your diskstation
If you already have a single domain letsencrypt cert, letsencrypt will allow you to replace it with an expanded cert covering up to 100 sub-domains.

Why would you want to do this?
  • provide free ssl protection for all web services, even those that do not natively support it
  • simplify ssl protection for apps that support ssl but have complicated setup steps
  • no more security exceptions in your web browsers for self-signed certs
  • simplify router/firewall port forwarding (only open ports needed are 80 and 443)
  • domain names are easier to remember that port numbers
This configuration does not encrypt traffic between your diskstation on your local network. If you need to encrypt local area network traffic, block direct requests to your diskstation's web services or find an alternative solution.

DSM 6
It looks like DSM 6 switches the internal webserver from Apache to nginx. With these changes, the reverse proxy scripts that worked in DSM 5 no longer function. Luckily, Synology has added reverse proxy features directly into the DSM web interface.

First you will want to set up a HTTP -> HTTPS redirect in the moustache template for the nginx config. Without the redirect in place, visitors to your sites using http:// will receive a HTTP 403 error from the nginx server and links within services may not function. You may need to reapply the changes to the moustache file after installing DSM updates as new updates may overwrite the edited file:
  • SSH into your synology with an admin account.
  • switch to the root account with

    Code: Select all

    sudo su -
    Alternatively, prepend 'sudo' to all of the following terminal commands
  • open /usr/syno/share/nginx/WWWService.mustache in a text editor like vi. To be safe, backup your config before making any changes

    Code: Select all

    cp /usr/syno/share/nginx/WWWService.mustache /usr/syno/share/nginx/WWWService.mustache.bak
  • locate the first lines of the file that look like this:

    Code: Select all

    server {
        listen 80 default_server{{#reuseport}} reuseport{{/reuseport}};
        listen [::]:80 default_server{{#reuseport}} reuseport{{/reuseport}};
        listen 443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
        listen [::]:443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
    
        server_name _;
    
        {{> /usr/syno/share/nginx/X-Accel}}
    change it to look like this

    Code: Select all

    server {
        listen 80 default_server{{#reuseport}} reuseport{{/reuseport}};
        listen [::]:80 default_server{{#reuseport}} reuseport{{/reuseport}};
    
        server_name _;
        return 301 https://$host$request_uri;
    }
    
    server {
        listen 443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
        listen [::]:443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
    
        server_name _;
    
        {{> /usr/syno/share/nginx/X-Accel}}
  • The next time the nginx config file is changed through the DSM web interface, the http > https redirect added to the template will be applied to the config
  • You may also manually add the 301 redirect to the nginx config file at /etc/nginx/nginx.conf, then reload nginx to apply the changes

    Code: Select all

    nginx -s reload
Now add a reverse proxy for each service from the DSM web interface at "Control Panel > Application Portal > Reverse Proxy".

As I upgraded from DSM 5 and kept my existing Let's Encrypt certs, I have not had a chance to try out the new integrated Let's Encrypt functionality in DSM 6. This post will be updated with instructions once I have had a chance to use it.

DSM 5.X
Get a certificate
DSM 5.x does not support running letsencrypt locally and DSM 6 has reportedly had issues with requests for sub-domains(Certificate Subject Alt Name). To get around these issues, we can run the letsencrypt certificate request code inside an external linux vm.

dip987's post is a great guide to get started with a single domain letsencrypt cert. When requesting multiple sub-domains, manually handling acme challenges for every domain becomes a pain. Letting letsencrypt handle creating the challenge files by using the webroot option simplifies the request.

I ran into problems requesting certs with the Apache reverse proxies for my sub-domains active, I recommend disabling these while making the cert request. Web station should route web requests for nonexistent sub-domains back to your main domain without any additional configuration (http://does-not-exist.example.com/.well-known > http://example.com/.well-known).
  1. Disable any existing url forwarding rules set up to map sub-domains to your synology web services.
  2. Spin up a linux vm
  3. Mount the web root of your diskstation to the local vm. There are multiple ways of doing this that vary greatly so I won't get into details here. Just make sure that the mount path is writable by the root user of your vm as letsencrypt runs as root. For this guide we will say the web root path is mounted on the vm at '/mnt/example/web'.
  4. Test the acme url. On the vm:

    Code: Select all

    mkdir -p /mnt/example/web/.well-known/acme-challenge
    sudo echo "test" > /mnt/example/web/.well-known/acme-challenge/test
    
    now make sure you can bring up http://example.com/.well-known/acme-challenge/test in a web browser.
  5. Download the latest letsencrypt request code on the vm:

    Code: Select all

    git clone https://github.com/letsencrypt/letsencrypt
    cd letsencrypt
  6. Make the certificate request:

    Code: Select all

    letsencrypt certonly --webroot-path /mnt/example/web/ -d example.com -d mail.example.com -d files.example.com -d dsm.example.com
    here we are requesting a single cert that validates the example.com domain and the mail, files and dsm sub-domains. Add as many sub-domains as needed.
  7. If all goes well the request will be successful and letsencrypt will have issued you a single certificate that is valid for your primary domain and the sub-domains you requested. You can find the new cert components at /etc/letsencrypt/archive/example.com on your vm. Import privkey#.pem, cert#.pem and chain#.pem to your Synology (control panel > Security > Certificate > "Import certificate"). The #'s in these files will increment by one every time you make a successful request.
Redirect synology package web services to sub-domain urls
We'll be using the built-in apache web server to redirect sub-domains to our web services using reverse proxies. Primal Cortex has already provided a great guide to setting this up. Scroll down to the bottom of the guide to the section detailing setting up the script provided by Michi.
  • Open Michi's script in a text editor
  • Add the missing # to the first line of the script so it reads

    Code: Select all

    #!/bin/sh
  • Change the url variable on the 4th line of the script to match your site domain name
  • Edit the section near the bottom of the script to match the sub-domain names to the port numbers your web services run on:

    Code: Select all

    #Usage: subdomain redirected port. So for example audio 8800 will redirect audio.mydomain.com to the internal 8800 port.
    redirectSubdomainTo audio 8800
    redirectSubdomainTo dsm 5000
    redirectSubdomainTo file 7000
    redirectSubdomainTo note 9350
    redirectSubdomainTo video 9007
  • (optional) Redirect future acme sub-domain cert requests back to your primary domain by adding a redirect rule to the following section:

    Code: Select all

    <VirtualHost *:80>
      ServerName $1.$URL
      <Location />
        RedirectPermanent / https://$1.$URL/
      </Location>
    </VirtualHost>
    Now becomes:

    Code: Select all

    <VirtualHost *:80>
      ServerName $1.$URL
      <Location />
        RedirectPermanent /.well-known/ http://${URL}/.well-known/
        RedirectPermanent / https://$1.$URL/
      </Location>
    </VirtualHost>
    Without this rule you will need to temporarily disable redirects when requesting a new cert. Note that even with the rule in place you may still encounter issues with certificate requests.
  • Save the script to /usr/local/etc/rc.d/S99subdomains.sh on your diskstation so it will run on startup.
  • Make the script executable with

    Code: Select all

    chmod +x /usr/local/etc/rc.d/S99subdomains.sh
  • Start the script with

    Code: Select all

    /usr/local/etc/rc.d/S99subdomains.sh start
Everything should now be in place. Open a sub-domain url in a web browser and you should see a lock icon in the browser url bar indicating the site is protected by a verified ssl certificate. Requests using http:// should automatically be redirected to https://.
Last edited by 2mny on Thu Jun 30, 2016 2:33 am, edited 3 times in total.

User avatar
ilkevinli
Sharp
Sharp
Posts: 166
Joined: Thu Apr 19, 2012 2:05 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by ilkevinli » Mon Mar 07, 2016 1:52 pm

Thanks for the guide. It would be a lot better if this could all be done from the NAS itself without using a VM.

scyto
Rookie
Rookie
Posts: 32
Joined: Sun Jul 19, 2015 11:10 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by scyto » Sat Apr 02, 2016 10:39 pm

ilkevinli wrote:Thanks for the guide. It would be a lot better if this could all be done from the NAS itself without using a VM.
Given that DSM 6 allows you to request the certs and export the files in the UI there should be no reason to spin up a VM or mess about installing lets encrypt. Getting certs via the UI has worked perfectly for me.

jce221
I'm New!
I'm New!
Posts: 3
Joined: Fri Mar 25, 2016 12:04 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by jce221 » Tue Apr 05, 2016 3:23 am

scyto

You were able to complete the entire process using the UI on DSM 6 and it worked successfully? I just received my DS and will be trying this out over the next couple of days. Thanks for the posts everyone!

CarrollLewis
I'm New!
I'm New!
Posts: 3
Joined: Thu Jun 23, 2016 8:25 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by CarrollLewis » Thu Jun 23, 2016 10:25 pm

@2mny, although I am using DSM 6.0.1-7393 Update 1, I could not get your instructions for DSM 6 to work.

I finally had success with [https://primalcortex.wordpress.com/2016 ... mment-2425][a hint from trent on primalcortex], but would have loved to get it all done your way.

CarrollLewis
I'm New!
I'm New!
Posts: 3
Joined: Thu Jun 23, 2016 8:25 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by CarrollLewis » Thu Jun 23, 2016 10:46 pm

Ugh, I'm still learning the synology forum UI and accidentally posted too soon. Let me try again.

@2mny, I'm using DSM 6.0.1-7393 Update 1, but couldn't get your instructions for DSM 6 to work for a virtual host domain. I want

Code: Select all

http://my.example.com
to 301 to

Code: Select all

https://my.example.com
, using the standard ports 80 and 443.

I finally had success with a hint from Trent on primalcortex, but would have preferred to do things your way.

First, I edited WWWService.mustache as you suggested, then created a test virtual host in the DSM Web Station. It created the virtual host, but did not update

Code: Select all

/etc/nginx/nginx.conf
with the new block.

Then I edited

Code: Select all

/etc/nginx/nginx.conf
directly, per your instructions, and restarted nginx with

Code: Select all

nginx -t && nginx -s reload
, also per your instructions. The

Code: Select all

-t
verified that my syntax was correct.

The last instruction you give is to create a reverse proxy, and here I had total failure. I have no experience with reverse proxies, so I don't know what it was supposed to look like. I navigated to the Application Portal in the Control Panel, Reverse Proxy tab, and hit Create. I tried Source: {Protocol: HTTP, Hostname: my.example.com, Port: 80} and Destination: {Protocol: HTTPS, Hostname: <my router IP>, Port: 443}, but it complained that my.example.com was already created, so it was invalid.

So I kept trying all sorts of things, e.g. source hostname *, destination hostname localhost, etc, etc, with various errors, including complaints that ports 80 and 443 are already in use, and not valid.

Any idea how to apply your instructions to a web station virtual host?

seopr9utpo
I'm New!
I'm New!
Posts: 7
Joined: Mon May 30, 2016 11:53 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by seopr9utpo » Fri Jun 24, 2016 5:36 pm

I'm trying to figure out where the actual LE certs are stored so that I can update them via command line.

Any ideas? Thanks.

2mny
Trainee
Trainee
Posts: 13
Joined: Wed Nov 21, 2012 3:47 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by 2mny » Thu Jun 30, 2016 2:27 am

seopr9utpo wrote:I'm trying to figure out where the actual LE certs are stored so that I can update them via command line.

Any ideas? Thanks.
SSl cert paths can be found in the /etc/nginx/nginx.conf file.

Code: Select all

    ssl_certificate           /usr/syno/etc/certificate/system/default/fullchain.pem;
    ssl_certificate_key       /usr/syno/etc/certificate/system/default/privkey.pem;
    ssl_protocols             TLSv1.2;
    ssl_ciphers               ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256;
    ssl_dhparam               /usr/syno/etc/ssl/dh2048.pem;
    ssl_prefer_server_ciphers on;

cravaus
Novice
Novice
Posts: 58
Joined: Wed Jul 02, 2014 6:12 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by cravaus » Fri Aug 26, 2016 5:25 pm

This is very helpful. I wish there was a way to avoid having this change wiped out on updates. I have noticed that at least in the last update, the following did not work to load the new code:

nginx -s reload

I used this instead:

synoservicecfg --restart nginx

Froberg
I'm New!
I'm New!
Posts: 1
Joined: Wed Aug 23, 2017 10:58 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by Froberg » Wed Aug 23, 2017 11:02 pm

I was unable to get your method to work. I'm mostly interested in making sure my public-facing sites, a wordpress and owncloud installation, are forced to https. As far as I can discern, nginx actively ignores .htaccess files, so I had hoped your solution would be "the one".
As for editing the mustache file, I worry it gets over-written by Syno habitually?

At any rate, I had zero luck using your suggestion, here's my current config - unaltered - maybe you can see what's up! :)

Code: Select all

server {
    listen 80 default_server{{#reuseport}} reuseport{{/reuseport}};
    listen [::]:80 default_server{{#reuseport}} reuseport{{/reuseport}};

    gzip on;

    {{> /usr/syno/share/nginx/WWW_Main}}

    location ~ ^/$ {
        rewrite / http://$host:{{DSM.port}}/ redirect;
    }
}

server {
    listen 443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
    listen [::]:443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};

    {{#DSM.https.compression}}
    gzip on;
    {{/DSM.https.compression}}

    {{> /usr/syno/share/nginx/WWW_Main}}

    location ~ ^/$ {
        rewrite / https://$host:{{DSM.ssl.port}}/ redirect;
    }
}
Thanks! :) And yes, let's indeed SSL ALL THE THINGS! :P

hshah
Apprentice
Apprentice
Posts: 85
Joined: Thu Aug 22, 2013 7:26 pm

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by hshah » Sun Oct 01, 2017 6:46 pm

The changes to WWWService.mustache do no seem to be applying either :(

2mny
Trainee
Trainee
Posts: 13
Joined: Wed Nov 21, 2012 3:47 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by 2mny » Wed Jan 24, 2018 7:54 pm

As far as I can tell, the WWWService.mustache file is used as a template to generate the nginx.conf file. Changes made through the web interface use the mustache file to create the nginx.conf file. Therefore:

- Updating the mustache file then restarting nginx through

Code: Select all

sudo nginx -s reload
will not cary the changes over to the nginx.conf file. Making a change through the web interface will cary the mustache file changes over to nginx.conf. Using

Code: Select all

sudo synoservice --restart nginx
may also cary changes over.

- Directly updating the nginx.conf file and running

Code: Select all

sudo nginx -s reload
will affect the changes immediately. However, if the mustache file has not been modified, those changes will be rewritten the next time a change is made through the web interface and possibly through other actions such as a WebStation update or diskstation restart.

- Installing diskstation updates may cause the mustache file to be replaced with the stock file, erasing any changes made to it.

As updating these files every time is a hassle, I'm going to look at making a startup script that modifies the mustache file on startup.

rdsxchg
I'm New!
I'm New!
Posts: 1
Joined: Wed Jun 27, 2018 4:21 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by rdsxchg » Wed Jun 27, 2018 4:29 am

Re: Redirect Virtual Hosts HTTP to HTTPS

The code from my WWWService.mustache file doesn't match the example provided here for DSM 6. My version is DSM 6.2-23739. Can someone please provide code that is known to work that matches the updated version of the WWWService.mustache file? Thanks.

WWWService.mustache from DSM 6.2-23739:
server {
listen 80 default_server{{#reuseport}} reuseport{{/reuseport}};
listen [::]:80 default_server{{#reuseport}} reuseport{{/reuseport}};

gzip on;

{{> /usr/syno/share/nginx/WWW_Main}}

location ~ ^/$ {
rewrite / http://$host:{{DSM.port}}/ redirect;
}
}

server {
listen 443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
listen [::]:443 default_server ssl{{#reuseport}} reuseport{{/reuseport}};
{{#DSM.https.compression}}
gzip on;
{{/DSM.https.compression}}

{{> /usr/syno/share/nginx/WWW_Main}}

location ~ ^/$ {
rewrite / https://$host:{{DSM.ssl.port}}/ redirect;
}
}

2mny
Trainee
Trainee
Posts: 13
Joined: Wed Nov 21, 2012 3:47 am

Re: Guide: SSL all the things! Proxying web services through sub-domains with letsencrypt SSL encryption

Unread post by 2mny » Thu Jun 28, 2018 2:45 am

For the updated WWWService.mustache file, I wrote the following python script which I saved to "/usr/local/etc/rc.d/S97SSLRedirect.py". The script checks the mustache file to see if it has the default configuration. If it does, the script backs up the mustache file then replaces the http portion of the config with a https redirect and restarts the nginx service. The nginx service restart triggers a rebuild of the nginx config files using the updated mustache. HTTP > HTTPS redirects should start working as soon as the script is run.

Code: Select all

#! /usr/bin/python

import re
import subprocess

MUSTACHE = '/usr/syno/share/nginx/WWWService.mustache'
old_txt = '''    {{> /usr/syno/share/nginx/WWW_Main}}

    location ~ ^/$ {
        rewrite / http://$host:{{DSM.port}}/ redirect;
    }'''
new_txt = '''    server_name _;
    return 301 https://$host$request_uri;'''

with open(MUSTACHE, 'r') as f:
    str = f.read()

if old_txt in str:
    with open(MUSTACHE + '.bak', 'w') as f:
        f.write(str)
    str = str.replace(old_txt, new_txt, 1)
    with open(MUSTACHE, 'w') as f:
        f.write(str)

    CMD = ['/usr/syno/sbin/synoservicecfg', '--restart', 'nginx']
    subprocess.check_call(CMD)
The script should run automatically at startup but if it doesn't, you can ssh in to your diskstation and manually run it with

Code: Select all

sudo /usr/local/etc/rc.d/S97SSLRedirect.py

Post Reply

Return to “HTTP/Apache Mods”