Dynamic vhosts with https on nginx

In earlier articles I described how to setup vhosts with https in OpenBSD’s httpd, but in the end I got stuck because httpd did not have the flexibility I need in my webserver, so the switch back to nginx was eminent. Now let’s get that dynamic vhosting running with fully automated certificate renewal from Let’s Encypt!

First we setup a server at port 80 that serves the acme-challenge and sends everything else to https:

server {
	listen 80 default_server;
	listen [::]:80 default_server;
	server_name _;
	
	# the acme-challenge
	location /.well-known/acme-challenge {
		rewrite ^/.well-known/acme-challenge/(.*) /$1 break;
		root /acme;
	}

	# redirect everybody else to https
	location / {
		return 301 https://$host$request_uri;

	}
}

Since OpenBSD’s nginx port does not allow the use of variables in the ssl_cerificate and ssl_certificate_key directives. I configured acme-client with only one certificate with a whole long list of alternative names. Kinda ugly, I know…

Activate this server and run:

$ doas acme-client -Fv example.com

When you have your certificate you can add it to the server configuration:

server {
	listen 443 ssl default_server;
	listen [::]:443 ssl default_server;
        server_name $host;
	set $basepath "/vhosts";
	ssl_certificate     /etc/ssl/example.com.fullchain.crt;
	ssl_certificate_key /etc/ssl/private/example.com.key;
   
	if ($host ~ "^(.[^.]*)\.(.[^.]*)$") {
		set $rootpath "$1.$2/www/";
	}
	if ($host ~ "^(.[^.]*)\.(.[^.]*)\.(.[^.]*)$") {
	        set $rootpath "$2.$3/$1/";
	}

	root $basepath/$rootpath;

	location / {
		# First attempt to serve request as file, then
		# as directory, then fall back to displaying a 404.
		try_files $uri $uri/ =404;
	}

	include common.conf;
}
$ doas rcctl reload nginx

And enjoy your dynamic vhosts with https. The only thing you need to do everytime you’ll add a (sub)domain is add it to /etc/acme-client.conf and renew your certificate.