Event dispatching system for Caddy

@francislavoie , on Caddy in Docker - can another container read the certificates? you said:

I’m working on an event dispatching system for Caddy which should eventually make it possible to copy certs for a domain to a well-known location when a cert is issued or renewed, but I don’t have a timeline for when it’ll be ready.

Any news about this?

1 Like

Yep, see here: Global options (Caddyfile) — Caddy Documentation

2 Likes

I put

{
        acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
        #acme_ca https://acme-v02.api.letsencrypt.org/directory
        events {
                on cert_obtained exec /root/certificate_obtained.sh {event.data.identifier} {event.data.certificate_path} {event.data.private_key_path}
        }
        debug
        log {
                output file /var/log/caddy.log
        }
}

on Caddyfile and /root/certificate_obtained.sh contains

#!/bin/ash

if [ "$#" -eq 0 ]
then
  echo "No arguments supplied" > /root/log.txt
  exit 1
fi

echo "`date "+%Y-%m-%d %H:%M:%S"` $1" >> /root/log.txt
echo "`date "+%Y-%m-%d %H:%M:%S"` $2" >> /root/log.txt
echo "`date "+%Y-%m-%d %H:%M:%S"` $3" >> /root/log.txt

just to see if script is being called and his parameters.

Nothing on log file and no /root/log.txt is created (script is not being called?).

I am using Caddy with caddy-dns/cloudflare and mholt/caddy-events-exec

1 Like

Are you actually running Caddy as root or is it running as a systemd service?

You didn’t fill out the help topic template so I’m missing a lot of context here. Please fill out the template if you need help.

1 Like

I just created a simple Caddy module to publish events to a Kafka topic, might be helpful for you. It isn’t certificate issuance specific, but you can read the events and fetch the certificates from storage if you want (i.e with a cert_obtained event).

3 Likes

Sorry, I was in a hurry and thought it just add

        events {
                on cert_obtained exec /root/certificate_obtained.sh {event.data.identifier} {event.data.certificate_path} {event.data.private_key_path}
        }

to /etc/Caddyfile would be enough to dispatch the shell script.
I will got more information and fill the topic template.

@francislavoie , now I think I have put all the necessary information, please let me know if you need any other information.

1. The problem I’m having:

I couldn’t get the script to run when Caddy got the certificates.

2. Error messages and/or full log output:

I didn’t see any error messages.

3. Caddy version:

caddy:~# caddy version
v2.7.3 h1:eMCNjOyMgB5A1KgOzT2dXKR4I0Va+YHCJYC8HHu+DP0=

4. How I installed and ran Caddy:

I’m using an LXC container with Alpine Linux v3.18 running on Proxmox v8.0.4.

a. System environment:

       .hddddddddddddddddddddddh.          root@caddy
      :dddddddddddddddddddddddddd:         ----------
     /dddddddddddddddddddddddddddd/        OS: Alpine Linux v3.18 x86_64
    +dddddddddddddddddddddddddddddd+       Host: Nitro AN515-51 V1.22
  `sdddddddddddddddddddddddddddddddds`     Kernel: 6.2.16-8-pve
 `ydddddddddddd++hdddddddddddddddddddy`    Uptime: 1 hour, 11 mins
