ACME External Account Binding and Caddy

Hi,

I am trying to create a plugin for Caddy to set Caddy’s acme_ca and acme_eab’s settings

	acme_ca <directory_url>
	acme_eab <key_id> <mac_key>

I have the following plugin

name: acme
version: 1.0.0
patches:
 caddyfile-global: |
    email email@domain.com
    acme_ca https://acme.sectigo.com/v2/InCommonECCOV
    acme_eab key_id hmac_value

Which does put it into the global config correctly I believe

# Global configuration
{
    email email@domain.com
    acme_ca https://acme.sectigo.com/v2/InCommonECCOV
    acme_eab key_id hmac_value
}

but I am getting the following error

caddy_1                      | {"level":"info","ts":1650598776.0691946,"msg":"using provided configuration","config_file":"/etc/caddy/Caddyfile","config_adapter":"caddyfile"}
caddy_1                      | run: adapting config using caddyfile: parsing caddyfile tokens for 'acme_eab': /etc/caddy/Caddyfile:5 - Error during parsing: Wrong argument count or unexpected line ending after 'key_id_value'

Thanks in advance!
Tom

Just wanted to follow up, that I actually got it working.

name: acme
version: 1.0.0
patches:
 caddyfile-global: |
    email email@domain.com
    acme_ca https://acme.sectigo.com/v2/InCommonECCOV
    acme_eab {
       key_id keyvalue
       mac_key hmac value
    }

Circling back to this @regis do you know why the caddy data directory might not actually be bind mounted, even though it is defined in the docker-compose.prod.yml file?

services:
  caddy:
    environment:
      default_site_port: ''
    image: docker.io/caddy:2.4.6
    ports:
    - published: 80
      target: 80
    - published: 443
      target: 443
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/data/caddy:/data:rw
    - /klib/data/nla-openedx/env/apps/caddy/Caddyfile:/etc/caddy/Caddyfile:ro

is what is defined in the docker-compose running config.

But when I go to /klib/data/nla-openedx/data/caddy/caddy/certificates all I see is the directory for acme-v02.api.letsencrypt.org-directory. However, if I go to /data/caddy/certificates after running tutor local exec caddy sh there are two directories “acme-v02.api.letsencrypt.org-directory” and “acme.sectigo.com-v2-incommoneccov” which I expect. I am expecting the sectigo one with the configuration of the plugin from above. So what is happening is everytime the caddy container restarts I get a new certificate request.

Thanks for your help!

More follow up to this, and I am even more confused now

From docker inspect <id_of_caddy_container>

          "Binds": [
                "/klib/data/nla-openedx/env/apps/caddy/Caddyfile:/etc/caddy/Caddyfile:ro",
                "fcf1bc52b587981740e18dae4481e5279fd64dae9e35b0f6c1ba03bed84cfce5:/data:rw",
                "57712742d88c0b41adff87d52eaa5e05718528b1abaa8d27e0910c4191a177f5:/config:rw"
            ],
    "Mounts": [
            {
                "Type": "volume",
                "Name": "57712742d88c0b41adff87d52eaa5e05718528b1abaa8d27e0910c4191a177f5",
                "Source": "/klib/data/docker/volumes/57712742d88c0b41adff87d52eaa5e05718528b1abaa8d27e0910c4191a177f5/_data",
                "Destination": "/config",
                "Driver": "local",
                "Mode": "rw",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "volume",
                "Name": "fcf1bc52b587981740e18dae4481e5279fd64dae9e35b0f6c1ba03bed84cfce5",
                "Source": "/klib/data/docker/volumes/fcf1bc52b587981740e18dae4481e5279fd64dae9e35b0f6c1ba03bed84cfce5/_data",
                "Destination": "/data",
                "Driver": "local",
                "Mode": "rw",
                "RW": true,
                "Propagation": ""
            },
            {
                "Type": "bind",
                "Source": "/klib/data/nla-openedx/env/apps/caddy/Caddyfile",
                "Destination": "/etc/caddy/Caddyfile",
                "Mode": "ro",
                "RW": false,
                "Propagation": "rprivate"
            }
        ],

