Files
Charon/docs/features/custom-plugins.md
GitHub Actions b86aa3921b feat(dns): add custom DNS provider plugin system
- Add plugin interface with lifecycle hooks (Init/Cleanup)
- Implement thread-safe provider registry
- Add plugin loader with SHA-256 signature verification
- Migrate 10 built-in providers to registry pattern
- Add multi-credential support to plugin interface
- Create plugin management UI with enable/disable controls
- Add dynamic credential fields based on provider metadata
- Include PowerDNS example plugin
- Add comprehensive user & developer documentation
- Fix frontend test hang (33min → 1.5min, 22x faster)

Platform: Linux/macOS only (Go plugin limitation)
Security: Signature verification, directory permission checks

Backend coverage: 85.1%
Frontend coverage: 85.31%

Closes: DNS Challenge Future Features - Phase 5
2026-01-07 02:54:01 +00:00

8.7 KiB

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

  1. Verify Plugin Source: Only download plugins from official repositories or trusted developers
  2. Check Signatures: Use signature verification (see Configuration section)
  3. Review Code: If possible, review plugin source code before building
  4. Secure Permissions: Plugin directory must not be world-writable (enforced automatically)
  5. Isolate Environment: Consider running Charon in a container with restricted permissions
  6. 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

  1. Obtain the Plugin File

    Download the .so file for your platform:

    wget https://example.com/plugins/powerdns-linux-amd64.so -O powerdns.so
    
  2. Verify Plugin Integrity (Recommended)

    Check the SHA-256 signature:

    sha256sum powerdns.so
    # Compare with published signature
    
  3. 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
    
  4. Configure Charon

    Edit your Charon configuration file:

    plugins:
      directory: /etc/charon/plugins
      # Optional: Enable signature verification
      allowed_signatures:
        powerdns: "sha256:your-signature-here"
    
  5. Restart Charon

    sudo systemctl restart charon
    
  6. Verify Plugin Loading

    Check Charon logs:

    sudo journalctl -u charon -f | grep -i plugin
    

    Expected 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:

  1. Mount Plugin Directory

    # docker-compose.yml
    services:
      charon:
        image: charon:latest
        volumes:
          - ./plugins:/etc/charon/plugins:ro
        environment:
          - PLUGIN_DIR=/etc/charon/plugins
    
  2. 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.

Via Web UI

  1. Navigate to SettingsDNS Providers
  2. Click Add Provider
  3. Select your custom provider from the dropdown
  4. Enter required credentials
  5. Click Test Connection to verify
  6. 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

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

Reporting Issues

When reporting plugin issues, include:

  1. Charon version and Go version
  2. Plugin name and version
  3. Operating system and architecture
  4. Complete error logs
  5. Plugin metadata (from API response)

See Also