Using Caddy, Letsencrypt wildcard certs and Domeneshop

Here’s how I use Letsencrypt wildcard certificates with my DNS provider, Domeneshop. I build my hosting environment with Docker for portability.

Obtain API token from Domeneshop and store them in a .env file.

# .env
DOMAINNAMESHOP_TOKEN=
DOMAINNAMESHOP_SECRET=

The domainnameshop plugin is not built-in, so we need to build our own Caddy image.

# Dockerfile
FROM caddy:builder-alpine AS builder
RUN xcaddy build \
    --with github.com/caddy-dns/domainnameshop
FROM caddy:latest
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
# compose.yml
services:
  caddy:
    #    image: caddy:latest
    build: .
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./conf:/etc/caddy
      - ./site:/srv
      - ./caddy_data:/data
      - ./caddy_config:/config
    networks:
      - web
    env_file: .env

networks:
  web:
    external: true

Our Caddyfile

# conf/Caddyfile
{
    email my@email.com
    debug
}

*.sub.domain.tld {
    tls {
        dns domainnameshop {
            api_token {env.DOMAINNAMESHOP_TOKEN}
            api_secret {env.DOMAINNAMESHOP_SECRET}
        }
    }
    abort
}

hello.sub.domain.tld {
    respond "Hello world!"
}


foo.sub.domain.tld {
    root /srv/foo.sub.domain.tld
    file_server
}

Place some index.html file in srv/foo.sub.domain.tld

Build and bring up Caddy: docker compose up

Docker containers routing

Note the “web” external network. This allows Caddy to access any local Docker service connected to the “web” network. Let’s add an app, listening on port 3000, connected to “web”:

# compose.yml
services:
  app:
# some app that listens to port 3000
# ...
networks:
  web:
    external: true
# Caddyfile
# ...
myapp.sub.domain.tld {
        reverse_proxy app-app-1:3000
}

Add a comment