config files inspect see’s

                "com.docker.compose.project.config_files": "/klib/data/nla-openedx/env/local/docker-compose.yml,/klib/data/nla-openedx/env/local/docker-compose.prod.yml",

cat /klib/data/nla-openedx/env/local/docker-compose.yml output

version: "3.7"
services:

  ############# External services


  mongodb:
    image: docker.io/mongo:4.2.17
    # Use WiredTiger in all environments, just like at edx.org
    command: mongod --nojournal --storageEngine wiredTiger
    restart: unless-stopped
    user: "999:999"
    privileged: false
    volumes:
      - ../../data/mongodb:/data/db
    depends_on:
      - mongodb-permissions
  mongodb-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["999", "/data/db"]
    restart: on-failure
    volumes:
      - ../../data/mongodb:/data/db



  mysql:
    image: docker.io/mysql:5.7.35
    command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
    restart: unless-stopped
    user: "999:999"
    privileged: false
    volumes:
      - ../../data/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: "<password>"
  mysql-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["999", "/var/lib/mysql"]
    restart: on-failure
    volumes:
      - ../../data/mysql:/var/lib/mysql



  elasticsearch:
    image: docker.io/elasticsearch:7.10.1
    environment:
      - cluster.name=openedx
      - bootstrap.memory_lock=true
      - discovery.type=single-node
      - "ES_JAVA_OPTS=-Xms1g -Xmx1g"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    restart: unless-stopped
    user: "1000:1000"
    volumes:
      - ../../data/elasticsearch:/usr/share/elasticsearch/data
    depends_on:
      - elasticsearch-permissions
  elasticsearch-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["1000", "/usr/share/elasticsearch/data"]
    restart: on-failure
    volumes:
      - ../../data/elasticsearch:/usr/share/elasticsearch/data



  redis:
    image: docker.io/redis:6.2.6
    working_dir: /openedx/redis/data
    user: "1000:1000"
    volumes:
      - ../apps/redis/redis.conf:/openedx/redis/config/redis.conf:ro
      - ../../data/redis:/openedx/redis/data
    command: redis-server /openedx/redis/config/redis.conf
    restart: unless-stopped
    depends_on:
      - redis-permissions
  redis-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["1000", "/openedx/redis/data"]
    restart: on-failure
    volumes:
      - ../../data/redis:/openedx/redis/data




  ############# LMS and CMS


  lms:
    image: docker.io/overhangio/openedx:13.1.11
    environment:
      SERVICE_VARIANT: lms
      UWSGI_WORKERS: 2
      SETTINGS: ${TUTOR_EDX_PLATFORM_SETTINGS:-tutor.production}
    restart: unless-stopped
    volumes:
      - ../apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
      - ../apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
      - ../apps/openedx/config:/openedx/config:ro
      - ../../data/lms:/openedx/data
      - ../../data/openedx-media:/openedx/media
    depends_on:
      - lms-permissions
      - mysql
      - elasticsearch
      - mongodb
      - redis


  lms-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["1000", "/openedx/data", "/openedx/media"]
    restart: on-failure
    volumes:
      - ../../data/lms:/openedx/data
      - ../../data/openedx-media:/openedx/media



  cms:
    image: docker.io/overhangio/openedx:13.1.11
    environment:
      SERVICE_VARIANT: cms
      UWSGI_WORKERS: 2
      SETTINGS: ${TUTOR_EDX_PLATFORM_SETTINGS:-tutor.production}
    restart: unless-stopped
    volumes:
      - ../apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
      - ../apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
      - ../apps/openedx/config:/openedx/config:ro
      - ../../data/cms:/openedx/data
      - ../../data/openedx-media:/openedx/media
    depends_on:
      - cms-permissions
      - mysql
      - elasticsearch
      - mongodb
      - redis

      - lms

  cms-permissions:
    image: docker.io/overhangio/openedx-permissions:13.1.11
    command: ["1000", "/openedx/data", "/openedx/media"]
    restart: on-failure
    volumes:
      - ../../data/cms:/openedx/data
      - ../../data/openedx-media:/openedx/media


  ############# LMS and CMS workers


  lms-worker:
    image: docker.io/overhangio/openedx:13.1.11
    environment:
      SERVICE_VARIANT: lms
      SETTINGS: ${TUTOR_EDX_PLATFORM_SETTINGS:-tutor.production}
    command: celery worker --app=lms.celery --loglevel=info --hostname=edx.lms.core.default.%%h --maxtasksperchild=100 --exclude-queues=edx.cms.core.default
    restart: unless-stopped
    volumes:
      - ../apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
      - ../apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
      - ../apps/openedx/config:/openedx/config:ro
      - ../../data/lms:/openedx/data
      - ../../data/openedx-media:/openedx/media
    depends_on:
      - lms



  cms-worker:
    image: docker.io/overhangio/openedx:13.1.11
    environment:
      SERVICE_VARIANT: cms
      SETTINGS: ${TUTOR_EDX_PLATFORM_SETTINGS:-tutor.production}
    command: celery worker --app=cms.celery --loglevel=info --hostname=edx.cms.core.default.%%h --maxtasksperchild 100 --exclude-queues=edx.lms.core.default
    restart: unless-stopped
    volumes:
      - ../apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
      - ../apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
      - ../apps/openedx/config:/openedx/config:ro
      - ../../data/cms:/openedx/data
      - ../../data/openedx-media:/openedx/media
    depends_on:
      - cms

