10 KiB
Executable File
Custom DNS Provider Plugins
Charon supports extending its DNS provider capabilities through a plugin system. This guide covers installation and usage of custom DNS provider plugins.
Platform Limitations
Important: Go plugins are only supported on Linux and macOS. Windows users must rely on built-in DNS providers.
- Supported: Linux (x86_64, ARM64), macOS (x86_64, ARM64)
- Not Supported: Windows (any architecture)
Security Considerations
Critical Security Warnings
⚠️ Plugins Execute In-Process
Custom plugins run directly within the Charon process with full access to:
- All system resources and memory
- Database credentials
- API tokens and secrets
- File system access with Charon's permissions
Only install plugins from trusted sources.
Security Best Practices
- Verify Plugin Source: Only download plugins from official repositories or trusted developers
- Check Signatures: Use signature verification (see Configuration section)
- Review Code: If possible, review plugin source code before building
- Secure Permissions: Plugin directory must not be world-writable (enforced automatically)
- Isolate Environment: Consider running Charon in a container with restricted permissions
- Regular Updates: Keep plugins updated to receive security patches
Signature Verification
Configure signature verification in your Charon configuration:
plugins:
directory: /path/to/plugins
allowed_signatures:
powerdns: "sha256:abc123def456..."
custom-provider: "sha256:789xyz..."
To generate a signature for a plugin:
sha256sum powerdns.so
# Output: abc123def456... powerdns.so
Installation
Prerequisites
- Charon must be built with CGO enabled (
CGO_ENABLED=1) - Go version must match between Charon and plugins (critical for compatibility)
- Plugin directory must exist with secure permissions
Installation Steps
-
Obtain the Plugin File
Download the
.sofile for your platform:curl https://example.com/plugins/powerdns-linux-amd64.so -O powerdns.so -
Verify Plugin Integrity (Recommended)
Check the SHA-256 signature:
sha256sum powerdns.so # Compare with published signature -
Copy to Plugin Directory
sudo mkdir -p /etc/charon/plugins sudo cp powerdns.so /etc/charon/plugins/ sudo chmod 755 /etc/charon/plugins/powerdns.so sudo chown root:root /etc/charon/plugins/powerdns.so -
Configure Charon
Edit your Charon configuration file:
plugins: directory: /etc/charon/plugins # Optional: Enable signature verification allowed_signatures: powerdns: "sha256:your-signature-here" -
Restart Charon
sudo systemctl restart charon -
Verify Plugin Loading
Check Charon logs:
sudo journalctl -u charon -f | grep -i pluginExpected output:
INFO Loaded DNS provider plugin type=powerdns name="PowerDNS" version="1.0.0" INFO Loaded 1 external DNS provider plugins (0 failed)
Docker Installation
When running Charon in Docker:
-
Mount Plugin Directory
# docker-compose.yml services: charon: image: charon:latest volumes: - ./plugins:/etc/charon/plugins:ro environment: - PLUGIN_DIR=/etc/charon/plugins -
Build with Plugins
Alternatively, include plugins in your Docker image:
FROM charon:latest COPY plugins/*.so /etc/charon/plugins/
Using Custom Providers
Once a plugin is installed and loaded, it appears in the DNS provider list alongside built-in providers.
Discovering Loaded Plugins via API
Query available provider types to see all registered providers (built-in and plugins):
curl https://charon.example.com/api/v1/dns-providers/types \
-H "Authorization: Bearer YOUR-TOKEN"
Response:
{
"types": [
{
"type": "cloudflare",
"name": "Cloudflare",
"description": "Cloudflare DNS provider",
"documentation_url": "https://developers.cloudflare.com/api/",
"is_built_in": true,
"fields": [...]
},
{
"type": "powerdns",
"name": "PowerDNS",
"description": "PowerDNS Authoritative Server with HTTP API",
"documentation_url": "https://doc.powerdns.com/authoritative/http-api/",
"is_built_in": false,
"fields": [...]
}
]
}
Key fields:
| Field | Description |
|---|---|
is_built_in |
true = compiled into Charon, false = external plugin |
fields |
Credential field specifications for the UI form |
Via Web UI
- Navigate to Settings → DNS Providers
- Click Add Provider
- Select your custom provider from the dropdown
- Enter required credentials
- Click Test Connection to verify
- Save the provider
Via API
curl -X POST https://charon.example.com/api/admin/dns-providers \
-H "Authorization: Bearer YOUR-TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "powerdns",
"credentials": {
"api_url": "https://pdns.example.com:8081",
"api_key": "your-api-key",
"server_id": "localhost"
}
}'
Example: PowerDNS Plugin
The PowerDNS plugin demonstrates a complete DNS provider implementation.
Required Credentials
- API URL: PowerDNS HTTP API endpoint (e.g.,
https://pdns.example.com:8081) - API Key: X-API-Key header value for authentication
Optional Credentials
- Server ID: PowerDNS server identifier (default:
localhost)
Configuration Example
{
"type": "powerdns",
"credentials": {
"api_url": "https://pdns.example.com:8081",
"api_key": "your-secret-key",
"server_id": "ns1"
}
}
Caddy Integration
The plugin automatically configures Caddy's DNS challenge for Let's Encrypt:
{
"name": "powerdns",
"api_url": "https://pdns.example.com:8081",
"api_key": "your-secret-key",
"server_id": "ns1"
}
Timeouts
- Propagation Timeout: 60 seconds
- Polling Interval: 2 seconds
Plugin Management
Listing Loaded Plugins
Via Types Endpoint (Recommended):
Filter for plugins using is_built_in: false:
curl https://charon.example.com/api/v1/dns-providers/types \
-H "Authorization: Bearer YOUR-TOKEN" | jq '.types[] | select(.is_built_in == false)'
Via Plugins Endpoint:
Get detailed plugin metadata including version and author:
curl https://charon.example.com/api/admin/plugins \
-H "Authorization: Bearer YOUR-TOKEN"
Response:
{
"plugins": [
{
"type": "powerdns",
"name": "PowerDNS",
"description": "PowerDNS Authoritative Server with HTTP API",
"version": "1.0.0",
"author": "Charon Community",
"is_built_in": false,
"go_version": "go1.23.4",
"interface_version": "v1"
}
]
}
Reloading Plugins
To reload plugins without restarting Charon:
curl -X POST https://charon.example.com/api/admin/plugins/reload \
-H "Authorization: Bearer YOUR-TOKEN"
Note: Due to Go runtime limitations, plugin code remains in memory even after unloading. A full restart is required to completely unload plugin code.
Unloading a Plugin
curl -X DELETE https://charon.example.com/api/admin/plugins/powerdns \
-H "Authorization: Bearer YOUR-TOKEN"
Troubleshooting
Plugin Not Loading
Check Go Version Compatibility:
go version
# Must match the version shown in plugin metadata
Check Plugin File Permissions:
ls -la /etc/charon/plugins/
# Should be 755 or 644, not world-writable
Check Charon Logs:
sudo journalctl -u charon -n 100 | grep -i plugin
Common Errors
plugin was built with a different version of Go
Cause: Plugin compiled with different Go version than Charon
Solution: Rebuild plugin with matching Go version or rebuild Charon
plugin not in allowlist
Cause: Signature verification enabled, but plugin not in allowed list
Solution: Add plugin signature to allowed_signatures configuration
signature mismatch
Cause: Plugin file signature doesn't match expected value
Solution: Verify plugin file integrity, re-download if corrupted
missing 'Plugin' symbol
Cause: Plugin doesn't export required Plugin variable
Solution: Rebuild plugin with correct exported symbol (see developer guide)
interface version mismatch
Cause: Plugin built against incompatible interface version
Solution: Update plugin to match Charon's interface version
Directory Permission Errors
If Charon reports "directory has insecure permissions":
# Fix directory permissions
sudo chmod 755 /etc/charon/plugins
# Ensure not world-writable
sudo chmod -R o-w /etc/charon/plugins
Performance Considerations
- Startup Time: Plugin loading adds 10-50ms per plugin to startup time
- Memory: Each plugin uses 1-5MB of additional memory
- Runtime: Plugin calls have minimal overhead (nanoseconds)
Compatibility Matrix
| Charon Version | Interface Version | Go Version Required |
|---|---|---|
| 1.0.x | v1 | 1.23.x |
| 1.1.x | v1 | 1.23.x |
| 2.0.x | v2 | 1.24.x |
Always use plugins built for your Charon interface version.
Support
Getting Help
- GitHub Discussions: https://github.com/Wikid82/charon/discussions
- Issue Tracker: https://github.com/Wikid82/charon/issues
- Documentation: https://docs.charon.example.com
Reporting Issues
When reporting plugin issues, include:
- Charon version and Go version
- Plugin name and version
- Operating system and architecture
- Complete error logs
- Plugin metadata (from API response)