Skip to main content

Blogging with Eleventy

Having posted sporadically on Medium I thought I'd finally put my thoughts into my own space. I moved the Logical Cobwebs website to Eleventy last week and while I'm on a roll…

Eleventy

I started off with Eleventy Blog template which not only saves you time but it demonstrates a lot of techniques. There's some solid CSS included but my approach was to start from scratch and pull in bits that I wanted.

Lighthouse

I love that, out of the box, the blog template includes the Lighthouse plugin which tests performance, accessibility, best practices and SEO. If you're not 100% on all those then the deploy fails! You can override that if you really want.

100% on all four metrics

Docker

I wanted to be able to run this website easily on my Mac so I set up Docker.

This is my Dockerfile. Not much going on here:

  1. Use an image providing Node 18
  2. Copy over the app
  3. Install the packages
  4. Tell it to run on port 8082
FROM node:18.15-bullseye

RUN mkdir -p /app
WORKDIR /app

COPY . /app/
RUN npm install

EXPOSE 8082

CMD [ "npx", "@11ty/eleventy", "--serve", "--port=8082" ]

We're using Traefik as a load balancer which makes things easy (even though we don't really need it). Here's the docker-compose.yml file:

version: "3.7"

services:

  lb:
    image: traefik:v2.9
    command:
      - --providers.docker
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  web:
    build:
      context: .
      dockerfile: Dockerfile
    labels:
      - traefik.http.routers.whoami.rule=Host("dev.logicalcobwebs.com")"
    depends_on:
      - lb
    container_name: logicalcobwebs
    restart: always
    volumes:
      - ./:/app:cached
    ports:
      - 8082:8082

volumes:
  logicalcobwebs-app:

And now it's just

docker-compose up web

And with dev.logicalcobwebs.com pointing to 127.0.0.1 I'm all set to go with it running at http://dev.logicalcobwebs.com (note: that website isn't available on the Internet, it's just on my machine).

Let's Encrypt!

But we can do more! Let's get SSL working automatically by asking Let's Encrypt to generate the SSL certificate using a DNS challenge from DNSimple.

version: "3.7"

services:

  lb:
    image: traefik:v2.9
    environment:
      - DNSIMPLE_OAUTH_TOKEN
      - DNSIMPLE_BASE_URL
    command:
      - --providers.docker
      - --entrypoints.http.address=:80
      - --entrypoints.https.address=:443
      - --api.insecure=true
      - --certificatesresolvers.letsencrypt.acme.dnsChallenge=true
      - --certificatesresolvers.letsencrypt.acme.dnsChallenge.provider=dnsimple
      - --certificatesresolvers.letsencrypt.acme.dnsChallenge.delayBeforeCheck=0
      - --certificatesresolvers.letsencrypt.acme.email=${EMAIL}
      - --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
    labels:
      - traefik.http.routers.to-https.rule=HostRegexp(`{host:.+}`)
      - traefik.http.routers.to-https.entrypoints=http
      - traefik.http.routers.to-https.middlewares=to-https
      - traefik.http.routers.traefik.rule=Host(`traefik.${DOMAIN}`)
      - traefik.http.routers.traefik.entrypoints=https
      - traefik.http.routers.traefik.service=api@internal
      - traefik.http.routers.traefik.tls=true
      - traefik.http.routers.traefik.tls.certresolver=${CERT_RESOLVER}
      - traefik.http.middlewares.to-https.redirectscheme.scheme=https

    ports:
      - 80:80
      - 8080:8080
      - 443:443
    volumes:
      - ./data/letsencrypt:/letsencrypt
      - /var/run/docker.sock:/var/run/docker.sock

  web:
    build:
      context: .
      dockerfile: Dockerfile
    labels:
      - traefik.http.routers.https.rule=Host(`${DOMAIN}`)
      - traefik.http.routers.https.entrypoints=https
      - traefik.http.routers.https.tls=true
      - traefik.http.routers.https.tls.certresolver=${CERT_RESOLVER}
    depends_on:
      - lb
    container_name: logicalcobwebs
    restart: always
    volumes:
      - ./:/app:cached
    ports:
      - 8082:8082

volumes:
  logicalcobwebs-app:

Finally, a .env file like this. You need to get DNSIMPLE_OAUTH_TOKEN from your DNSimple account settings, not from your user settings.

DOMAIN=dev.logicalcobwebs.com
EMAIL=
CERT_RESOLVER=letsencrypt
DNSIMPLE_BASE_URL=https://api.dnsimple.com
DNSIMPLE_OAUTH_TOKEN=

Now we can use https://dev.logicalcobwebs.com.