.hddddddddddd+`  `+ddddh:-sdddddddddddh.   Packages: 84 (apk)
hdddddddddd+`      `+y:    .sddddddddddh   Shell: ash
ddddddddh+`   `//`   `.`     -sddddddddd   Resolution: 1920x1080
ddddddh+`   `/hddh/`   `:s-    -sddddddd   Terminal: /dev/pts/3
ddddh+`   `/+/dddddh/`   `+s-    -sddddd   CPU: Intel i7-7700HQ (2) @ 3.800GHz
ddd+`   `/o` :dddddddh/`   `oy-    .yddd   Memory: 20MiB / 256MiB
hdddyo+ohddyosdddddddddho+oydddy++ohdddh
.hddddddddddddddddddddddddddddddddddddh.
 `yddddddddddddddddddddddddddddddddddy`
  `sdddddddddddddddddddddddddddddddds`
    +dddddddddddddddddddddddddddddd+
     /dddddddddddddddddddddddddddd/
      :dddddddddddddddddddddddddd:
       .hddddddddddddddddddddddh.

b. Command:

caddy:~# caddy

Caddy run with root user but as is a isolated LXC container this should not be a problem.

c. Service/unit/compose file:

#!/sbin/openrc-run
supervisor=supervise-daemon

name="Caddy web server"
description="Fast, multi-platform web server with automatic HTTPS"
description_checkconfig="Check configuration"
description_reload="Reload configuration without downtime"

: ${caddy_opts:="--config /etc/caddy/Caddyfile --adapter caddyfile"}

command=/usr/sbin/caddy
command_args="run $caddy_opts"
command_user=caddy:caddy
extra_commands="checkconfig"
extra_started_commands="reload"
capabilities="^cap_net_bind_service"

depend() {
        need net localmount
        after firewall
}

checkconfig() {
        ebegin "Checking configuration for $name"
        su ${command_user%:*} -s /bin/sh -c "$command validate $caddy_opts"
        eend $?
}

reload() {
        ebegin "Reloading $name"
        su ${command_user%:*} -s /bin/sh -c "$command reload $caddy_opts"
        eend $?
}

stop_pre() {
        if [ "$RC_CMD" = restart ]; then
                checkconfig || return $?
        fi
}

d. My complete Caddy config:

{
        acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
        #acme_ca https://acme-v02.api.letsencrypt.org/directory
        events {
                on cert_obtained exec /root/certificate_obtained.sh {event.data.identifier} {event.data.certificate_path} {event.data.private_key_path}
        }
        debug
        log {
                output file /var/log/caddy.log
        }
}

(cloudflare) {
        tls username@home.arpa {
                dns cloudflare <secret>
        }
}

(vips_only) {
        @fuck_off_world {
                not remote_ip 10.1.1.0/24 186.222.222.222/32
        }
        respond @fuck_off_world 403
}

adguard.home.arpa {
        import cloudflare
        import vips_only
        reverse_proxy http://adguard.home.arpa:80
}

caddy.home.arpa {
       import cloudflare
       import vips_only
       root * /var/www
       file_server browse
}

ldap.home.arpa {
        import cloudflare
        import vips_only
        respond "LDAP"
}

pve-01.home.arpa {
        import cloudflare
        import vips_only
        reverse_proxy https://pve-01.home.arpa:8006 {
                transport http {
                        tls_insecure_skip_verify
                }
        }
}

*.caddy.home.arpa {
        import cloudflare
        import vips_only

        @adguard host adguard.caddy.home.arpa
        handle @adguard {
                reverse_proxy http://adguard.home.arpa:80
        }

        @pve-01 host pve-01.caddy.home.arpa
        handle @pve-01 {
                reverse_proxy https://pve-01.home.arpa:8006 {
                        transport http {
                                tls_insecure_skip_verify
                        }
                }
        }

        # Fallback for otherwise unhandled domains
        handle {
                abort
        }
}

5. Links to relevant resources:

At first I want to do two things:

  • copy certificate pve-01.home.arpa to host running Proxmox
  • copy certificate ldap.home.arpa to LXC container running OpenLDAP

Afterwards, whenever Caddy renews the certificates, the script must run and copy the new certificates.

Important:
I used the apk add caddy command to install Caddy using Alpine’s package manager and then I replaced the Caddy executable in /usr/sbin/caddy with the one I downloaded from the site* already with the “caddy-dns” plugins /cloudflare" and “mholt/caddy-events-exec” (indicated on the Global options (Caddyfile) — Caddy Documentation page).

*wget -q -O /usr/sbin/caddy "https://caddyserver.com/api/download?os=linux&arch=amd64&p=github.com%2Fcaddy-dns%2Fcloudflare&p=github.com%2Fmholt%2Fcaddy-events-exec"

So Caddy is running as the caddy user and not as root. Probably makes sense that it can’t run commands in /root since those are owned by root.

Move the commands to /etc/caddy or something instead.

You were right, it was problem with permissions.

I thought Caddy was running as root user.

I first moved the certificate_obtained.sh file to /etc/caddy/ and then chown caddy:caddy in /etc/caddy/.

It didn’t seem to work but that’s because for testing purposes I just wanted to create a log file with the received parameters.

It was necessary to change the owner of the /etc/caddy/ folder to caddy for the script to run and create the log file.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.