Recommended way to support www and naked domain with Cookieplone

Working with Cookieplone what's the right way to support www and the naked domain in the Traefik setup with varnish?

I had the issue with my recent setup from 2025 and newer Cookieplone devops templates.

Prerequisites

A DNS Setup pointing at the IP of the server both from naked domain example.com and subdomain www.example.com

A Cookieplone devops setup using Cookieplone (1.0.0) and cookieplone-templates (1ee1cfe) or later using the devops option with Traefik with the following default setup in devops/stacks/project-title.example.com.yml Only traefik part, rest omitted.

It worked for me with a project setup created by Cookieplone 0.9.7 and cookieplone-templates (83b50c6).

---
version: '3.8'

services:
  traefik:
    image: traefik:v2.11

    ports:
      - 80:80
      - 443:443

    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 5s
        order: start-first
      labels:
        - traefik.enable=true
        - traefik.constraint-label=public
        - traefik.http.services.traefik-public.loadbalancer.server.port=8000
        ## Basic Authentication
        ### Note: all dollar signs in the hash need to be doubled for escaping.
        ### To create user:password pair, it's possible to use this command:
        ### echo $(htpasswd -nb user password) | sed -e s/\\$/\\$\\$/g
        ### Defaults to admin:admin
        #- traefik.http.middlewares.admin-auth.basicauth.users=admin:$$apr1$$uZPT5Fgu$$AmlIdamxT5ipBvPlsdfD70
        #- traefik.http.routers.traefik-public-https.rule=Host(`traefik-project-dummy.example.com`)
        #- traefik.http.routers.traefik-public-https.entrypoints=https
        #- traefik.http.routers.traefik-public-https.tls=true
        #- traefik.http.routers.traefik-public-https.service=api@internal
        #- traefik.http.routers.traefik-public-https.middlewares=admin-auth

        # GENERIC MIDDLEWARES
        - traefik.http.middlewares.https-redirect.redirectscheme.scheme=https
        - traefik.http.middlewares.https-redirect.redirectscheme.permanent=true
        - traefik.http.middlewares.gzip.compress=true
        - traefik.http.middlewares.gzip.compress.excludedcontenttypes=image/png, image/jpeg, font/woff2

        # GENERIC ROUTERS
        - traefik.http.routers.generic-https-redirect.entrypoints=http
        - traefik.http.routers.generic-https-redirect.rule=HostRegexp(`{host:.*}`)
        - traefik.http.routers.generic-https-redirect.priority=1
        - traefik.http.routers.generic-https-redirect.middlewares=https-redirect

# acsr note: additions goes here below

    volumes:

# unchanged below
...

I ran into issues when using approaches published elsewhere here (mentioned above) when the letsencrypt certificates were not in effect, when the www prefix was hit on http and a certificate warning blocked the further redirection process.

Solution is resort the stuff and use a different order.

additions to the stacks/*.yml going into the labels just below the existing stuff (as marked above in the example):slight_smile:


        # GENERIC MIDDLEWARES          ✅ keep as-is
...

        # GENERIC ROUTERS              ✅ keep as-is
...

        # Explicit www router → forces cert provisioning at startup
        - traefik.http.routers.wwwsecure-explicit.rule=Host(`www.example.com`)
        - traefik.http.routers.wwwsecure-explicit.entrypoints=https
        - traefik.http.routers.wwwsecure-explicit.tls=true
        - traefik.http.routers.wwwsecure-explicit.tls.certresolver=le
        - traefik.http.routers.wwwsecure-explicit.middlewares=wwwtohttps
        - traefik.http.routers.wwwsecure-explicit.service=svc-varnish
        - traefik.http.routers.wwwsecure-explicit.priority=10

        # HostRegexp catchall as fallback
        - traefik.http.routers.wwwsecure-catchall.rule=HostRegexp(`{host:(www\.).+}`)
        - traefik.http.routers.wwwsecure-catchall.entrypoints=https
        - traefik.http.routers.wwwsecure-catchall.tls=true
        - traefik.http.routers.wwwsecure-catchall.tls.certresolver=le
        - traefik.http.routers.wwwsecure-catchall.middlewares=wwwtohttps
        - traefik.http.routers.wwwsecure-catchall.service=svc-varnish
        - traefik.http.routers.wwwsecure-catchall.priority=5

        # Strip www and redirect to naked domain
        - traefik.http.middlewares.wwwtohttps.redirectregex.regex=^https?://(?:www\.)?(.+)
        - traefik.http.middlewares.wwwtohttps.redirectregex.replacement=https://$${1}
        - traefik.http.middlewares.wwwtohttps.redirectregex.permanent=true
        
        # Or if you prefer www as the canonical (naked → www), flip the regex:
        # - traefik.http.middlewares.trim_www.redirectregex.regex=^https://(?!www\.)(.+)
        # - traefik.http.middlewares.trim_www.redirectregex.replacement=https://www.$${1}
        # - traefik.http.middlewares.trim_www.redirectregex.permanent=true

IMPORTANT: Make sure the DNS A-Record (or CNAME) for the secondary domain www.example.com is in place during deployment, or the fetching of the letsencrypt cert will fail!

Note: The commented out section for the other order is a suggestion and was not tested in production

When confirmed by a second party, this should go into the cookieplone templates as options or at least into the docs. It worked for me.

Warning: NOT tested for possible inefficiencies in the routing and redirection. I needed just something that worked NOW.