3

I am running Nextcloud on a Raspberry Pi at home. It updates its IPv6 address on a hostname at the DynDNS provider spDYN.de. However, as my provider only offers IPv6 connections (using DS-Lite for IPv4), I can only directly access the hostname from other IPv6 connections, and I have to use an IPv4-IPv6 postmapper to connect to it from IPv4 networks.

This is not a big deal, as my website is hosted on a server which has both IPv6 and IPv4 connections, so I used socat according to this tutorial to set up a portmapper on the server hosting my website, routing a specific port from my website domain to port 443 on the dynamic DNS hostname. This works perfectly, but it creates a problem with SSL certificates:

On the RasPi, I used certbot to create a "Let's encrypt" certificate for the dynamic DNS hostname, which works perfectly and the connection is shown as secured. Also, on my webserver, I created a similar certificate for the domain that I am using for the portmapper, which in itself works. However, when I access the domain with the specific, forwarded port to access the RasPi, the browser continues to show the URL containing my domain, but it receives the certificate from the RasPi which has been issued for the dynamic DNS hostname. As a consequence, of course, the security check fails as the certificate is issued for the "wrong" domain. I already tried issueing a certificate on my RasPi for my domain, but it fails telling me I am "unauthorised".

How can I solve this problem? Where do I have to set up which kind of certificate?

2

To avoid certificate errors, you need the pi to send a certificate which matches the domain used. There are two approaches to this:

  1. Use one certificate for both domains, installed on both the pi and main server. It doesn't matter which domain the client used in its query, the certificate will match.
  2. Choose a certificate the client expects and send that.

Option 1 is easier and common practice. Look at the certificate for google.com! Both the pi and the main server will have the same certificate (for both domains) installed. In order to get such a certificate from Let's Encrypt, you will need the main server to run a website for the pi's dynamic domain also and use one certbot command to verify control of both domains at once. The main server's site for the dyndns name need not host the content from the pi - it's just there so Let's Encrypt can verify you have control of that site (you can even turn off that site between renewals).

Sample Certbot command for this (run on the main web server):

letsencrypt certonly --webroot --csr request.csr -w /http/pisite/www -d mypi.spdyn.de -w /http/mainwebsite/www -d maindomain.de

Where request.csr uses either domain as the CN and has both domains in the SANs field, /http/pisite/www refers to a local directory you would create for another website on the current server bound to the pi's dynamic name, and /http/mainwebsite/www is the existing directory of your main website.


Option 2 is more involved but produces a 'cleaner' result: the client gets a certificate which matches the domain they typed. On the raspberry pi, run nginx with the stream module (or equivalent) which, when a TLS connection is opened: examines the SNI field (without accepting the TLS connection), and based on the domain included there, chooses which upstream to forward the connection to. This lets you choose how you want to handle requests made of the main domain on the external port forwarded to the raspberry pi. You can send them to the main web server just as if they were made on the correct port, you can send them to some other port on the pi (ie Nextcloud, or anything else), you can terminate them with the same nginx instance and show whatever page you like, or simply close the connection. The choice is yours.

Here is a sample configuration for this method:

stream/sni-switch.conf

# Listen on 443, and on new connection:
#   if the SNI is mapped herein, handle it on this Nginx
#   else, forward the whole session to 192.168.1.80:443 (TCP passthrough, no decryption)

upstream mainwebserver {
    server 192.168.1.80:443;
}

upstream local_https {
    server 127.0.0.1:1443;
}

map $ssl_preread_server_name $name {
    default mainwebserver;

    pisite.spdyn.de     local_https;
}

server {
    listen 443;

    ssl_preread on;
    proxy_pass $name;
}

And in nginx.conf

load_module /usr/lib/nginx/modules/ngx_stream_module.so;

stream {
    include /etc/nginx/stream/sni-switch.conf;
}

...

To do this with Apache, see this. A sample configuration from which might look like this:

<VirtualHost *:*>
    ProxyPreserveHost On
    ProxyPass        "/" "http://192.168.1.80/"
    ProxyPassReverse "/" "http://192.168.1.80/"
    ServerName maindomain.de
</VirtualHost>
| improve this answer | |
  • Thank you very much for your answer! Reagarding option 1 - at the moment, traffic to the dynamic DNS name does not pass through the web server, so that means I would redirect my dynamic DNS hostname to my web server as well to generate the certificate? Regarding option 2 - I am using Apache, I guess this module would serve the same purpose? wiki.apache.org/httpd/NameBasedSSLVHostsWithSNI – iYassin Oct 1 '17 at 19:41
  • 1- That would work, yes. You would have to be willing to make this significant configuration change every three months or so, though. 2 - do it like this – Scruffy Oct 2 '17 at 11:14
  • I realised it using the VirtualHost option now and it works perfectly. Thank you! – iYassin Oct 4 '17 at 22:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.