Nginx to Caddy to Traefik

I've hosted half-baked experiments on and off for over a year or so now over at digital ocean. You know how life can just, get in the way of programming. It's been exceedingly frustrating getting 30-45m spurts of time to work on something over the span of a week or more, wherein most of that time is spent only 'catching up' to what I have done before. I yearned for a toolset that would just allow me to get going with blogging, hosting a minecraft server, or getting a project up and running. All three of those things have fairly simple answers in my mind now, that I can get up and running in an arbitrary environment almost trivially, pretty much entirely because of docker hub and all the great images people create.

At least for web-hosting and blogging, I think I've found the magic sauce - but to tell you the punch line would be selling you short - the journey is really where the learning took place.

So, firstly, I wanted to blog. How does one blog in 2017/2018 era of tech? Well, medium is quite popular, but people have their gripes with the medium platform. I could just post on reddit or hackernews, but I knew I wanted to self-host. Especially since I had underutilized bandwidth on a digital ocean droplet, and a domain name I'm paying for and basically not using.

Now, how does one self-host? Do you just roll your own infrastructure on top of a VPS? Use a static-site generator like hugo? Actually with hugo, it would be easier to host on github, gitlab, or over at netlify like where my wife is initially hosting her portfolio.

I wanted to manage my content more than what hugo and other tools offered. So I knew I wanted a ghost blog, since it was open source, completely theme-driven, and just real nice. They have a solid dev team, and a good paid cloud solution to fund the ongoing development of the product.

But my journey hit a rocky road... You see, I wanted to write my own NodeJS app at thenewells.us, and then have another node app be the ghost blog at subdomains. Seems like a good idea, initially, but then the root NodeJS app became a bottleneck. I have the code hosted over at GitLab for that root project, but the direction, vision, and time needed wasn't something I could give at the moment. So the whole thing stalled.

A major part of the time commitment was my naivete in trying to setup a secure NodeJS web app, rather than relying on a proxy like nginx, and when I figured out that wasn't what people did, I was still naive in trying to get my own nginx configuration up and running without learning about nginx configuration.

Eventually, I started playing with docker and docker compose more, and that helped alleviate the necessary environment configuration to get everything working, but I was still writing my own nginx config (and using it by either the Dockerfile COPY, or mounting the config as a volume into the container).

Then I saw the light.

Then I saw the light.
Photo by Jake Givens / Unsplash

I was looking at kubernetes, docker swarm, and Caddy. Caddy is a breath of fresh air if you have ever needed to configure apche or nginx. It handle https automatically via Lets Encrypt, and does the 'right thing'™ as you would expect.

But my voyage into configuration and web server tech didn't stop there. I knew I wanted a Ghost blog, and I had setup a local ghost blog via docker, and I knew I wanted to set up an identical, but separate blog for my wife - and have it all orchestrated with Docker.

Enter traefik.

It supports k8, docker, and many other backends - perfect for my use-case of orchestrating docker containers on a single host (for now), while having an easy path to scale to other machines later. I got a scalable, https configuration in 58 lines. With just two files - seriously, here are the original files used in conjunction with the traefik image that handles incoming traffic to thenewells.us:

docker-compose.yml

version: "3"

services:
  traefik:
    image: traefik:1.3.6-alpine
    command: --docker
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - ./traefik.toml:/traefik.toml
      - ./acme.json:/acme.json
    labels:
      - "traefik.frontend.rule=Host:admin.thenewells.us"
      - "traefik.port=8080"
    networks:
      - web

networks:
  web:
    external: true

traefik.toml

debug = false
checkNewVersion = true
logLevel = "ERROR"
defaultEntryPoints = ["https","http"]

[web]
address = ":8080"
  [web.auth.basic]
  users = ["admin:encryptedadminpass"]

[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.redirect]
    entryPoint = "https"
  [entryPoints.https]
  address = ":443"
  [entryPoints.https.tls]

[retry]

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "thenewells.us"
watch = true
exposedbydefault = false

[acme]
email = "newell.sean.a@gmail.com"
storage = "acme.json"
entryPoint = "https"
onHostRule = true
onDemands = false

Now, to host the blogs, it's just another simple docker-compose file since traefik listens for events on the docker socket. For the two ghost blogs (for my wife and I) there's only one compose file.

docker-compose.yml

version: "3"

services:
  sean-blog:
    image: ghost:1-alpine
    container_name: sean-blog
    restart: always
    networks:
      - web
      - internal
    expose:
      - "2368"
    volumes:
      - snew_ghost_data:/var/lib/ghost/content
    labels:
      - traefik.backend=seanblog
      - traefik.docker.network=web
      - traefik.frontend.rule=Host:sean.thenewells.us
      - traefik.port=2368

  nicki-blog:
    image: ghost:1-alpine
    container_name: nicki-blog
    restart: always
    networks:
      - web
      - internal
    expose:
      - "2368"
    volumes:
      - nicki_ghost_data:/var/lib/ghost/content
    labels:
      - traefik.backend=nickiblog
      - traefik.docker.network=web
      - traefik.frontend.rule=Host:nicki.thenewells.us
      - traefik.port=2368

networks:
  web:
    external: true
  internal:
    external: false

volumes:
  snew_ghost_data:
  nicki_ghost_data:

It's taken way too long, but now that I have this all up and running, I hope to stick with traefik and docker for a while, perhaps dipping more into k8, so I can get more proficient with it.

Happy Coding!