How to set Sandstorm behind a reverse proxy, keeping your sandcats.io domain and certificates

I’m having some fun tinkering with my new Intel NUC home server (with Linux, of course) and moving everything that I had in the “cloud” to it (except backups). Last night I set up Sandstorm behind an nginx reverse proxy accepting https connections (for this and other services) while keeping Sandstorm working with my registered sandcats.io domain and free auto-renewable https certificates. Since this is something I couldn’t find any documentation about I’ll add how to get it done in this article.

This was not obvious to do because:

  • Sandcats.io certificates only seem to work for the 443 port (or maybe is a problem with the renewal, I don’t know).

  • Sandstorm need a wildcard domain or subdomain to run and letscrypt doesn’t provide wildcard certificates. So to reverse proxy Sandstorm under your own domain you would need a paid wildcard cert (and those are not cheap) or run on unencrypted http (and you don’t want that).

  • Self signed wildcard certificates don’t work very well. Usually they make the images don’t load correctly even if you accept the certificate (happened to me on Chrome, Opera, in Firefox grains wouldn’t even load) or require you to create a rootCA cert and install it on every machine where you want to use Sandstorm. Which defeats the purpose of having web apps and it’s not always easy to do on some phones or other non-PC devices.

The official documentation advices to use sniproxy if you want to share the 443 port with other applications. I did that for a while, having a dockerized sniproxy in front of both nginx and Sandstorm redirecting to the correct one based on the ssl handshake. I run like this for a while, but I had two problems. First, there was a noticeable performance penalty in requests/second compared to unproxied nginx. The second problem is that I saw that there was some leaking something between domains. For example using some web tool to analyze site performance that showed all requests I saw that, oddly, there were some requests for parts of my site (on another domain) that landed on my name.sandcats.io domain, and they delayed the page loading. Also, with sniproxy I couldn’t enable http2.

Finally after some tinkering and a little scripting I found a better and working solution. Follow these steps:

Install and configure Sandstorm

Do the initial installation and configuration of Sandstorm, choosing to enable the Sandcats service. Don’t start the service yet. Now edit your sandstorm.conf file and configure it to also use HTTPS by adding or uncommenting the line:

HTTPS_PORT=443

Its important to keep the port number of the HTTPS_PORT option at 443 at least when retrieving of renewing the certificates. If you are running your Sandstorm service inside a container or VM you can leave this option enabled since this way the short-lived certificates will continue auto renewing themselves and we’ll not export the 443 port outside the container so it won’t conflict with your reverse proxy.

If you aren’t using running Sandstorm inside a container, you’ll need to block or redirect the port (with iptables?). Or just use Docker, it’s super easy with Sandstorm

Next, change BASE_URL to use start with https://:

# BASE_URL=http://yourname.sandcats.io
BASE_URL=https://yourname.sandcats.io

After this:

  • Stop your reverse proxy so the 443 port is free

  • Run the sandstorm service, making sure that the 443 port is accessible from the outside (unfirewall it, enable it on docker with the -p 443:443 option, whatever)

  • Check with your browser that you can access your https URL and Sandstorm works.

  • Check the logs on [sandstorm_dir]/data/var/log/sandstorm/log) to see that it fetched the certificates.

  • Double check that the files are on [sandstorm_dir]/data/var/sandcats/https/yourname.sandcats.io (they are like timestamps with .csr or response-json extensions or no extension, with the timestamp being the expiration date)

  • Finally, stop sandstorm, and if you run it dockerized unexport the 443 port but expose the HTTP port (see below in the network section) or if you are running it uncontained change or disable the HTTPS_PORT setting as needed.

  • Wake up both your reverse proxy and sandstorm services.

Run the script on this repo

That script will copy the Sandcats.io certs in your reverse proxy directory (for nginx this would tipically be /etc/nginx/ssl). Since Sancats.io certificates must be renewed weekly I suggest to add this to your cron. A typical call could be:

extract_certs.sh
cp sandstorm.key /etc/nginx/ssl
cp sandstorm.pem /etc/nginx/ssl

Configure Sandstorm network parameters

Next you need to configure your Sandstorm container/VM so it serves on the 443 port of the container and can be linked to other containers but it’s not published on the host machine (where it would conflict with your reverse proxy).

In the case of the docker container just remove the -p parameter for the docker run command and add the port as a --expose like:

sudo docker run --name sandstorm \
  --privileged --sig-proxy=true --expose 443 \
  -v /home/you/docker/sandstorm/data:/opt/sandstorm \
  -d buildpack-deps \
   bash -c 'useradd --system --user-group sandstorm && ' \
           '/opt/sandstorm/sandstorm start && ' \
           'tail -f /opt/sandstorm/var/log/sandstorm.log && ' \
           'sleep infinity' 

With --expose only