中文 | English
This is an event handler plugin designed for Caddy v2 that allows executing external commands when Caddy events occur. This is a true event-triggered plugin, not a monitoring-based one.
- ✅ Event-Triggered: Directly interfaces with Caddy v2's event system, triggering scripts in the synchronous execution path of event occurrence
- ✅ Supports Multiple Caddy Events: Including TLS certificate events, HTTP routing events, etc.
- ✅ Placeholder Replacement: Supports placeholders like
{event.name},{event.data.identifier}, etc. - ✅ Environment Variable Passing: Can pass event data as environment variables to scripts
- ✅ Timeout Control: Can set command execution timeout
- ✅ Working Directory: Can specify the working directory for command execution
- ✅ Shell Support: Supports executing commands through shell
- ✅ Error Handling: Can choose to abort events when commands fail
# Install xcaddy
go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
# Build Caddy with the plugin
xcaddy build --with github.com/RedForestLonvor/caddy-event-trigger=.| Option | Type | Required | Default | Description |
|---|---|---|---|---|
command |
[]string |
Yes* | - | Command array to execute (each element is one argument) |
shell |
string |
No | - | Execute command through specified shell |
shell_args |
[]string |
No | - | Extra arguments passed to the shell before -c |
timeout |
duration |
No | Unlimited | Command execution timeout (e.g.: 30s, 5m, 1h) |
work_dir |
string |
No | Current directory | Working directory for command execution |
env |
map[string]string |
No | - | Additional environment variables (supports placeholders) |
abort_on_error |
bool |
No | false |
Whether to abort event when command fails |
*Note: At least one of command and shell must be set
{
"apps": {
"events": {
"subscriptions": [
{
"events": ["cert_obtained"],
"handlers": [
{
"handler": "exec",
"command": ["./my_script.sh"],
"env": {
"CERT_ID": "{event.data.identifier}",
"CERT_PATH": "{event.data.certificate_path}",
"KEY_PATH": "{event.data.private_key_path}"
},
"timeout": "30s",
"work_dir": "/tmp",
"abort_on_error": false
}
]
}
]
}
}
}{
events {
on cert_obtained exec ./my_script.sh
on cert_obtained exec {
shell /bin/sh
shell_args -euxo pipefail
command ./my_script.sh --cert {event.data.certificate_path}
timeout 30s
work_dir /tmp
env PUSH_URL https://example.com/api
abort_on_error false
}
}
}cert_obtained: Certificate obtained successfully (requires TLS automation configuration)cert_failed: Certificate obtaining failed (requires TLS automation configuration)tls_get_certificate: TLS handshake certificate retrieval
started: Caddy server started*: Wildcard event (matches all events)
- Event types may vary depending on Caddy version and loaded modules
- Some events like
cert_obtainingwere not verified in local testing - You can discover available events by monitoring Caddy logs or using the wildcard
*event
identifier: Certificate identifier (domain name)certificate_path: Certificate file pathprivate_key_path: Private key file pathmetadata_path: Metadata file pathrenewal: Whether it's a renewalremaining: Remaining validity period
{
"apps": {
"events": {
"subscriptions": [
{
"events": ["started"],
"handlers": [
{
"handler": "exec",
"command": ["echo", "Server started at: {event.time}"]
}
]
}
]
},
"http": {
"servers": {
"test": {
"listen": [":8080"],
"routes": [
{
"handle": [
{
"handler": "static_response",
"body": "Hello from Caddy Events!"
}
]
}
]
}
}
}
}
}{
"apps": {
"events": {
"subscriptions": [
{
"events": ["cert_obtained"],
"handlers": [
{
"handler": "exec",
"command": ["./deploy_cert.sh"],
"env": {
"EVENT_TYPE": "{event.name}",
"DOMAIN": "{event.data.identifier}",
"CERT_FILE": "{event.data.certificate_path}",
"KEY_FILE": "{event.data.private_key_path}",
"TIMESTAMP": "{event.time}"
}
}
]
}
]
}
}
}{
"apps": {
"events": {
"subscriptions": [
{
"events": ["started"],
"handlers": [
{
"handler": "exec",
"shell": "/bin/sh",
"shell_args": ["-euxo", "pipefail"],
"command": ["set -e; echo 'Server started'; date | tee /var/log/caddy-start.log"]
}
]
}
]
}
}
}{
"apps": {
"events": {
"subscriptions": [
{
"events": ["cert_obtained"],
"handlers": [
{
"handler": "exec",
"command": ["./deploy_to_cdn.sh"],
"env": {
"DOMAIN": "{event.data.identifier}",
"CERT_FILE": "{event.data.certificate_path}",
"KEY_FILE": "{event.data.private_key_path}"
},
"timeout": "30s",
"abort_on_error": true
}
]
}
]
}
}
}# Create a simple test configuration
cat > test_simple.json << 'EOF'
{
"apps": {
"events": {
"subscriptions": [
{
"events": ["started"],
"handlers": [
{
"handler": "exec",
"command": ["echo", "✅ Plugin working! Event: {event.name}"]
}
]
}
]
},
"http": {
"servers": {
"test": {
"listen": [":8080"],
"routes": [
{
"handle": [
{
"handler": "static_response",
"body": "Test page"
}
]
}
]
}
}
}
}
}
EOF
# Test the plugin
./caddy run --config test_simple.json# Run all tests
bash tests/run_all.sh
# Run individual tests
bash tests/test_env_vars.sh # Environment variables
bash tests/test_shell_mode.sh # Shell mode
bash tests/test_timeout.sh # Timeout control
bash tests/test_abort_on_error.sh # Error handling# Check if the plugin is loaded
./caddy list-modules | grep events
# Should show: events and events.handlers.exec# Clone repository
git clone https://github.com/RedForestLonvor/caddy-event-trigger.git
cd caddy-event-trigger
# Install dependencies
go mod tidy
# Build Caddy with plugin
xcaddy build --with github.com/RedForestLonvor/caddy-event-trigger=.MIT License
Issues and Pull Requests are welcome!
A: Check the following:
- Confirm event name is correct
- Check if script path is correct (recommend using absolute path)
- Check Caddy logs for error messages
- Confirm script has execute permissions
A: Check the following:
- Confirm
envconfiguration is correct - Check placeholder syntax is correct (e.g.:
{event.name}) - Confirm script can receive environment variables
A: Suggestions:
- Use
echocommand to test basic functionality - Check Caddy log output
- Add debug information in scripts
- Use wildcard event
*to capture all events