How I improved the security of this blog by removing the need of a shared docker socket.

In my last post I described how I set up this site, relying only on a single docker compose file.  I was a bit worried, though, about exposing the docker socket to a container, which is not a best practice if you don't trust the security of the image you are running.

Even if I actually trust very much the authors of both nginx-proxy and docker-letsencrypt-nginx-proxy-companion (kudos to you, @jaswilder and @blusseau, keep up your awesome work), others may feel unconfortable with this kind of set up.

For my use-case, the automatic configuration of the proxy (which is the only reason behind sharing the docker socket) is not really needed. A commenter suggested to look at steveltn/https-portal which can be configured using only environment variables, and automatically provides both the proxy and the Let's Encrypt certificate renewal.

First of all I edited the compose file, to include the new image and remove the configurations and volumes needed for the deleted ones:


version: '3.1'
services:
  https-nginx-proxy:
    image: steveltn/https-portal
    restart: always
    ports:
      - "80:80"
      - "443:443"
    depends_on:
      - ghost
    environment:
      - DOMAINS= www.ourdomain.com -> http://ghost:2368 , ourdomain.com -> http://ghost:2368
      - STAGE=production
      - nginx.certs:/var/lib/https-portal
  ghost:
    image: ghost:2-alpine
    restart: always
    expose:
      - "2368"
    volumes:
      - ghost.data:/var/lib/ghost/content
    environment:
      - url=https://www.ourdomain.com 
      - NODE_ENV=production
volumes:
  nginx.certs:
  ghost.data:

Comparing this setup with the previous one, the environment variables needed for the auto-discovery  are gone (LETSENCRYPT_HOST, LETSENCRYPT_EMAIL, VIRTUAL_HOST ), and the only need for the proxy are DOMAINS, which contains the comma separated list of the proxy routes (domain -> internal_host: port), and the STAGE  which tells the proxy to use the production Let's Encrypt endpoints. To store the certificates among restarts, I use the same nginx.certs volume I configured before.