cat /klib/data/nla-openedx/env/local/docker-compose.prod.yml output

version: "3.7"
services:
  # Web proxy for load balancing and SSL termination
  caddy:
    image: docker.io/caddy:2.4.6
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    environment:
      default_site_port: ""
    volumes:
      - ../apps/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
      - ../../data/caddy:/data


  # MFE
  mfe:
      image: docker.io/overhangio/openedx-mfe:13.0.1
      build:
          context: ../plugins/mfe/build/mfe/
      restart: unless-stopped

tutor local dc config output

services:
  caddy:
    environment:
      default_site_port: ''
    image: docker.io/caddy:2.4.6
    ports:
    - published: 80
      target: 80
    - published: 443
      target: 443
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/data/caddy:/data:rw
    - /klib/data/nla-openedx/env/apps/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
  cms:
    depends_on:
    - cms-permissions
    - elasticsearch
    - lms
    - mongodb
    - mysql
    - redis
    environment:
      SERVICE_VARIANT: cms
      SETTINGS: tutor.production
      UWSGI_WORKERS: 2
    image: docker.io/overhangio/openedx:13.1.11
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/env/apps/openedx/config:/openedx/config:ro
    - /klib/data/nla-openedx/data/cms:/openedx/data:rw
    - /klib/data/nla-openedx/env/apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
    - /klib/data/nla-openedx/env/apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  cms-permissions:
    command:
    - '1000'
    - /openedx/data
    - /openedx/media
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/cms:/openedx/data:rw
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  cms-worker:
    command: celery worker --app=cms.celery --loglevel=info --hostname=edx.cms.core.default.%%h
      --maxtasksperchild 100 --exclude-queues=edx.lms.core.default
    depends_on:
    - cms
    environment:
      SERVICE_VARIANT: cms
      SETTINGS: tutor.production
    image: docker.io/overhangio/openedx:13.1.11
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/env/apps/openedx/config:/openedx/config:ro
    - /klib/data/nla-openedx/data/cms:/openedx/data:rw
    - /klib/data/nla-openedx/env/apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
    - /klib/data/nla-openedx/env/apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  elasticsearch:
    depends_on:
    - elasticsearch-permissions
    environment:
      ES_JAVA_OPTS: -Xms1g -Xmx1g
      bootstrap.memory_lock: "true"
      cluster.name: openedx
      discovery.type: single-node
    image: docker.io/elasticsearch:7.10.1
    restart: unless-stopped
    ulimits:
      memlock:
        hard: -1
        soft: -1
    user: 1000:1000
    volumes:
    - /klib/data/nla-openedx/data/elasticsearch:/usr/share/elasticsearch/data:rw
  elasticsearch-permissions:
    command:
    - '1000'
    - /usr/share/elasticsearch/data
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/elasticsearch:/usr/share/elasticsearch/data:rw
  lms:
    depends_on:
    - elasticsearch
    - lms-permissions
    - mongodb
    - mysql
    - redis
    environment:
      SERVICE_VARIANT: lms
      SETTINGS: tutor.production
      UWSGI_WORKERS: 2
    image: docker.io/overhangio/openedx:13.1.11
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/env/apps/openedx/config:/openedx/config:ro
    - /klib/data/nla-openedx/data/lms:/openedx/data:rw
    - /klib/data/nla-openedx/env/apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
    - /klib/data/nla-openedx/env/apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  lms-permissions:
    command:
    - '1000'
    - /openedx/data
    - /openedx/media
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/lms:/openedx/data:rw
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  lms-worker:
    command: celery worker --app=lms.celery --loglevel=info --hostname=edx.lms.core.default.%%h
      --maxtasksperchild=100 --exclude-queues=edx.cms.core.default
    depends_on:
    - lms
    environment:
      SERVICE_VARIANT: lms
      SETTINGS: tutor.production
    image: docker.io/overhangio/openedx:13.1.11
    restart: unless-stopped
    volumes:
    - /klib/data/nla-openedx/env/apps/openedx/config:/openedx/config:ro
    - /klib/data/nla-openedx/data/lms:/openedx/data:rw
    - /klib/data/nla-openedx/env/apps/openedx/settings/cms:/openedx/edx-platform/cms/envs/tutor:ro
    - /klib/data/nla-openedx/env/apps/openedx/settings/lms:/openedx/edx-platform/lms/envs/tutor:ro
    - /klib/data/nla-openedx/data/openedx-media:/openedx/media:rw
  mfe:
    build:
      context: /klib/data/nla-openedx/env/plugins/mfe/build/mfe
    image: docker.io/overhangio/openedx-mfe:13.0.1
    restart: unless-stopped
  mongodb:
    command: mongod --nojournal --storageEngine wiredTiger
    depends_on:
    - mongodb-permissions
    image: docker.io/mongo:4.2.17
    privileged: false
    restart: unless-stopped
    user: 999:999
    volumes:
    - /klib/data/nla-openedx/data/mongodb:/data/db:rw
  mongodb-permissions:
    command:
    - '999'
    - /data/db
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/mongodb:/data/db:rw
  mysql:
    command: mysqld --character-set-server=utf8 --collation-server=utf8_general_ci
    environment:
      MYSQL_ROOT_PASSWORD: <password>
    image: docker.io/mysql:5.7.35
    privileged: false
    restart: unless-stopped
    user: 999:999
    volumes:
    - /klib/data/nla-openedx/data/mysql:/var/lib/mysql:rw
  mysql-permissions:
    command:
    - '999'
    - /var/lib/mysql
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/mysql:/var/lib/mysql:rw
  redis:
    command: redis-server /openedx/redis/config/redis.conf
    depends_on:
    - redis-permissions
    image: docker.io/redis:6.2.6
    restart: unless-stopped
    user: 1000:1000
    volumes:
    - /klib/data/nla-openedx/env/apps/redis/redis.conf:/openedx/redis/config/redis.conf:ro
    - /klib/data/nla-openedx/data/redis:/openedx/redis/data:rw
    working_dir: /openedx/redis/data
  redis-permissions:
    command:
    - '1000'
    - /openedx/redis/data
    image: docker.io/overhangio/openedx-permissions:13.1.11
    restart: on-failure
    volumes:
    - /klib/data/nla-openedx/data/redis:/openedx/redis/data:rw
version: '3.7'

I’m at a loss of why the bind mount isn’t being honored? Does anyone have any ideas?

I ended up doing a down, removing the volumes and recreating every it put the files in the bind mount as expected.

This sometimes happens to me as well. I call it “docker-compose black magic”.