Skip to content

Instantly share code, notes, and snippets.

@0xMurage
Last active April 13, 2025 11:19
Show Gist options
  • Save 0xMurage/a171204992f6b16e1b527c9241c9c2c8 to your computer and use it in GitHub Desktop.
Save 0xMurage/a171204992f6b16e1b527c9241c9c2c8 to your computer and use it in GitHub Desktop.
Issuing TLS Certificates on Traefik Using Let's Encrypt Pebble ACME Test Server

Issuing TLS Certificates on Traefik Using Let's Encrypt Pebble ACME Test Server

Prerequisites

  • Docker with the Docker Compose plugin

Steps

1. Download Required Files

Download the following files and place them in your working directory:

  • compose.yaml — a sample production Docker Compose file.
  • compose.override.yaml — includes development configurations. More about how overrides work can be found here.
  • .env — a sample environment file. Docker Compose will automatically use this for interpolating variables in your compose YAML files.

2. Download Pebble Certificate Authority Certificate

Download the Pebble test CA certificate from this link and save it as pebble.minica.pem.

⚠️ Important Notes:

  • The pebble.minica.pem file is required by Traefik to securely communicate with the Pebble ACME server, as Pebble only serves requests over HTTPS.
  • This file acts as the default TLS certificate for the Pebble ACME server.
  • Do not add pebble.minica.pem to your system’s list of trusted root certificates. It is intended only for local development and used internally by Traefik.
  • If needed, you can generate a different CA manually. Refer to the official Pebble documentation for details.

Place the pebble.minica.pem file in the same directory as compose.override.yaml, or adjust the volume mount path in that file to match your setup.


3. Update Environment Variables

Open and edit the .env file with the following changes:

  • Set ACME_CA_SERVER to https://pebble_acme:14000/dir — this is the Pebble container’s internal ACME directory URL.
  • Replace the default domain in WHOAMI_HOST (e.g., example.local) with your own development domain or subdomain.

4. Start the Services

Run the following command to launch the stack:

docker compose up

Once running, Traefik should automatically request and assign a TLS certificate to the configured WHOAMI_HOST.

🔄 Heads-up: Every time the Pebble container restarts, a new certificate will be issued for the domain, subdomain(s), or wildcard you've configured. This is by design—Pebble does not retain state by default and there's no built-in persistence for certificates across container restarts.

TRAEFIK_DEBUG_LEVEL=WARN
ACME_CA_SERVER=https://pebble_acme:14000/dir
[email protected]
WHOAMI_HOST=whoami.local
services:
gateway_proxy:
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./pebble.minica.pem:/pebble.minica.pem
environment:
LEGO_CA_CERTIFICATES: /pebble.minica.pem
LEGO_CA_SERVER_NAME: pebble
networks:
- gateway_proxy
depends_on:
pebble_acme:
condition: service_started
required: true
pebble_acme:
image: ghcr.io/letsencrypt/pebble:latest
expose:
- 14000
environment:
PEBBLE_VA_NOSLEEP: 1
PEBBLE_VA_ALWAYS_VALID: 1
networks:
- gateway_proxy
whoami:
image: traefik/whoami
labels:
- traefik.enable=true
- traefik.http.routers.whoami.rule=HOST(`${WHOAMI_HOST?err}`)
- traefik.http.routers.whoami.middlewares=whoami-https-redirect-middleware
- traefik.http.middlewares.whoami-https-redirect-middleware.redirectscheme.scheme=https
- traefik.http.middlewares.whoami-https-redirect-middleware.redirectscheme.permanent=true
- traefik.http.routers.whoami-secure.rule=Host(`${WHOAMI_HOST?err}`)
- traefik.http.routers.whoami-secure.entrypoints=websecure
- traefik.http.routers.whoami-secure.tls=true
- traefik.http.routers.whoami-secure.tls.certresolver=http-challenge-resolver
networks:
- gateway_proxy
name: gateway
services:
gateway_proxy:
image: traefik:v3.1.0
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- 443:443
- 80:80
networks:
- gateway_proxy
command:
# entry points
- --entrypoints.webinsecure.address=:80
- --entrypoints.websecure.address=:443
# providers
- --providers.docker=true
- --providers.docker.exposedbydefault=false
# TLS cert resolvers: example resolver for staging and dev environments
- --certificatesresolvers.http-challenge-resolver.acme.httpchallenge=true
- --certificatesresolvers.http-challenge-resolver.acme.httpchallenge.entrypoint=webinsecure
- --certificatesresolvers.http-challenge-resolver.acme.caserver=${ACME_CA_SERVER?Err}
- --certificatesresolvers.http-challenge-resolver.acme.email=${ACME_EMAIL?Err}
# miscellaneous
- --log.level=${TRAEFIK_DEBUG_LEVEL:-WARN}
networks:
gateway_proxy:
driver: bridge
name: gateway_proxy
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment