chore: clean .gitignore cache
This commit is contained in:
@@ -1,97 +0,0 @@
|
||||
---
|
||||
title: Access Control Lists (ACLs)
|
||||
description: Define exactly who can access what with fine-grained rules
|
||||
---
|
||||
|
||||
# Access Control Lists (ACLs)
|
||||
|
||||
Define exactly who can access what. Block specific countries, allow only certain IP ranges, or require authentication for sensitive applications. Fine-grained rules give you complete control.
|
||||
|
||||
## Overview
|
||||
|
||||
Access Control Lists let you create granular rules that determine who can reach your proxied services. Rules are evaluated in order, and the first matching rule determines whether access is allowed or denied.
|
||||
|
||||
ACL capabilities:
|
||||
|
||||
- **IP Allowlists** — Only permit specific IPs or ranges
|
||||
- **IP Blocklists** — Deny access from known bad actors
|
||||
- **Country/Geo Blocking** — Restrict access by geographic location
|
||||
- **CIDR Support** — Define rules using network ranges (e.g., `192.168.1.0/24`)
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Compliance** — Restrict access to specific regions for data sovereignty
|
||||
- **Security** — Block high-risk countries or known malicious networks
|
||||
- **Internal Services** — Limit access to corporate IP ranges
|
||||
- **Layered Defense** — Combine with WAF and CrowdSec for comprehensive protection
|
||||
|
||||
## Configuration
|
||||
|
||||
### Creating an Access List
|
||||
|
||||
1. Navigate to **Access Lists** in the sidebar
|
||||
2. Click **Add Access List**
|
||||
3. Provide a descriptive name (e.g., "Office IPs Only")
|
||||
4. Configure your rules
|
||||
|
||||
### Rule Types
|
||||
|
||||
#### IP Range Filtering
|
||||
|
||||
Add specific IPs or CIDR ranges:
|
||||
|
||||
```text
|
||||
Allow: 192.168.1.0/24 # Allow entire subnet
|
||||
Allow: 10.0.0.5 # Allow single IP
|
||||
Deny: 0.0.0.0/0 # Deny everything else
|
||||
```
|
||||
|
||||
Rules are processed top-to-bottom. Place more specific rules before broader ones.
|
||||
|
||||
#### Country/Geo Blocking
|
||||
|
||||
Block or allow traffic by country:
|
||||
|
||||
1. In the Access List editor, go to **Country Rules**
|
||||
2. Select countries to **Allow** or **Deny**
|
||||
3. Choose default action for unlisted countries
|
||||
|
||||
Common configurations:
|
||||
|
||||
- **Allow only your country** — Whitelist your country, deny all others
|
||||
- **Block high-risk regions** — Deny specific countries, allow rest
|
||||
- **Compliance zones** — Allow only EU countries for GDPR compliance
|
||||
|
||||
### Applying to Proxy Hosts
|
||||
|
||||
1. Edit your proxy host
|
||||
2. Go to the **Access** tab
|
||||
3. Select your Access List from the dropdown
|
||||
4. Save changes
|
||||
|
||||
Each proxy host can have one Access List assigned. Create multiple lists for different access patterns.
|
||||
|
||||
## Rule Evaluation Order
|
||||
|
||||
```text
|
||||
1. Check IP allowlist → Allow if matched
|
||||
2. Check IP blocklist → Deny if matched
|
||||
3. Check country rules → Allow/Deny based on geo
|
||||
4. Apply default action
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
| Scenario | Recommendation |
|
||||
|----------|----------------|
|
||||
| Internal admin panels | Allowlist office/VPN IPs only |
|
||||
| Public websites | Use geo-blocking for high-risk regions |
|
||||
| API endpoints | Combine IP rules with rate limiting |
|
||||
| Development servers | Restrict to developer IPs |
|
||||
|
||||
## Related
|
||||
|
||||
- [Proxy Hosts](./proxy-hosts.md) — Apply access lists to services
|
||||
- [CrowdSec Integration](./crowdsec.md) — Automatic threat-based blocking
|
||||
- [Rate Limiting](./rate-limiting.md) — Limit request frequency
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,161 +0,0 @@
|
||||
---
|
||||
title: REST API
|
||||
description: Comprehensive REST API for automation and integrations
|
||||
---
|
||||
|
||||
# REST API
|
||||
|
||||
Automate everything. Charon's comprehensive REST API lets you manage hosts, certificates, security rules, and settings programmatically. Perfect for CI/CD pipelines, Infrastructure as Code, or custom integrations.
|
||||
|
||||
## Overview
|
||||
|
||||
The REST API provides full control over Charon's functionality through HTTP endpoints. All responses are JSON-formatted, and the API follows RESTful conventions for resource management.
|
||||
|
||||
**Base URL**: `http://your-charon-instance:81/api`
|
||||
|
||||
### Authentication
|
||||
|
||||
All API requests require a Bearer token. Generate tokens in **Settings → API Tokens**.
|
||||
|
||||
```bash
|
||||
# Include in all requests
|
||||
Authorization: Bearer your-api-token-here
|
||||
```
|
||||
|
||||
Tokens support granular permissions:
|
||||
- **Read-only**: View configurations without modification
|
||||
- **Full access**: Complete CRUD operations
|
||||
- **Scoped**: Limit to specific resource types
|
||||
|
||||
## Why Use the API?
|
||||
|
||||
| Use Case | Benefit |
|
||||
|----------|---------|
|
||||
| **CI/CD Pipelines** | Automatically create proxy hosts for staging/preview deployments |
|
||||
| **Infrastructure as Code** | Version control your Charon configuration |
|
||||
| **Custom Dashboards** | Build monitoring integrations |
|
||||
| **Bulk Operations** | Manage hundreds of hosts programmatically |
|
||||
| **GitOps Workflows** | Sync configuration from Git repositories |
|
||||
|
||||
## Key Endpoints
|
||||
|
||||
### Proxy Hosts
|
||||
|
||||
```bash
|
||||
# List all proxy hosts
|
||||
curl -X GET "http://charon:81/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Create a proxy host
|
||||
curl -X POST "http://charon:81/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"domain_names": ["app.example.com"],
|
||||
"forward_host": "10.0.0.5",
|
||||
"forward_port": 3000,
|
||||
"ssl_forced": true,
|
||||
"certificate_id": 1
|
||||
}'
|
||||
|
||||
# Update a proxy host
|
||||
curl -X PUT "http://charon:81/api/nginx/proxy-hosts/1" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"forward_port": 8080}'
|
||||
|
||||
# Delete a proxy host
|
||||
curl -X DELETE "http://charon:81/api/nginx/proxy-hosts/1" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
### SSL Certificates
|
||||
|
||||
```bash
|
||||
# List certificates
|
||||
curl -X GET "http://charon:81/api/nginx/certificates" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Request new Let's Encrypt certificate
|
||||
curl -X POST "http://charon:81/api/nginx/certificates" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"provider": "letsencrypt",
|
||||
"domain_names": ["secure.example.com"],
|
||||
"meta": {"dns_challenge": true, "dns_provider": "cloudflare"}
|
||||
}'
|
||||
```
|
||||
|
||||
### DNS Providers
|
||||
|
||||
```bash
|
||||
# List configured DNS providers
|
||||
curl -X GET "http://charon:81/api/nginx/dns-providers" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Add a DNS provider (for DNS-01 challenges)
|
||||
curl -X POST "http://charon:81/api/nginx/dns-providers" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"name": "Cloudflare Production",
|
||||
"acme_dns_provider": "cloudflare",
|
||||
"meta": {"CF_API_TOKEN": "your-cloudflare-token"}
|
||||
}'
|
||||
```
|
||||
|
||||
### Security Settings
|
||||
|
||||
```bash
|
||||
# Get WAF status
|
||||
curl -X GET "http://charon:81/api/security/waf" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
|
||||
# Enable WAF for a host
|
||||
curl -X PUT "http://charon:81/api/nginx/proxy-hosts/1" \
|
||||
-H "Authorization: Bearer $TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"waf_enabled": true, "waf_mode": "block"}'
|
||||
|
||||
# List CrowdSec decisions
|
||||
curl -X GET "http://charon:81/api/security/crowdsec/decisions" \
|
||||
-H "Authorization: Bearer $TOKEN"
|
||||
```
|
||||
|
||||
## CI/CD Integration Example
|
||||
|
||||
### GitHub Actions
|
||||
|
||||
```yaml
|
||||
- name: Create Preview Environment
|
||||
run: |
|
||||
curl -X POST "${{ secrets.CHARON_URL }}/api/nginx/proxy-hosts" \
|
||||
-H "Authorization: Bearer ${{ secrets.CHARON_TOKEN }}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"domain_names": ["pr-${{ github.event.number }}.preview.example.com"],
|
||||
"forward_host": "${{ steps.deploy.outputs.ip }}",
|
||||
"forward_port": 3000
|
||||
}'
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
The API returns standard HTTP status codes:
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `200` | Success |
|
||||
| `201` | Resource created |
|
||||
| `400` | Invalid request body |
|
||||
| `401` | Invalid or missing token |
|
||||
| `403` | Insufficient permissions |
|
||||
| `404` | Resource not found |
|
||||
| `500` | Server error |
|
||||
|
||||
## Related
|
||||
|
||||
- [Backup & Restore](backup-restore.md) - API-managed backups
|
||||
- [SSL Certificates](ssl-certificates.md) - Certificate automation
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,637 +0,0 @@
|
||||
# Audit Logging
|
||||
|
||||
Charon's audit logging system provides comprehensive tracking of all DNS provider credential operations, giving you complete visibility into who accessed, modified, or used sensitive credentials.
|
||||
|
||||
## Overview
|
||||
|
||||
Audit logging automatically records security-sensitive operations for compliance, security monitoring, and troubleshooting. Every action involving DNS provider credentials is tracked with full context including:
|
||||
|
||||
- **Who**: User ID or system actor
|
||||
- **What**: Specific action performed (create, update, delete, test, decrypt)
|
||||
- **When**: Precise timestamp
|
||||
- **Where**: IP address and user agent
|
||||
- **Why**: Full event context and metadata
|
||||
|
||||
### Why Audit Logging Matters
|
||||
|
||||
- **Security Monitoring**: Detect unauthorized access or suspicious patterns
|
||||
- **Compliance**: Meet SOC 2, GDPR, HIPAA, and PCI-DSS requirements for audit trails
|
||||
- **Troubleshooting**: Diagnose certificate issuance failures retrospectively
|
||||
- **Accountability**: Track all credential operations with full attribution
|
||||
|
||||
## Accessing Audit Logs
|
||||
|
||||
### Navigation
|
||||
|
||||
1. Navigate to **Security** in the main menu
|
||||
2. Click **Audit Logs** in the submenu
|
||||
3. The audit log table displays recent events with pagination
|
||||
|
||||
### UI Overview
|
||||
|
||||
The audit log interface consists of:
|
||||
|
||||
- **Data Table**: Lists all audit events with key information
|
||||
- **Filter Bar**: Refine results by date, category, actor, action, or resource
|
||||
- **Search Box**: Full-text search across event details
|
||||
- **Details Modal**: View complete event information with related events
|
||||
- **Export Button**: Download audit logs as CSV for external analysis
|
||||
|
||||
## Understanding Audit Events
|
||||
|
||||
### Event Categories
|
||||
|
||||
All audit events are categorized for easy filtering:
|
||||
|
||||
| Category | Description | Example Events |
|
||||
|----------|-------------|----------------|
|
||||
| `dns_provider` | DNS provider credential operations | Create, update, delete, test credentials |
|
||||
| `certificate` | Certificate lifecycle events | Issuance, renewal, failure |
|
||||
| `system` | System-level operations | Automated credential decryption |
|
||||
|
||||
### Event Actions
|
||||
|
||||
Charon logs the following DNS provider operations:
|
||||
|
||||
| Action | When It's Logged | Details Captured |
|
||||
|--------|------------------|------------------|
|
||||
| `dns_provider_create` | New DNS provider added | Provider name, type, is_default flag |
|
||||
| `dns_provider_update` | Provider settings changed | Changed fields, old values, new values |
|
||||
| `dns_provider_delete` | Provider removed | Provider name, type, whether credentials existed |
|
||||
| `credential_test` | Credentials tested via API | Provider name, test result, error message |
|
||||
| `credential_decrypt` | Caddy reads credentials for cert issuance | Provider name, purpose (certificate_issuance) |
|
||||
| `certificate_issued` | Certificate successfully issued | Domain, provider used, success/failure status |
|
||||
|
||||
## Filtering and Search
|
||||
|
||||
### Date Range Filter
|
||||
|
||||
Filter events by time period:
|
||||
|
||||
1. Click the **Date Range** dropdown
|
||||
2. Select a preset (**Last 24 Hours**, **Last 7 Days**, **Last 30 Days**, **Last 90 Days**)
|
||||
3. Or select **Custom Range** and pick specific start and end dates
|
||||
4. Results update automatically
|
||||
|
||||
### Category Filter
|
||||
|
||||
Filter by event category:
|
||||
|
||||
1. Click the **Category** dropdown
|
||||
2. Select one or more categories (dns_provider, certificate, system)
|
||||
3. Only events matching selected categories will be displayed
|
||||
|
||||
### Actor Filter
|
||||
|
||||
Filter by who performed the action:
|
||||
|
||||
1. Click the **Actor** dropdown
|
||||
2. Select a user from the list (shows both username and user ID)
|
||||
3. Select **System** to see automated operations
|
||||
4. View only events from the selected actor
|
||||
|
||||
### Action Filter
|
||||
|
||||
Filter by specific operation type:
|
||||
|
||||
1. Click the **Action** dropdown
|
||||
2. Select one or more actions (create, update, delete, test, decrypt)
|
||||
3. Results show only the selected action types
|
||||
|
||||
### Resource Filter
|
||||
|
||||
Filter by specific DNS provider:
|
||||
|
||||
1. Click the **Resource** dropdown
|
||||
2. Select a DNS provider from the list
|
||||
3. View only events related to that provider
|
||||
|
||||
### Search
|
||||
|
||||
Perform free-text search across all event details:
|
||||
|
||||
1. Enter search terms in the **Search** box
|
||||
2. Press Enter or click the search icon
|
||||
3. Results include events where the search term appears in:
|
||||
- Provider name
|
||||
- Event details JSON
|
||||
- IP addresses
|
||||
- User agents
|
||||
|
||||
### Clearing Filters
|
||||
|
||||
- Click the **Clear Filters** button to reset all filters
|
||||
- Filters persist while navigating within the audit log page
|
||||
- Filters reset when you leave and return to the page
|
||||
|
||||
## Viewing Event Details
|
||||
|
||||
### Opening the Details Modal
|
||||
|
||||
1. Click any row in the audit log table
|
||||
2. Or click the **View Details** button on the right side of a row
|
||||
|
||||
### Details Modal Contents
|
||||
|
||||
The details modal displays:
|
||||
|
||||
- **Event UUID**: Unique identifier for the event
|
||||
- **Timestamp**: Exact date and time (ISO 8601 format)
|
||||
- **Actor**: User ID or "system" for automated operations
|
||||
- **Action**: Operation performed
|
||||
- **Category**: Event category (dns_provider, certificate, etc.)
|
||||
- **Resource**: DNS provider name and UUID
|
||||
- **IP Address**: Client IP that initiated the operation
|
||||
- **User Agent**: Browser or API client information
|
||||
- **Full Details**: Complete JSON payload with all event metadata
|
||||
|
||||
### Understanding the Details JSON
|
||||
|
||||
The details field contains a JSON object with event-specific information:
|
||||
|
||||
**Create Event Example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Cloudflare Production",
|
||||
"type": "cloudflare",
|
||||
"is_default": true
|
||||
}
|
||||
```
|
||||
|
||||
**Update Event Example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"changed_fields": ["credentials", "is_default"],
|
||||
"old_values": {
|
||||
"is_default": false
|
||||
},
|
||||
"new_values": {
|
||||
"is_default": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Test Event Example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"test_result": "success",
|
||||
"response_time_ms": 342
|
||||
}
|
||||
```
|
||||
|
||||
**Decrypt Event Example:**
|
||||
|
||||
```json
|
||||
{
|
||||
"purpose": "certificate_issuance",
|
||||
"success": true
|
||||
}
|
||||
```
|
||||
|
||||
### Finding Related Events
|
||||
|
||||
1. In the details modal, note the **Resource UUID**
|
||||
2. Click **View Related Events** to see all events for this resource
|
||||
3. Or manually filter by Resource UUID using the filter bar
|
||||
|
||||
## Exporting Audit Logs
|
||||
|
||||
### CSV Export
|
||||
|
||||
Export audit logs for external analysis, compliance reporting, or archival:
|
||||
|
||||
1. Apply desired filters to narrow down events
|
||||
2. Click the **Export CSV** button
|
||||
3. A CSV file downloads with the following columns:
|
||||
- Timestamp
|
||||
- Actor
|
||||
- Action
|
||||
- Event Category
|
||||
- Resource ID
|
||||
- Resource UUID
|
||||
- IP Address
|
||||
- User Agent
|
||||
- Details
|
||||
|
||||
### Export Use Cases
|
||||
|
||||
- **Compliance Reports**: Generate quarterly audit reports for SOC 2
|
||||
- **Security Analysis**: Import into SIEM tools for threat detection
|
||||
- **Forensics**: Investigate security incidents with complete audit trail
|
||||
- **Backup**: Archive audit logs beyond the retention period
|
||||
|
||||
### Export Limitations
|
||||
|
||||
- Exports are limited to 10,000 events per download
|
||||
- For larger exports, use date range filters to split into multiple files
|
||||
- Exports respect all active filters (date, category, actor, etc.)
|
||||
|
||||
## Event Scenarios
|
||||
|
||||
### Scenario 1: New DNS Provider Setup
|
||||
|
||||
**Timeline:**
|
||||
|
||||
1. User `admin@example.com` logs in from `192.168.1.100`
|
||||
2. Navigates to DNS Providers page
|
||||
3. Clicks "Add DNS Provider"
|
||||
4. Fills in Cloudflare credentials and clicks Save
|
||||
|
||||
**Audit Log Entries:**
|
||||
|
||||
```
|
||||
2026-01-03 14:23:45 | user:5 | dns_provider_create | dns_provider | {"name":"Cloudflare Prod","type":"cloudflare","is_default":true}
|
||||
```
|
||||
|
||||
### Scenario 2: Credential Testing
|
||||
|
||||
**Timeline:**
|
||||
|
||||
1. User tests existing provider credentials
|
||||
2. API validation succeeds
|
||||
|
||||
**Audit Log Entries:**
|
||||
|
||||
```
|
||||
2026-01-03 14:25:12 | user:5 | credential_test | dns_provider | {"test_result":"success","response_time_ms":342}
|
||||
```
|
||||
|
||||
### Scenario 3: Certificate Issuance
|
||||
|
||||
**Timeline:**
|
||||
|
||||
1. Caddy detects new host requires SSL certificate
|
||||
2. Caddy decrypts DNS provider credentials
|
||||
3. ACME DNS-01 challenge completes successfully
|
||||
4. Certificate issued
|
||||
|
||||
**Audit Log Entries:**
|
||||
|
||||
```
|
||||
2026-01-03 14:30:00 | system | credential_decrypt | dns_provider | {"purpose":"certificate_issuance","success":true}
|
||||
2026-01-03 14:30:45 | system | certificate_issued | certificate | {"domain":"app.example.com","provider":"cloudflare","result":"success"}
|
||||
```
|
||||
|
||||
### Scenario 4: Provider Update
|
||||
|
||||
**Timeline:**
|
||||
|
||||
1. User updates default provider setting
|
||||
2. API saves changes
|
||||
|
||||
**Audit Log Entries:**
|
||||
|
||||
```
|
||||
2026-01-03 15:00:22 | user:5 | dns_provider_update | dns_provider | {"changed_fields":["is_default"],"old_values":{"is_default":false},"new_values":{"is_default":true}}
|
||||
```
|
||||
|
||||
### Scenario 5: Provider Deletion
|
||||
|
||||
**Timeline:**
|
||||
|
||||
1. User deletes unused DNS provider
|
||||
2. Credentials are securely wiped
|
||||
|
||||
**Audit Log Entries:**
|
||||
|
||||
```
|
||||
2026-01-03 16:45:33 | user:5 | dns_provider_delete | dns_provider | {"name":"Old Provider","type":"route53","had_credentials":true}
|
||||
```
|
||||
|
||||
## Viewing Provider-Specific Audit History
|
||||
|
||||
### From DNS Provider Page
|
||||
|
||||
1. Navigate to **Settings** → **DNS Providers**
|
||||
2. Click on any DNS provider to open the edit form
|
||||
3. Click the **View Audit History** button
|
||||
4. See all audit events for this specific provider
|
||||
|
||||
### API Endpoint
|
||||
|
||||
You can also retrieve provider-specific audit logs via API:
|
||||
|
||||
```bash
|
||||
GET /api/v1/dns-providers/:id/audit-logs?page=1&limit=50
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Questions
|
||||
|
||||
**Q: Why don't I see audit logs from before today?**
|
||||
|
||||
A: Audit logging was introduced in Charon v1.2.0. Only events after the feature was enabled are logged. Previous operations are not retroactively logged.
|
||||
|
||||
**Q: How long are audit logs kept?**
|
||||
|
||||
A: By default, audit logs are retained for 90 days. After 90 days, logs are automatically deleted to prevent unbounded database growth. Administrators can configure the retention period via environment variable `AUDIT_LOG_RETENTION_DAYS`.
|
||||
|
||||
**Q: Can audit logs be modified or deleted?**
|
||||
|
||||
A: No. Audit logs are immutable and append-only. Only the automatic cleanup job (based on retention policy) can delete logs. This ensures audit trail integrity for compliance purposes.
|
||||
|
||||
**Q: What happens if audit logging fails?**
|
||||
|
||||
A: Audit logging is non-blocking and asynchronous. If the audit log channel is full or the database is temporarily unavailable, the event is dropped but the primary operation (e.g., creating a DNS provider) succeeds. Dropped events are logged to the application log for monitoring.
|
||||
|
||||
**Q: Do audit logs include credential values?**
|
||||
|
||||
A: No. Audit logs never include actual credential values (API keys, tokens, passwords). Only metadata about the operation is logged (provider name, type, whether credentials were present).
|
||||
|
||||
**Q: Can I see who viewed credentials?**
|
||||
|
||||
A: Credentials are never "viewed" directly. The only access logged is when credentials are decrypted for certificate issuance (logged as `credential_decrypt` with actor "system").
|
||||
|
||||
### Performance Impact
|
||||
|
||||
Audit logging is designed for minimal performance impact:
|
||||
|
||||
- **Asynchronous Writes**: Audit events are written via a buffered channel and background goroutine
|
||||
- **Non-Blocking**: Failed audit writes do not block API operations
|
||||
- **Indexed Queries**: Database indexes on `created_at`, `event_category`, `resource_uuid`, and `actor` ensure fast filtering
|
||||
- **Automatic Cleanup**: Old logs are periodically deleted to prevent database bloat
|
||||
|
||||
**Typical Impact:**
|
||||
|
||||
- API request latency: +0.1ms (sending to channel)
|
||||
- Database writes: Batched in background, no user-facing impact
|
||||
- Storage: ~500 bytes per event, ~1.5 GB per year at 100 events/day
|
||||
|
||||
### Missing Events
|
||||
|
||||
If you expect to see an event but don't:
|
||||
|
||||
1. **Check filters**: Clear all filters and search to see all events
|
||||
2. **Check date range**: Expand date range to "Last 90 Days"
|
||||
3. **Check retention policy**: Event may have been automatically deleted
|
||||
4. **Check application logs**: Look for "audit channel full" or "Failed to write audit log" messages
|
||||
|
||||
### Slow Query Performance
|
||||
|
||||
If audit log pages load slowly:
|
||||
|
||||
1. **Narrow date range**: Searching 90 days of logs is slower than 7 days
|
||||
2. **Use specific filters**: Filter by category, actor, or action before searching
|
||||
3. **Check database indexes**: Ensure indexes on `security_audits` table are present
|
||||
4. **Consider archival**: Export and delete old logs if database is very large
|
||||
|
||||
## API Reference
|
||||
|
||||
### List Audit Logs
|
||||
|
||||
Retrieve audit logs with pagination and filtering.
|
||||
|
||||
**Endpoint:**
|
||||
|
||||
```http
|
||||
GET /api/v1/audit-logs
|
||||
```
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `page` (int, default: 1): Page number
|
||||
- `limit` (int, default: 50, max: 100): Results per page
|
||||
- `actor` (string): Filter by actor (user ID or "system")
|
||||
- `action` (string): Filter by action type
|
||||
- `event_category` (string): Filter by category (dns_provider, certificate, etc.)
|
||||
- `resource_uuid` (string): Filter by resource UUID
|
||||
- `start_date` (RFC3339): Start of date range
|
||||
- `end_date` (RFC3339): End of date range
|
||||
|
||||
**Example Request:**
|
||||
|
||||
```bash
|
||||
curl -X GET "https://charon.example.com/api/v1/audit-logs?page=1&limit=50&event_category=dns_provider&start_date=2026-01-01T00:00:00Z" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"audit_logs": [
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"actor": "user:5",
|
||||
"action": "dns_provider_create",
|
||||
"event_category": "dns_provider",
|
||||
"resource_id": 3,
|
||||
"resource_uuid": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"details": "{\"name\":\"Cloudflare\",\"type\":\"cloudflare\",\"is_default\":true}",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0",
|
||||
"created_at": "2026-01-03T14:23:45Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"limit": 50,
|
||||
"total": 1,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Get Single Audit Event
|
||||
|
||||
Retrieve complete details for a specific audit event.
|
||||
|
||||
**Endpoint:**
|
||||
|
||||
```http
|
||||
GET /api/v1/audit-logs/:uuid
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `uuid` (string, required): Event UUID
|
||||
|
||||
**Example Request:**
|
||||
|
||||
```bash
|
||||
curl -X GET "https://charon.example.com/api/v1/audit-logs/550e8400-e29b-41d4-a716-446655440000" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"actor": "user:5",
|
||||
"action": "dns_provider_create",
|
||||
"event_category": "dns_provider",
|
||||
"resource_id": 3,
|
||||
"resource_uuid": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"details": "{\"name\":\"Cloudflare\",\"type\":\"cloudflare\",\"is_default\":true}",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0",
|
||||
"created_at": "2026-01-03T14:23:45Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Get Provider Audit History
|
||||
|
||||
Retrieve all audit events for a specific DNS provider.
|
||||
|
||||
**Endpoint:**
|
||||
|
||||
```http
|
||||
GET /api/v1/dns-providers/:id/audit-logs
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
- `id` (int, required): DNS provider ID
|
||||
|
||||
**Query Parameters:**
|
||||
|
||||
- `page` (int, default: 1): Page number
|
||||
- `limit` (int, default: 50, max: 100): Results per page
|
||||
|
||||
**Example Request:**
|
||||
|
||||
```bash
|
||||
curl -X GET "https://charon.example.com/api/v1/dns-providers/3/audit-logs?page=1&limit=50" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"audit_logs": [
|
||||
{
|
||||
"id": 3,
|
||||
"uuid": "770e8400-e29b-41d4-a716-446655440002",
|
||||
"actor": "user:5",
|
||||
"action": "dns_provider_update",
|
||||
"event_category": "dns_provider",
|
||||
"resource_id": 3,
|
||||
"resource_uuid": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"details": "{\"changed_fields\":[\"is_default\"],\"new_values\":{\"is_default\":true}}",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0",
|
||||
"created_at": "2026-01-03T15:00:22Z"
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"uuid": "550e8400-e29b-41d4-a716-446655440000",
|
||||
"actor": "user:5",
|
||||
"action": "dns_provider_create",
|
||||
"event_category": "dns_provider",
|
||||
"resource_id": 3,
|
||||
"resource_uuid": "660e8400-e29b-41d4-a716-446655440001",
|
||||
"details": "{\"name\":\"Cloudflare\",\"type\":\"cloudflare\",\"is_default\":true}",
|
||||
"ip_address": "192.168.1.100",
|
||||
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) Chrome/120.0",
|
||||
"created_at": "2026-01-03T14:23:45Z"
|
||||
}
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"limit": 50,
|
||||
"total": 2,
|
||||
"total_pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
All audit log API endpoints require authentication. Include a valid session cookie or Bearer token:
|
||||
|
||||
```bash
|
||||
# Cookie-based auth (from browser)
|
||||
Cookie: session=YOUR_SESSION_TOKEN
|
||||
|
||||
# Bearer token auth (from API client)
|
||||
Authorization: Bearer YOUR_API_TOKEN
|
||||
```
|
||||
|
||||
### Error Responses
|
||||
|
||||
| Status Code | Error | Description |
|
||||
|-------------|-------|-------------|
|
||||
| 400 | Invalid parameter | Invalid page/limit or malformed date |
|
||||
| 401 | Unauthorized | Missing or invalid authentication |
|
||||
| 404 | Not found | Audit event UUID does not exist |
|
||||
| 500 | Server error | Database error or service unavailable |
|
||||
|
||||
## Configuration
|
||||
|
||||
### Retention Period
|
||||
|
||||
Configure how long audit logs are retained before automatic deletion:
|
||||
|
||||
**Environment Variable:**
|
||||
|
||||
```bash
|
||||
AUDIT_LOG_RETENTION_DAYS=90 # Default: 90 days
|
||||
```
|
||||
|
||||
**Docker Compose:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
charon:
|
||||
environment:
|
||||
- AUDIT_LOG_RETENTION_DAYS=180 # 6 months
|
||||
```
|
||||
|
||||
### Channel Buffer Size
|
||||
|
||||
Configure the size of the audit log channel buffer (advanced):
|
||||
|
||||
**Environment Variable:**
|
||||
|
||||
```bash
|
||||
AUDIT_LOG_CHANNEL_SIZE=1000 # Default: 1000 events
|
||||
```
|
||||
|
||||
Increase if you see "audit channel full" errors in application logs during high-load periods.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Regular Reviews**: Schedule weekly or monthly reviews of audit logs to spot anomalies
|
||||
2. **Alert on Patterns**: Set up alerts for suspicious patterns (e.g., bulk deletions, off-hours access)
|
||||
3. **Export for Compliance**: Regularly export logs for compliance archival before they're auto-deleted
|
||||
4. **Filter Before Export**: Use filters to export only relevant events for specific audits
|
||||
5. **Document Procedures**: Create runbooks for investigating common security scenarios
|
||||
6. **Integrate with SIEM**: Export logs to your SIEM tool for centralized security monitoring
|
||||
7. **Test Retention Policy**: Verify the retention period meets your compliance requirements
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Immutable Logs**: Audit logs cannot be modified or deleted by users (only auto-cleanup)
|
||||
- **No Credential Leakage**: Actual credential values are never logged
|
||||
- **Complete Attribution**: Every event includes actor, IP, and user agent for full traceability
|
||||
- **Secure Storage**: Audit logs are stored in the same encrypted database as other sensitive data
|
||||
- **Access Control**: Audit log viewing requires authentication (no anonymous access)
|
||||
|
||||
## Related Features
|
||||
|
||||
- [DNS Challenge Support](./dns-challenge.md) - Configure DNS providers for automated certificates
|
||||
- [Security Features](./security.md) - WAF, access control, and security notifications
|
||||
- [Notifications](./notifications.md) - Get alerts for security events
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues with audit logging:
|
||||
|
||||
1. Check the [Troubleshooting](#troubleshooting) section above
|
||||
2. Review the [GitHub Issues](https://github.com/Wikid82/charon/issues) for known problems
|
||||
3. Open a new issue with the `audit-logging` label
|
||||
4. Join the [Discord community](https://discord.gg/charon) for real-time support
|
||||
|
||||
---
|
||||
|
||||
**Last Updated:** January 3, 2026
|
||||
**Feature Version:** v1.2.0
|
||||
**Documentation Version:** 1.0
|
||||
@@ -1,84 +0,0 @@
|
||||
---
|
||||
title: Backup & Restore
|
||||
description: Easy configuration backup and restoration
|
||||
---
|
||||
|
||||
# Backup & Restore
|
||||
|
||||
Your configuration is valuable. Charon makes it easy to backup your entire setup and restore it when needed—whether you're migrating to new hardware or recovering from a problem.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon provides automatic configuration backups and one-click restore functionality. Your proxy hosts, SSL certificates, access lists, and settings are all preserved, ensuring you can recover quickly from any situation.
|
||||
|
||||
Backups are stored within the Charon data directory and can be downloaded for off-site storage.
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Disaster Recovery**: Restore your entire configuration in seconds
|
||||
- **Migration Made Easy**: Move to new hardware without reconfiguring
|
||||
- **Change Confidence**: Make changes knowing you can roll back
|
||||
- **Audit Trail**: Keep historical snapshots of your configuration
|
||||
|
||||
## What Gets Backed Up
|
||||
|
||||
| Component | Included |
|
||||
|-----------|----------|
|
||||
| **Database** | All proxy hosts, redirects, streams, and 404 hosts |
|
||||
| **SSL Certificates** | Let's Encrypt certificates and custom certificates |
|
||||
| **Access Lists** | All access control configurations |
|
||||
| **Users** | User accounts and permissions |
|
||||
| **Settings** | Application preferences and configurations |
|
||||
| **CrowdSec Config** | Security settings and custom rules |
|
||||
|
||||
## Creating Backups
|
||||
|
||||
### Automatic Backups
|
||||
|
||||
Charon creates automatic backups:
|
||||
|
||||
- Before major configuration changes
|
||||
- On a configurable schedule (default: daily)
|
||||
- Before version upgrades
|
||||
|
||||
### Manual Backups
|
||||
|
||||
To create a manual backup:
|
||||
|
||||
1. Navigate to **Settings** → **Backup**
|
||||
2. Click **Create Backup**
|
||||
3. Optionally download the backup file for off-site storage
|
||||
|
||||
## Restoring from Backup
|
||||
|
||||
To restore a previous configuration:
|
||||
|
||||
1. Navigate to **Settings** → **Backup**
|
||||
2. Select the backup to restore from the list
|
||||
3. Click **Restore**
|
||||
4. Confirm the restoration
|
||||
|
||||
> **Note**: Restoring a backup will overwrite current settings. Consider creating a backup of your current state first.
|
||||
|
||||
## Backup Retention
|
||||
|
||||
Charon manages backup storage automatically:
|
||||
|
||||
- **Automatic backups**: Retained for 30 days
|
||||
- **Manual backups**: Retained indefinitely until deleted
|
||||
- **Pre-upgrade backups**: Retained for 90 days
|
||||
|
||||
Configure retention settings in **Settings** → **Backup** → **Retention Policy**.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Download backups regularly** for off-site storage
|
||||
2. **Test restores** periodically to ensure backups are valid
|
||||
3. **Backup before changes** when modifying critical configurations
|
||||
4. **Label manual backups** with descriptive names
|
||||
|
||||
## Related
|
||||
|
||||
- [Zero-Downtime Updates](live-reload.md)
|
||||
- [Settings](../getting-started/configuration.md)
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,175 +0,0 @@
|
||||
---
|
||||
title: Caddyfile Import
|
||||
description: Import existing Caddyfile configurations with one click
|
||||
category: migration
|
||||
---
|
||||
|
||||
# Caddyfile Import
|
||||
|
||||
Migrating from another Caddy setup? Import your existing Caddyfile configurations with one click. Your existing work transfers seamlessly—no need to start from scratch.
|
||||
|
||||
## Overview
|
||||
|
||||
Caddyfile import parses your existing Caddy configuration files and converts them into Charon-managed hosts. This enables smooth migration from standalone Caddy installations, other Caddy-based tools, or configuration backups.
|
||||
|
||||
### Supported Configurations
|
||||
|
||||
- **Reverse Proxy Sites**: Domain → backend mappings
|
||||
- **File Server Sites**: Static file hosting configurations
|
||||
- **TLS Settings**: Certificate paths and ACME settings
|
||||
- **Headers**: Custom header configurations
|
||||
- **Redirects**: Redirect rules and rewrites
|
||||
|
||||
## Why Use This
|
||||
|
||||
### Preserve Existing Work
|
||||
|
||||
- Don't rebuild configurations from scratch
|
||||
- Maintain proven routing rules
|
||||
- Keep customizations intact
|
||||
|
||||
### Reduce Migration Risk
|
||||
|
||||
- Preview imports before applying
|
||||
- Identify conflicts and duplicates
|
||||
- Rollback if issues occur
|
||||
|
||||
### Accelerate Adoption
|
||||
|
||||
- Evaluate Charon without commitment
|
||||
- Run imports on staging first
|
||||
- Gradual migration at your pace
|
||||
|
||||
## How to Import
|
||||
|
||||
### Step 1: Access Import Tool
|
||||
|
||||
1. Navigate to **Settings** → **Import / Export**
|
||||
2. Click **Import Caddyfile**
|
||||
|
||||
### Step 2: Provide Configuration
|
||||
|
||||
Choose one of three methods:
|
||||
|
||||
**Paste Content:**
|
||||
```
|
||||
example.com {
|
||||
reverse_proxy localhost:3000
|
||||
}
|
||||
|
||||
api.example.com {
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
```
|
||||
|
||||
**Upload File:**
|
||||
- Click **Choose File**
|
||||
- Select your Caddyfile
|
||||
|
||||
**Fetch from URL:**
|
||||
- Enter URL to raw Caddyfile content
|
||||
- Useful for version-controlled configurations
|
||||
|
||||
### Step 3: Preview and Confirm
|
||||
|
||||
The import preview shows:
|
||||
|
||||
- **Hosts Found**: Number of site blocks detected
|
||||
- **Parse Warnings**: Non-fatal issues or unsupported directives
|
||||
- **Conflicts**: Domains that already exist in Charon
|
||||
|
||||
### Step 4: Execute Import
|
||||
|
||||
Click **Import** to create hosts. The process handles each host individually—one failure doesn't block others.
|
||||
|
||||
## Import Results Modal
|
||||
|
||||
After import completes, a summary modal displays:
|
||||
|
||||
| Category | Description |
|
||||
|----------|-------------|
|
||||
| **Created** | New hosts added to Charon |
|
||||
| **Updated** | Existing hosts modified (if overwrite enabled) |
|
||||
| **Skipped** | Hosts skipped due to conflicts or errors |
|
||||
| **Warnings** | Non-blocking issues to review |
|
||||
|
||||
### Example Results
|
||||
|
||||
```
|
||||
Import Complete
|
||||
|
||||
✓ Created: 12 hosts
|
||||
↻ Updated: 3 hosts
|
||||
○ Skipped: 2 hosts
|
||||
⚠ Warnings: 1
|
||||
|
||||
Details:
|
||||
✓ example.com → localhost:3000
|
||||
✓ api.example.com → localhost:8080
|
||||
○ old.example.com (already exists, overwrite disabled)
|
||||
⚠ staging.example.com (unsupported directive: php_fastcgi)
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
### Overwrite Existing
|
||||
|
||||
| Setting | Behavior |
|
||||
|---------|----------|
|
||||
| **Off** (default) | Skip hosts that already exist |
|
||||
| **On** | Replace existing hosts with imported configuration |
|
||||
|
||||
### Import Disabled Hosts
|
||||
|
||||
Create hosts but leave them disabled for review before enabling.
|
||||
|
||||
### TLS Handling
|
||||
|
||||
| Source TLS Setting | Charon Behavior |
|
||||
|--------------------|-----------------|
|
||||
| ACME configured | Enable Let's Encrypt |
|
||||
| Custom certificates | Create host, flag for manual cert upload |
|
||||
| No TLS | Create HTTP-only host |
|
||||
|
||||
## Migration from Other Caddy Setups
|
||||
|
||||
### From Caddy Standalone
|
||||
|
||||
1. Locate your Caddyfile (typically `/etc/caddy/Caddyfile`)
|
||||
2. Copy contents or upload file
|
||||
3. Import into Charon
|
||||
4. Verify hosts work correctly
|
||||
5. Point DNS to Charon
|
||||
6. Decommission old Caddy
|
||||
|
||||
### From Other Management Tools
|
||||
|
||||
Export Caddyfile from your current tool, then import into Charon. Most Caddy-based tools provide export functionality.
|
||||
|
||||
### Partial Migrations
|
||||
|
||||
Import specific site blocks by editing the Caddyfile before import. Remove sites you want to migrate later or manage separately.
|
||||
|
||||
## Limitations
|
||||
|
||||
Some Caddyfile features require manual configuration after import:
|
||||
|
||||
- Custom plugins/modules
|
||||
- Complex matcher expressions
|
||||
- Snippet references (imported inline)
|
||||
- Global options (applied separately)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Parse error | Check Caddyfile syntax validity |
|
||||
| Missing hosts | Ensure site blocks have valid domains |
|
||||
| TLS warnings | Configure certificates manually post-import |
|
||||
| Duplicate domains | Enable overwrite or rename in source |
|
||||
|
||||
## Related
|
||||
|
||||
- [Web UI](web-ui.md) - Managing imported hosts
|
||||
- [SSL Certificates](ssl-certificates.md) - Certificate configuration
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,91 +0,0 @@
|
||||
---
|
||||
title: CrowdSec Integration
|
||||
description: Behavior-based threat detection powered by a global community
|
||||
---
|
||||
|
||||
# CrowdSec Integration
|
||||
|
||||
Protect your applications using behavior-based threat detection powered by a global community of security data. Bad actors get blocked automatically before they can cause harm.
|
||||
|
||||
## Overview
|
||||
|
||||
CrowdSec analyzes your traffic patterns and blocks malicious behavior in real-time. Unlike traditional firewalls that rely on static rules, CrowdSec uses behavioral analysis and crowdsourced threat intelligence to identify and stop attacks.
|
||||
|
||||
Key capabilities:
|
||||
|
||||
- **Behavior Detection** — Identifies attack patterns like brute-force, scanning, and exploitation
|
||||
- **Community Blocklists** — Benefit from threats detected by the global CrowdSec community
|
||||
- **Real-time Blocking** — Malicious IPs are blocked immediately via Caddy integration
|
||||
- **Automatic Updates** — Threat intelligence updates continuously
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Proactive Defense** — Block attackers before they succeed
|
||||
- **Zero False Positives** — Behavioral analysis reduces incorrect blocks
|
||||
- **Community Intelligence** — Leverage data from thousands of CrowdSec users
|
||||
- **GUI-Controlled** — Enable/disable directly from the UI, no environment variables needed
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enabling CrowdSec
|
||||
|
||||
1. Navigate to **Settings → Security**
|
||||
2. Toggle **CrowdSec Protection** to enabled
|
||||
3. CrowdSec starts automatically and persists across container restarts
|
||||
|
||||
No environment variables or manual configuration required.
|
||||
|
||||
### Hub Presets
|
||||
|
||||
Access pre-built security configurations from the CrowdSec Hub:
|
||||
|
||||
1. Go to **Settings → Security → Hub Presets**
|
||||
2. Browse available collections (e.g., `crowdsecurity/nginx`, `crowdsecurity/http-cve`)
|
||||
3. Search for specific parsers, scenarios, or collections
|
||||
4. Click **Install** to add to your configuration
|
||||
|
||||
Popular presets include:
|
||||
|
||||
- **HTTP Probing** — Detect reconnaissance and scanning
|
||||
- **Bad User-Agents** — Block known malicious bots
|
||||
- **CVE Exploits** — Protection against known vulnerabilities
|
||||
|
||||
### Console Enrollment
|
||||
|
||||
Connect to the CrowdSec Console for centralized management:
|
||||
|
||||
1. Go to **Settings → Security → Console Enrollment**
|
||||
2. Enter your enrollment key from [console.crowdsec.net](https://console.crowdsec.net)
|
||||
3. Click **Enroll**
|
||||
|
||||
The Console provides:
|
||||
|
||||
- Multi-instance management
|
||||
- Historical attack data
|
||||
- Alert notifications
|
||||
- Blocklist subscriptions
|
||||
|
||||
### Live Decisions
|
||||
|
||||
View active blocks in real-time:
|
||||
|
||||
1. Navigate to **Security → Live Decisions**
|
||||
2. See all currently blocked IPs with:
|
||||
- IP address and origin country
|
||||
- Reason for block (scenario triggered)
|
||||
- Duration remaining
|
||||
- Option to manually unban
|
||||
|
||||
## Automatic Startup & Persistence
|
||||
|
||||
CrowdSec settings are stored in Charon's database and synchronized with the Security Config:
|
||||
|
||||
- **On Container Start** — CrowdSec launches automatically if previously enabled
|
||||
- **Configuration Sync** — Changes in the UI immediately apply to CrowdSec
|
||||
- **State Persistence** — Decisions and configurations survive restarts
|
||||
|
||||
## Related
|
||||
|
||||
- [Web Application Firewall](./waf.md) — Complement CrowdSec with WAF protection
|
||||
- [Access Control](./access-control.md) — Manual IP blocking and geo-restrictions
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,430 +0,0 @@
|
||||
# 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:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
directory: /path/to/plugins
|
||||
allowed_signatures:
|
||||
powerdns: "sha256:abc123def456..."
|
||||
custom-provider: "sha256:789xyz..."
|
||||
```
|
||||
|
||||
To generate a signature for a plugin:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
curl https://example.com/plugins/powerdns-linux-amd64.so -O powerdns.so
|
||||
```
|
||||
|
||||
2. **Verify Plugin Integrity (Recommended)**
|
||||
|
||||
Check the SHA-256 signature:
|
||||
|
||||
```bash
|
||||
sha256sum powerdns.so
|
||||
# Compare with published signature
|
||||
```
|
||||
|
||||
3. **Copy to Plugin Directory**
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```yaml
|
||||
plugins:
|
||||
directory: /etc/charon/plugins
|
||||
# Optional: Enable signature verification
|
||||
allowed_signatures:
|
||||
powerdns: "sha256:your-signature-here"
|
||||
```
|
||||
|
||||
5. **Restart Charon**
|
||||
|
||||
```bash
|
||||
sudo systemctl restart charon
|
||||
```
|
||||
|
||||
6. **Verify Plugin Loading**
|
||||
|
||||
Check Charon logs:
|
||||
|
||||
```bash
|
||||
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**
|
||||
|
||||
```yaml
|
||||
# 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:
|
||||
|
||||
```dockerfile
|
||||
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):
|
||||
|
||||
```bash
|
||||
curl https://charon.example.com/api/v1/dns-providers/types \
|
||||
-H "Authorization: Bearer YOUR-TOKEN"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"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
|
||||
|
||||
1. Navigate to **Settings** → **DNS 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
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```json
|
||||
{
|
||||
"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`:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
curl https://charon.example.com/api/admin/plugins \
|
||||
-H "Authorization: Bearer YOUR-TOKEN"
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```bash
|
||||
curl -X DELETE https://charon.example.com/api/admin/plugins/powerdns \
|
||||
-H "Authorization: Bearer YOUR-TOKEN"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Plugin Not Loading
|
||||
|
||||
**Check Go Version Compatibility:**
|
||||
|
||||
```bash
|
||||
go version
|
||||
# Must match the version shown in plugin metadata
|
||||
```
|
||||
|
||||
**Check Plugin File Permissions:**
|
||||
|
||||
```bash
|
||||
ls -la /etc/charon/plugins/
|
||||
# Should be 755 or 644, not world-writable
|
||||
```
|
||||
|
||||
**Check Charon Logs:**
|
||||
|
||||
```bash
|
||||
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":
|
||||
|
||||
```bash
|
||||
# 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:
|
||||
|
||||
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
|
||||
|
||||
- [Plugin Security Guide](./plugin-security.md)
|
||||
- [Plugin Development Guide](../development/plugin-development.md)
|
||||
- [DNS Provider Configuration](./dns-providers.md)
|
||||
- [Security Best Practices](../../SECURITY.md)
|
||||
@@ -1,586 +0,0 @@
|
||||
# DNS Provider Auto-Detection
|
||||
|
||||
## Overview
|
||||
|
||||
DNS Provider Auto-Detection is an intelligent feature that automatically identifies which DNS provider manages your domain's nameservers. This helps streamline the setup process and reduces configuration errors when creating wildcard SSL certificate proxy hosts.
|
||||
|
||||
### Benefits
|
||||
|
||||
- **Reduce Configuration Errors**: Eliminates the risk of selecting the wrong DNS provider
|
||||
- **Faster Setup**: No need to manually check your DNS registrar or control panel
|
||||
- **Auto-Fill Provider Selection**: Automatically suggests the correct DNS provider in proxy host forms
|
||||
- **Reduced Support Burden**: Fewer configuration issues to troubleshoot
|
||||
|
||||
### When Detection Occurs
|
||||
|
||||
Auto-detection runs automatically when you:
|
||||
|
||||
- Enter a wildcard domain (`*.example.com`) in the proxy host creation form
|
||||
- The domain requires DNS-01 challenge validation for Let's Encrypt SSL certificates
|
||||
|
||||
## How Auto-Detection Works
|
||||
|
||||
### Detection Process
|
||||
|
||||
1. **Nameserver Lookup**: System performs a DNS query to retrieve the authoritative nameservers for your domain
|
||||
2. **Pattern Matching**: Compares nameserver hostnames against known provider patterns
|
||||
3. **Confidence Assessment**: Assigns a confidence level based on match quality
|
||||
4. **Provider Suggestion**: Suggests configured DNS providers that match the detected type
|
||||
5. **Caching**: Results are cached for 1 hour to improve performance
|
||||
|
||||
### Confidence Levels
|
||||
|
||||
| Level | Description | Action Required |
|
||||
|-------|-------------|-----------------|
|
||||
| **High** | Exact match with known provider pattern | Safe to use auto-detected provider |
|
||||
| **Medium** | Partial match or common pattern | Verify provider before using |
|
||||
| **Low** | Weak match or ambiguous pattern | Manually verify provider selection |
|
||||
| **None** | No matching pattern found | Manual provider selection required |
|
||||
|
||||
### Caching Behavior
|
||||
|
||||
- Detection results are cached for **1 hour**
|
||||
- Reduces DNS query load and improves response time
|
||||
- Cache is invalidated when manually changing provider
|
||||
- Each domain is cached independently
|
||||
|
||||
## Using Auto-Detection
|
||||
|
||||
### Automatic Detection
|
||||
|
||||
When creating a new proxy host with a wildcard domain:
|
||||
|
||||
1. Enter your wildcard domain in the **Domain Names** field (e.g., `*.example.com`)
|
||||
2. The system automatically performs nameserver lookup
|
||||
3. Detection results appear in the **DNS Provider** section
|
||||
4. If a match is found, the provider is automatically selected
|
||||
|
||||
**Visual Indicator**: A detection status badge appears next to the DNS Provider dropdown showing:
|
||||
|
||||
- ✓ Provider detected
|
||||
- ⚠ No provider detected
|
||||
- ℹ Multiple nameservers found
|
||||
|
||||
### Manual Detection
|
||||
|
||||
If auto-detection doesn't run automatically or you want to recheck:
|
||||
|
||||
1. Click the **Detect Provider** button next to the DNS Provider dropdown
|
||||
2. System performs fresh nameserver lookup (bypasses cache)
|
||||
3. Results update immediately
|
||||
|
||||
> **Note**: Manual detection is useful after changing nameservers at your DNS provider.
|
||||
|
||||
### Reviewing Detection Results
|
||||
|
||||
The detection results panel displays:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| **Status** | Whether provider was detected |
|
||||
| **Detected Provider Type** | DNS provider identified (e.g., "cloudflare") |
|
||||
| **Confidence** | Detection confidence level |
|
||||
| **Nameservers** | List of authoritative nameservers found |
|
||||
| **Suggested Provider** | Configured provider that matches detected type |
|
||||
|
||||
### Manual Override
|
||||
|
||||
You can always override auto-detection:
|
||||
|
||||
1. Select a different provider from the **DNS Provider** dropdown
|
||||
2. Your selection takes precedence over auto-detection
|
||||
3. System uses your selected provider credentials
|
||||
|
||||
> **Warning**: Using the wrong provider will cause SSL certificate issuance to fail.
|
||||
|
||||
## Detection Results Explained
|
||||
|
||||
### Example 1: Successful Detection
|
||||
|
||||
```
|
||||
Domain: *.example.com
|
||||
|
||||
Detection Results:
|
||||
✓ Provider Detected
|
||||
|
||||
Detected Provider Type: cloudflare
|
||||
Confidence: High
|
||||
Nameservers:
|
||||
- ns1.cloudflare.com
|
||||
- ns2.cloudflare.com
|
||||
|
||||
Suggested Provider: "Production Cloudflare"
|
||||
```
|
||||
|
||||
**Action**: Use the suggested provider with confidence.
|
||||
|
||||
### Example 2: No Match Found
|
||||
|
||||
```
|
||||
Domain: *.internal.company.com
|
||||
|
||||
Detection Results:
|
||||
⚠ No Provider Detected
|
||||
|
||||
Nameservers:
|
||||
- ns1.internal.company.com
|
||||
- ns2.internal.company.com
|
||||
|
||||
Confidence: None
|
||||
```
|
||||
|
||||
**Action**: Manually select the appropriate DNS provider or configure a custom provider.
|
||||
|
||||
### Example 3: Multiple Providers (Rare)
|
||||
|
||||
```
|
||||
Domain: *.example.com
|
||||
|
||||
Detection Results:
|
||||
⚠ Multiple Providers Detected
|
||||
|
||||
Detected Types:
|
||||
- cloudflare (2 nameservers)
|
||||
- route53 (1 nameserver)
|
||||
|
||||
Confidence: Medium
|
||||
```
|
||||
|
||||
**Action**: Verify your domain's nameserver configuration at your DNS registrar. Mixed providers are uncommon and may indicate a configuration issue.
|
||||
|
||||
## Supported DNS Providers
|
||||
|
||||
The system recognizes the following DNS providers by their nameserver patterns:
|
||||
|
||||
| Provider | Nameserver Pattern | Example Nameserver |
|
||||
|----------|-------------------|-------------------|
|
||||
| **Cloudflare** | `*.ns.cloudflare.com` | `ns1.cloudflare.com` |
|
||||
| **AWS Route 53** | `*.awsdns*` | `ns-123.awsdns-12.com` |
|
||||
| **DigitalOcean** | `*.digitalocean.com` | `ns1.digitalocean.com` |
|
||||
| **Google Cloud DNS** | `*.googledomains.com`, `ns-cloud*` | `ns-cloud-a1.googledomains.com` |
|
||||
| **Azure DNS** | `*.azure-dns*` | `ns1-01.azure-dns.com` |
|
||||
| **Namecheap** | `*.registrar-servers.com` | `dns1.registrar-servers.com` |
|
||||
| **GoDaddy** | `*.domaincontrol.com` | `ns01.domaincontrol.com` |
|
||||
| **Hetzner** | `*.hetzner.com`, `*.hetzner.de` | `helium.ns.hetzner.com` |
|
||||
| **Vultr** | `*.vultr.com` | `ns1.vultr.com` |
|
||||
| **DNSimple** | `*.dnsimple.com` | `ns1.dnsimple.com` |
|
||||
|
||||
### Provider-Specific Examples
|
||||
|
||||
#### Cloudflare
|
||||
|
||||
```
|
||||
Nameservers:
|
||||
ns1.cloudflare.com
|
||||
ns2.cloudflare.com
|
||||
|
||||
Detected: cloudflare (High confidence)
|
||||
```
|
||||
|
||||
#### AWS Route 53
|
||||
|
||||
```
|
||||
Nameservers:
|
||||
ns-1234.awsdns-12.com
|
||||
ns-5678.awsdns-34.net
|
||||
|
||||
Detected: route53 (High confidence)
|
||||
```
|
||||
|
||||
#### Google Cloud DNS
|
||||
|
||||
```
|
||||
Nameservers:
|
||||
ns-cloud-a1.googledomains.com
|
||||
ns-cloud-a2.googledomains.com
|
||||
|
||||
Detected: googleclouddns (High confidence)
|
||||
```
|
||||
|
||||
#### DigitalOcean
|
||||
|
||||
```
|
||||
Nameservers:
|
||||
ns1.digitalocean.com
|
||||
ns2.digitalocean.com
|
||||
ns3.digitalocean.com
|
||||
|
||||
Detected: digitalocean (High confidence)
|
||||
```
|
||||
|
||||
### Unsupported Providers
|
||||
|
||||
If your DNS provider isn't listed above:
|
||||
|
||||
1. **Custom/Internal DNS**: You'll need to manually select a provider that uses the same API (e.g., many providers use Cloudflare's API)
|
||||
2. **New Provider**: Request support by opening a GitHub issue with your provider's nameserver pattern
|
||||
3. **Workaround**: Configure a supported provider that's API-compatible, or use a different DNS provider for wildcard domains
|
||||
|
||||
## Manual Override Scenarios
|
||||
|
||||
### When to Override Auto-Detection
|
||||
|
||||
Override auto-detection when:
|
||||
|
||||
1. **Multiple Credentials**: You have multiple configured providers of the same type (e.g., "Dev Cloudflare" and "Prod Cloudflare")
|
||||
2. **API-Compatible Providers**: Using a provider that shares an API with a detected provider
|
||||
3. **Custom DNS Servers**: Running custom DNS infrastructure that mimics provider nameservers
|
||||
4. **Testing**: Deliberately testing with different credentials
|
||||
|
||||
### How to Override
|
||||
|
||||
1. Ignore the auto-detected provider suggestion
|
||||
2. Select your preferred provider from the **DNS Provider** dropdown
|
||||
3. Save the proxy host with your selection
|
||||
4. System will use your selected credentials
|
||||
|
||||
> **Important**: Ensure your selected provider has valid API credentials and permissions to modify DNS records for the domain.
|
||||
|
||||
### Custom Nameservers
|
||||
|
||||
For custom or internal nameservers:
|
||||
|
||||
1. Detection will likely return "No Provider Detected"
|
||||
2. You must manually select a provider
|
||||
3. Ensure the selected provider type matches your DNS server's API
|
||||
4. Configure appropriate API credentials in the DNS Provider settings
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
Domain: *.corp.internal
|
||||
Nameservers: ns1.corp.internal, ns2.corp.internal
|
||||
|
||||
Auto-detection: None
|
||||
Manual selection required: Select compatible provider or configure custom
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Detection Failed: Domain Not Found
|
||||
|
||||
**Symptom**: Error message "Failed to detect DNS provider" or "Domain not found"
|
||||
|
||||
**Causes**:
|
||||
|
||||
- Domain doesn't exist yet
|
||||
- Domain not propagated to public DNS
|
||||
- DNS resolution blocked by firewall
|
||||
|
||||
**Solutions**:
|
||||
|
||||
- Verify domain exists and is registered
|
||||
- Wait for DNS propagation (up to 48 hours)
|
||||
- Check network connectivity and DNS resolution
|
||||
- Manually select provider and proceed
|
||||
|
||||
### Wrong Provider Detected
|
||||
|
||||
**Symptom**: System detects incorrect provider type
|
||||
|
||||
**Causes**:
|
||||
|
||||
- Domain using DNS proxy/forwarding service
|
||||
- Recent nameserver change not yet propagated
|
||||
- Multiple providers in nameserver list
|
||||
|
||||
**Solutions**:
|
||||
|
||||
- Wait for DNS propagation (up to 24 hours)
|
||||
- Manually override provider selection
|
||||
- Verify nameservers at your domain registrar
|
||||
- Use manual detection to refresh results
|
||||
|
||||
### Multiple Providers Detected
|
||||
|
||||
**Symptom**: Detection shows multiple provider types
|
||||
|
||||
**Causes**:
|
||||
|
||||
- Nameservers from different providers (unusual)
|
||||
- DNS migration in progress
|
||||
- Misconfigured nameservers
|
||||
|
||||
**Solutions**:
|
||||
|
||||
- Check nameserver configuration at your registrar
|
||||
- Complete DNS migration to single provider
|
||||
- Manually select the primary/correct provider
|
||||
- Contact DNS provider support if configuration is correct
|
||||
|
||||
### No DNS Provider Configured for Detected Type
|
||||
|
||||
**Symptom**: Provider detected but no matching provider configured in system
|
||||
|
||||
**Example**:
|
||||
|
||||
```
|
||||
Detected Provider Type: cloudflare
|
||||
Error: No DNS provider of type 'cloudflare' is configured
|
||||
```
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Navigate to **Settings** → **DNS Providers**
|
||||
2. Click **Add DNS Provider**
|
||||
3. Select the detected provider type (e.g., Cloudflare)
|
||||
4. Enter API credentials:
|
||||
- Cloudflare: API Token or Global API Key + Email
|
||||
- Route 53: Access Key ID + Secret Access Key
|
||||
- DigitalOcean: API Token
|
||||
- (See provider-specific documentation)
|
||||
5. Save provider configuration
|
||||
6. Return to proxy host creation and retry
|
||||
|
||||
> **Tip**: You can configure multiple providers of the same type with different names (e.g., "Dev Cloudflare" and "Prod Cloudflare").
|
||||
|
||||
### Custom/Internal DNS Servers Not Detected
|
||||
|
||||
**Symptom**: Using private/internal DNS, no provider detected
|
||||
|
||||
**This is expected behavior**. Custom DNS servers don't match public provider patterns.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. Manually select a provider that uses a compatible API
|
||||
2. If using BIND, PowerDNS, or other custom DNS:
|
||||
- Configure acme.sh or certbot direct integration
|
||||
- Use supported provider API if available
|
||||
- Consider using supported DNS provider for wildcard domains only
|
||||
3. If no compatible API:
|
||||
- Use HTTP-01 challenge instead (no wildcard support)
|
||||
- Configure manual DNS challenge workflow
|
||||
|
||||
### Detection Caching Issues
|
||||
|
||||
**Symptom**: Detection results don't reflect recent nameserver changes
|
||||
|
||||
**Cause**: Results cached for 1 hour
|
||||
|
||||
**Solutions**:
|
||||
|
||||
- Wait up to 1 hour for cache to expire
|
||||
- Use **Detect Provider** button for manual detection (bypasses cache)
|
||||
- DNS propagation may also take additional time (separate from caching)
|
||||
|
||||
## API Reference
|
||||
|
||||
### Detection Endpoint
|
||||
|
||||
Auto-detection is exposed via REST API for automation and integrations.
|
||||
|
||||
#### Endpoint
|
||||
|
||||
```
|
||||
POST /api/dns-providers/detect
|
||||
```
|
||||
|
||||
#### Authentication
|
||||
|
||||
Requires API token with `dns_providers:read` permission.
|
||||
|
||||
```http
|
||||
Authorization: Bearer YOUR_API_TOKEN
|
||||
```
|
||||
|
||||
#### Request Body
|
||||
|
||||
```json
|
||||
{
|
||||
"domain": "*.example.com"
|
||||
}
|
||||
```
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `domain` (required): Full domain name including wildcard (e.g., `*.example.com`)
|
||||
|
||||
#### Response: Success
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "detected",
|
||||
"provider_type": "cloudflare",
|
||||
"confidence": "high",
|
||||
"nameservers": [
|
||||
"ns1.cloudflare.com",
|
||||
"ns2.cloudflare.com"
|
||||
],
|
||||
"suggested_provider_id": 42,
|
||||
"suggested_provider_name": "Production Cloudflare",
|
||||
"cached": false
|
||||
}
|
||||
```
|
||||
|
||||
**Response Fields**:
|
||||
|
||||
- `status`: `"detected"` or `"not_detected"`
|
||||
- `provider_type`: Detected provider type (string) or `null`
|
||||
- `confidence`: `"high"`, `"medium"`, `"low"`, or `"none"`
|
||||
- `nameservers`: Array of authoritative nameservers (strings)
|
||||
- `suggested_provider_id`: Database ID of matching configured provider (integer or `null`)
|
||||
- `suggested_provider_name`: Display name of matching provider (string or `null`)
|
||||
- `cached`: Whether result is from cache (boolean)
|
||||
|
||||
#### Response: Not Detected
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "not_detected",
|
||||
"provider_type": null,
|
||||
"confidence": "none",
|
||||
"nameservers": [
|
||||
"ns1.custom-dns.com",
|
||||
"ns2.custom-dns.com"
|
||||
],
|
||||
"suggested_provider_id": null,
|
||||
"suggested_provider_name": null,
|
||||
"cached": false
|
||||
}
|
||||
```
|
||||
|
||||
#### Response: Error
|
||||
|
||||
```json
|
||||
{
|
||||
"error": "Failed to resolve nameservers for domain",
|
||||
"details": "NXDOMAIN: domain does not exist"
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP Status Codes**:
|
||||
|
||||
- `200 OK`: Detection completed successfully
|
||||
- `400 Bad Request`: Invalid domain format
|
||||
- `401 Unauthorized`: Missing or invalid API token
|
||||
- `500 Internal Server Error`: DNS resolution or server error
|
||||
|
||||
#### Example: cURL
|
||||
|
||||
```bash
|
||||
curl -X POST https://charon.example.com/api/dns-providers/detect \
|
||||
-H "Authorization: Bearer YOUR_API_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"domain": "*.example.com"
|
||||
}'
|
||||
```
|
||||
|
||||
#### Example: JavaScript
|
||||
|
||||
```javascript
|
||||
async function detectDNSProvider(domain) {
|
||||
const response = await fetch('/api/dns-providers/detect', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': `Bearer ${apiToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ domain })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'detected') {
|
||||
console.log(`Detected: ${result.provider_type} (${result.confidence})`);
|
||||
console.log(`Nameservers: ${result.nameservers.join(', ')}`);
|
||||
} else {
|
||||
console.log('No provider detected');
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Usage
|
||||
detectDNSProvider('*.example.com');
|
||||
```
|
||||
|
||||
#### Example: Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def detect_dns_provider(domain: str, api_token: str) -> dict:
|
||||
response = requests.post(
|
||||
'https://charon.example.com/api/dns-providers/detect',
|
||||
headers={
|
||||
'Authorization': f'Bearer {api_token}',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
json={'domain': domain}
|
||||
)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
# Usage
|
||||
result = detect_dns_provider('*.example.com', 'YOUR_API_TOKEN')
|
||||
if result['status'] == 'detected':
|
||||
print(f"Detected: {result['provider_type']} ({result['confidence']})")
|
||||
print(f"Nameservers: {', '.join(result['nameservers'])}")
|
||||
else:
|
||||
print('No provider detected')
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### General Recommendations
|
||||
|
||||
1. **Trust High Confidence**: High-confidence detections are highly reliable
|
||||
2. **Verify Medium/Low**: Always verify medium or low confidence detections before using
|
||||
3. **Manual Override When Needed**: Don't hesitate to override if detection seems incorrect
|
||||
4. **Keep Providers Updated**: Ensure DNS provider API credentials are current
|
||||
5. **Monitor Detection**: Track detection success rates in your environment
|
||||
|
||||
### For Multiple Environments
|
||||
|
||||
When managing multiple environments (dev, staging, production):
|
||||
|
||||
1. Use descriptive provider names: "Dev Cloudflare", "Prod Cloudflare"
|
||||
2. Auto-detection will suggest the first matching provider by default
|
||||
3. Always verify the suggested provider matches your intended environment
|
||||
4. Consider using different DNS providers per environment to avoid confusion
|
||||
|
||||
### For Enterprise/Internal DNS
|
||||
|
||||
If using custom enterprise DNS infrastructure:
|
||||
|
||||
1. Document which Charon DNS provider type is compatible with your system
|
||||
2. Create named providers for each environment/purpose
|
||||
3. Train users to ignore auto-detection for internal domains
|
||||
4. Consider maintaining a mapping document of internal domains to correct providers
|
||||
|
||||
### For Multi-Credential Setups
|
||||
|
||||
When using multiple credentials for the same provider:
|
||||
|
||||
1. Name providers clearly: "Cloudflare - Account A", "Cloudflare - Account B"
|
||||
2. Document which domains belong to which account
|
||||
3. Always review auto-detected suggestions carefully
|
||||
4. Use manual override to select the correct credential set
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DNS Provider Configuration](../guides/dns-providers.md) - Setting up DNS provider credentials
|
||||
- [Multi-Credential DNS Support](./multi-credential-dns.md) - Managing multiple providers of same type
|
||||
- [Proxy Host Creation](../guides/proxy-hosts.md) - Creating wildcard SSL proxy hosts
|
||||
- [SSL Certificate Management](../guides/ssl-certificates.md) - Let's Encrypt and certificate issuance
|
||||
- [Troubleshooting DNS Issues](../troubleshooting/dns-problems.md) - Common DNS configuration problems
|
||||
|
||||
## Support
|
||||
|
||||
If you encounter issues with DNS Provider Auto-Detection:
|
||||
|
||||
1. Check the [Troubleshooting](#troubleshooting) section above
|
||||
2. Review [GitHub Issues](https://github.com/yourusername/charon/issues) for similar problems
|
||||
3. Open a new issue with:
|
||||
- Domain name (sanitized if sensitive)
|
||||
- Detected provider (if any)
|
||||
- Expected provider
|
||||
- Nameservers returned
|
||||
- Error messages or logs
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: January 2026
|
||||
**Feature Version**: 0.1.6-beta.0+
|
||||
**Status**: Production Ready
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,626 +0,0 @@
|
||||
# DNS Challenge (DNS-01) for SSL Certificates
|
||||
|
||||
Charon supports **DNS-01 challenge validation** for issuing SSL/TLS certificates, enabling wildcard certificates and secure automation through 15+ integrated DNS providers.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Why Use DNS Challenge?](#why-use-dns-challenge)
|
||||
- [Supported DNS Providers](#supported-dns-providers)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Manual DNS Challenge](#manual-dns-challenge)
|
||||
- [Troubleshooting](#troubleshooting)
|
||||
- [Related Documentation](#related-documentation)
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
### What is DNS-01 Challenge?
|
||||
|
||||
The DNS-01 challenge is an ACME (Automatic Certificate Management Environment) validation method where you prove domain ownership by creating a specific DNS TXT record. When you request a certificate, the Certificate Authority (CA) provides a challenge token that must be published as a DNS record at `_acme-challenge.yourdomain.com`.
|
||||
|
||||
### How It Works
|
||||
|
||||
```
|
||||
┌─────────────┐ 1. Request Certificate ┌──────────────┐
|
||||
│ Charon │ ─────────────────────────────────▶ │ Let's │
|
||||
│ │ │ Encrypt │
|
||||
│ │ ◀───────────────────────────────── │ (CA) │
|
||||
└─────────────┘ 2. Receive Challenge Token └──────────────┘
|
||||
│
|
||||
│ 3. Create TXT Record via DNS Provider API
|
||||
▼
|
||||
┌─────────────┐
|
||||
│ DNS │ _acme-challenge.example.com TXT "token123..."
|
||||
│ Provider │
|
||||
└─────────────┘
|
||||
│
|
||||
│ 4. CA Verifies DNS Record
|
||||
▼
|
||||
┌──────────────┐ 5. Certificate Issued ┌─────────────┐
|
||||
│ Let's │ ─────────────────────────────────▶│ Charon │
|
||||
│ Encrypt │ │ │
|
||||
└──────────────┘ └─────────────┘
|
||||
```
|
||||
|
||||
### Key Features
|
||||
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| **Wildcard Certificates** | Issue certificates for `*.example.com` |
|
||||
| **15+ DNS Providers** | Native integration with major DNS services |
|
||||
| **Secure Credentials** | AES-256-GCM encryption with automatic key rotation |
|
||||
| **Plugin Architecture** | Extend with custom providers via webhooks or scripts |
|
||||
| **Manual Option** | Support for any DNS provider via manual record creation |
|
||||
| **Auto-Renewal** | Certificates renew automatically before expiration |
|
||||
|
||||
---
|
||||
|
||||
## Why Use DNS Challenge?
|
||||
|
||||
### DNS-01 vs HTTP-01 Comparison
|
||||
|
||||
| Feature | DNS-01 Challenge | HTTP-01 Challenge |
|
||||
|---------|-----------------|-------------------|
|
||||
| **Wildcard Certificates** | ✅ Yes | ❌ No |
|
||||
| **Requires Port 80** | ❌ No | ✅ Yes |
|
||||
| **Works Behind Firewall** | ✅ Yes | ⚠️ Requires port forwarding |
|
||||
| **Internal Networks** | ✅ Yes | ❌ No |
|
||||
| **Multiple Servers** | ✅ One validation, many servers | ❌ Each server validates |
|
||||
| **Setup Complexity** | Medium (API credentials) | Low (no credentials) |
|
||||
|
||||
### When to Use DNS-01
|
||||
|
||||
Choose DNS-01 challenge when you need:
|
||||
|
||||
- ✅ **Wildcard certificates** (`*.example.com`) — DNS-01 is the **only** method that supports wildcards
|
||||
- ✅ **Servers without public port 80** — Firewalls, NAT, or security policies blocking HTTP
|
||||
- ✅ **Internal/private networks** — Servers not accessible from the internet
|
||||
- ✅ **Multi-server deployments** — One certificate for load-balanced or clustered services
|
||||
- ✅ **CI/CD automation** — Fully automated certificate issuance without HTTP exposure
|
||||
|
||||
### When HTTP-01 May Be Better
|
||||
|
||||
Consider HTTP-01 challenge when:
|
||||
|
||||
- You don't need wildcard certificates
|
||||
- Port 80 is available and publicly accessible
|
||||
- You want simpler setup without managing DNS credentials
|
||||
- Your DNS provider isn't supported by Charon
|
||||
|
||||
---
|
||||
|
||||
## Supported DNS Providers
|
||||
|
||||
Charon integrates with 15+ DNS providers for automatic DNS record management.
|
||||
|
||||
### Tier 1: Full API Support
|
||||
|
||||
These providers have complete, tested integration with automatic record creation and cleanup:
|
||||
|
||||
| Provider | API Type | Documentation |
|
||||
|----------|----------|---------------|
|
||||
| **Cloudflare** | REST API | [Cloudflare Setup Guide](#cloudflare-setup) |
|
||||
| **AWS Route53** | AWS SDK | [Route53 Setup Guide](#route53-setup) |
|
||||
| **DigitalOcean** | REST API | [DigitalOcean Setup Guide](#digitalocean-setup) |
|
||||
| **Google Cloud DNS** | GCP SDK | [Google Cloud Setup Guide](#google-cloud-setup) |
|
||||
| **Azure DNS** | Azure SDK | [Azure Setup Guide](#azure-setup) |
|
||||
|
||||
### Tier 2: Standard API Support
|
||||
|
||||
Fully functional providers with standard API integration:
|
||||
|
||||
| Provider | API Type | Notes |
|
||||
|----------|----------|-------|
|
||||
| **Hetzner** | REST API | Hetzner Cloud DNS |
|
||||
| **Linode** | REST API | Linode DNS Manager |
|
||||
| **Vultr** | REST API | Vultr DNS |
|
||||
| **OVH** | REST API | OVH API credentials required |
|
||||
| **Namecheap** | XML API | API access must be enabled in account |
|
||||
| **GoDaddy** | REST API | Production API key required |
|
||||
| **DNSimple** | REST API | v2 API |
|
||||
| **NS1** | REST API | NS1 Managed DNS |
|
||||
|
||||
### Tier 3: Alternative Methods
|
||||
|
||||
For providers without direct API support or custom DNS infrastructure:
|
||||
|
||||
| Method | Use Case | Documentation |
|
||||
|--------|----------|---------------|
|
||||
| **RFC 2136** | Self-hosted BIND9, PowerDNS, Knot DNS | [RFC 2136 Setup](./dns-providers.md#rfc-2136-dynamic-dns) |
|
||||
| **Webhook** | Custom DNS APIs, automation platforms | [Webhook Provider](./dns-providers.md#webhook-provider) |
|
||||
| **Script** | Legacy tools, custom integrations | [Script Provider](./dns-providers.md#script-provider) |
|
||||
| **Manual** | Any DNS provider (user creates records) | [Manual DNS Challenge](#manual-dns-challenge) |
|
||||
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before configuring DNS challenge:
|
||||
|
||||
1. ✅ A domain name you control
|
||||
2. ✅ Access to your DNS provider's control panel
|
||||
3. ✅ API credentials from your DNS provider (see provider-specific guides below)
|
||||
4. ✅ Charon installed and running
|
||||
|
||||
### Step 1: Add a DNS Provider
|
||||
|
||||
1. Navigate to **Settings** → **DNS Providers** in Charon
|
||||
2. Click **"Add DNS Provider"**
|
||||
3. Select your DNS provider from the dropdown
|
||||
4. Enter a descriptive name (e.g., "Cloudflare - Production")
|
||||
|
||||
### Step 2: Configure API Credentials
|
||||
|
||||
Each provider requires specific credentials. See provider-specific sections below.
|
||||
|
||||
> **Security Note**: All credentials are encrypted with AES-256-GCM before storage. See [Key Rotation](./key-rotation.md) for credential security best practices.
|
||||
|
||||
### Step 3: Test the Connection
|
||||
|
||||
1. After saving, click **"Test Connection"** on the provider card
|
||||
2. Charon will verify API access by attempting to list DNS zones
|
||||
3. A green checkmark indicates successful authentication
|
||||
|
||||
### Step 4: Request a Certificate
|
||||
|
||||
1. Navigate to **Certificates** → **Request Certificate**
|
||||
2. Enter your domain name:
|
||||
- For standard certificate: `example.com`
|
||||
- For wildcard certificate: `*.example.com`
|
||||
3. Select **"DNS-01"** as the challenge type
|
||||
4. Choose your configured DNS provider
|
||||
5. Click **"Request Certificate"**
|
||||
|
||||
### Step 5: Monitor Progress
|
||||
|
||||
The certificate request progresses through these stages:
|
||||
|
||||
```
|
||||
Pending → Creating DNS Record → Waiting for Propagation → Validating → Issued
|
||||
```
|
||||
|
||||
- **Creating DNS Record**: Charon creates the `_acme-challenge` TXT record
|
||||
- **Waiting for Propagation**: DNS changes propagate globally (typically 30-120 seconds)
|
||||
- **Validating**: CA verifies the DNS record
|
||||
- **Issued**: Certificate is ready for use
|
||||
|
||||
---
|
||||
|
||||
## Provider-Specific Setup
|
||||
|
||||
### Cloudflare Setup
|
||||
|
||||
Cloudflare is the recommended DNS provider due to fast propagation and excellent API support.
|
||||
|
||||
#### Creating API Credentials
|
||||
|
||||
**Option A: API Token (Recommended)**
|
||||
|
||||
1. Log in to [Cloudflare Dashboard](https://dash.cloudflare.com)
|
||||
2. Go to **My Profile** → **API Tokens**
|
||||
3. Click **"Create Token"**
|
||||
4. Select **"Edit zone DNS"** template
|
||||
5. Configure permissions:
|
||||
- **Zone**: DNS → Edit
|
||||
- **Zone Resources**: Include → Specific zone → Your domain
|
||||
6. Click **"Continue to summary"** → **"Create Token"**
|
||||
7. Copy the token (shown only once)
|
||||
|
||||
**Option B: Global API Key (Not Recommended)**
|
||||
|
||||
1. Go to **My Profile** → **API Tokens**
|
||||
2. Scroll to **"API Keys"** section
|
||||
3. Click **"View"** next to **"Global API Key"**
|
||||
4. Copy the key
|
||||
|
||||
#### Charon Configuration
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Provider Type** | Cloudflare |
|
||||
| **API Token** | Your API token (from Option A) |
|
||||
| **Email** | (Required only for Global API Key) |
|
||||
|
||||
### Route53 Setup
|
||||
|
||||
AWS Route53 requires IAM credentials with specific DNS permissions.
|
||||
|
||||
#### Creating IAM Policy
|
||||
|
||||
Create a custom IAM policy with these permissions:
|
||||
|
||||
```json
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Effect": "Allow",
|
||||
"Action": [
|
||||
"route53:GetHostedZone",
|
||||
"route53:ListHostedZones",
|
||||
"route53:ListHostedZonesByName",
|
||||
"route53:ChangeResourceRecordSets",
|
||||
"route53:GetChange"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
> **Security Tip**: For production, restrict `Resource` to specific hosted zone ARNs.
|
||||
|
||||
#### Creating IAM User
|
||||
|
||||
1. Go to **IAM** → **Users** → **Add Users**
|
||||
2. Enter username (e.g., `charon-dns`)
|
||||
3. Select **"Access key - Programmatic access"**
|
||||
4. Attach the custom policy created above
|
||||
5. Complete user creation and save the **Access Key ID** and **Secret Access Key**
|
||||
|
||||
#### Charon Configuration
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Provider Type** | Route53 |
|
||||
| **Access Key ID** | Your IAM access key |
|
||||
| **Secret Access Key** | Your IAM secret key |
|
||||
| **Region** | (Optional) AWS region, e.g., `us-east-1` |
|
||||
|
||||
### DigitalOcean Setup
|
||||
|
||||
#### Creating API Token
|
||||
|
||||
1. Log in to [DigitalOcean Control Panel](https://cloud.digitalocean.com)
|
||||
2. Go to **API** → **Tokens/Keys**
|
||||
3. Click **"Generate New Token"**
|
||||
4. Enter a name (e.g., "Charon DNS")
|
||||
5. Select **"Write"** scope
|
||||
6. Click **"Generate Token"**
|
||||
7. Copy the token (shown only once)
|
||||
|
||||
#### Charon Configuration
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Provider Type** | DigitalOcean |
|
||||
| **API Token** | Your personal access token |
|
||||
|
||||
### Google Cloud Setup
|
||||
|
||||
#### Creating Service Account
|
||||
|
||||
1. Go to [Google Cloud Console](https://console.cloud.google.com)
|
||||
2. Select your project
|
||||
3. Navigate to **IAM & Admin** → **Service Accounts**
|
||||
4. Click **"Create Service Account"**
|
||||
5. Enter name (e.g., `charon-dns`)
|
||||
6. Grant role: **DNS Administrator** (`roles/dns.admin`)
|
||||
7. Click **"Create Key"** → **JSON**
|
||||
8. Download and secure the JSON key file
|
||||
|
||||
#### Charon Configuration
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Provider Type** | Google Cloud DNS |
|
||||
| **Project ID** | Your GCP project ID |
|
||||
| **Service Account JSON** | Contents of the JSON key file |
|
||||
|
||||
### Azure Setup
|
||||
|
||||
#### Creating Service Principal
|
||||
|
||||
```bash
|
||||
# Create service principal with DNS Zone Contributor role
|
||||
az ad sp create-for-rbac \
|
||||
--name "charon-dns" \
|
||||
--role "DNS Zone Contributor" \
|
||||
--scopes "/subscriptions/<subscription-id>/resourceGroups/<resource-group>/providers/Microsoft.Network/dnszones/<zone-name>"
|
||||
```
|
||||
|
||||
Save the output containing `appId`, `password`, and `tenant`.
|
||||
|
||||
#### Charon Configuration
|
||||
|
||||
| Field | Value |
|
||||
|-------|-------|
|
||||
| **Provider Type** | Azure DNS |
|
||||
| **Subscription ID** | Your Azure subscription ID |
|
||||
| **Resource Group** | Resource group containing DNS zone |
|
||||
| **Tenant ID** | Azure AD tenant ID |
|
||||
| **Client ID** | Service principal appId |
|
||||
| **Client Secret** | Service principal password |
|
||||
|
||||
---
|
||||
|
||||
## Manual DNS Challenge
|
||||
|
||||
For DNS providers not directly supported by Charon, you can use the **Manual DNS Challenge** workflow.
|
||||
|
||||
### When to Use Manual Challenge
|
||||
|
||||
- Your DNS provider lacks API support
|
||||
- Company policies restrict API credential storage
|
||||
- You prefer manual control over DNS records
|
||||
- Testing or one-time certificate requests
|
||||
|
||||
### Manual Challenge Workflow
|
||||
|
||||
#### Step 1: Initiate the Challenge
|
||||
|
||||
1. Navigate to **Certificates** → **Request Certificate**
|
||||
2. Enter your domain name
|
||||
3. Select **"DNS-01 (Manual)"** as the challenge type
|
||||
4. Click **"Request Certificate"**
|
||||
|
||||
#### Step 2: Create DNS Record
|
||||
|
||||
Charon displays the required DNS record:
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────────────┐
|
||||
│ Manual DNS Challenge Instructions │
|
||||
├──────────────────────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ Create the following DNS TXT record at your DNS provider: │
|
||||
│ │
|
||||
│ Record Name: _acme-challenge.example.com │
|
||||
│ Record Type: TXT │
|
||||
│ Record Value: dGVzdC12YWx1ZS1mb3ItYWNtZS1jaGFsbGVuZ2U= │
|
||||
│ TTL: 120 (or minimum allowed) │
|
||||
│ │
|
||||
│ ⏳ Waiting for confirmation... │
|
||||
│ │
|
||||
│ [ Copy Record Value ] [ I've Created the Record ] │
|
||||
└──────────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
#### Step 3: Add Record to DNS Provider
|
||||
|
||||
Log in to your DNS provider and create the TXT record:
|
||||
|
||||
**Example: Generic DNS Provider**
|
||||
|
||||
1. Navigate to DNS management for your domain
|
||||
2. Click **"Add Record"** or **"New DNS Record"**
|
||||
3. Configure:
|
||||
- **Type**: TXT
|
||||
- **Name/Host**: `_acme-challenge` (some providers auto-append domain)
|
||||
- **Value/Content**: The challenge token from Charon
|
||||
- **TTL**: 120 seconds (or minimum allowed)
|
||||
4. Save the record
|
||||
|
||||
#### Step 4: Verify DNS Propagation
|
||||
|
||||
Before confirming, verify the record has propagated:
|
||||
|
||||
**Using dig command:**
|
||||
|
||||
```bash
|
||||
dig TXT _acme-challenge.example.com +short
|
||||
```
|
||||
|
||||
**Expected output:**
|
||||
|
||||
```
|
||||
"dGVzdC12YWx1ZS1mb3ItYWNtZS1jaGFsbGVuZ2U="
|
||||
```
|
||||
|
||||
**Using online tools:**
|
||||
|
||||
- [DNSChecker](https://dnschecker.org)
|
||||
- [MXToolbox](https://mxtoolbox.com/TXTLookup.aspx)
|
||||
- [WhatsMyDNS](https://whatsmydns.net)
|
||||
|
||||
#### Step 5: Confirm Record Creation
|
||||
|
||||
1. Return to Charon
|
||||
2. Click **"I've Created the Record"**
|
||||
3. Charon verifies the record and completes validation
|
||||
4. Certificate is issued upon successful verification
|
||||
|
||||
#### Step 6: Cleanup (Automatic)
|
||||
|
||||
Charon displays instructions to remove the TXT record after certificate issuance. While optional, removing challenge records is recommended for cleaner DNS configuration.
|
||||
|
||||
### Manual Challenge Tips
|
||||
|
||||
- ✅ **Wait for propagation**: DNS changes can take 1-60 minutes to propagate globally
|
||||
- ✅ **Check exact record name**: Some providers require `_acme-challenge`, others need `_acme-challenge.example.com`
|
||||
- ✅ **Verify before confirming**: Use `dig` or online tools to confirm the record exists
|
||||
- ✅ **Mind the TTL**: Lower TTL values speed up propagation but may not be supported by all providers
|
||||
- ❌ **Don't include quotes**: The TXT value should be the raw token, not wrapped in quotes (unless your provider requires it)
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### DNS Propagation Delays
|
||||
|
||||
**Symptom**: Certificate request stuck at "Waiting for Propagation" or validation fails.
|
||||
|
||||
**Causes**:
|
||||
- DNS TTL is high (cached old records)
|
||||
- DNS provider has slow propagation
|
||||
- Regional DNS inconsistency
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Verify the record exists locally:**
|
||||
|
||||
```bash
|
||||
dig TXT _acme-challenge.example.com @8.8.8.8
|
||||
```
|
||||
|
||||
2. **Check multiple DNS servers:**
|
||||
|
||||
```bash
|
||||
dig TXT _acme-challenge.example.com @1.1.1.1
|
||||
dig TXT _acme-challenge.example.com @208.67.222.222
|
||||
```
|
||||
|
||||
3. **Wait longer**: Some providers take up to 60 minutes for full propagation
|
||||
|
||||
4. **Lower TTL**: If possible, set TTL to 120 seconds or lower before requesting certificates
|
||||
|
||||
5. **Retry the request**: Cancel and retry after confirming DNS propagation
|
||||
|
||||
#### Invalid API Credentials
|
||||
|
||||
**Symptom**: "Authentication failed" or "Invalid credentials" error when testing connection.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
| Provider | Common Issues |
|
||||
|----------|---------------|
|
||||
| **Cloudflare** | Token expired, wrong zone permissions, using Global API Key without email |
|
||||
| **Route53** | IAM policy missing required actions, wrong region |
|
||||
| **DigitalOcean** | Token has read-only scope (needs write) |
|
||||
| **Google Cloud** | Wrong project ID, service account lacks DNS Admin role |
|
||||
|
||||
**Verification Steps**:
|
||||
|
||||
1. **Re-check credentials**: Copy-paste directly from provider, avoid manual typing
|
||||
2. **Verify permissions**: Ensure API token/key has DNS edit permissions
|
||||
3. **Test API directly**: Use provider's API documentation to test credentials independently
|
||||
4. **Check for typos**: Especially in email addresses and project IDs
|
||||
|
||||
#### Permission Denied / Access Denied
|
||||
|
||||
**Symptom**: Connection test passes, but record creation fails.
|
||||
|
||||
**Causes**:
|
||||
- API token has read-only permissions
|
||||
- Zone/domain not accessible with current credentials
|
||||
- Rate limiting or account restrictions
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Cloudflare**: Ensure token has "Zone:DNS:Edit" permission for the specific zone
|
||||
2. **Route53**: Verify IAM policy includes `ChangeResourceRecordSets` action
|
||||
3. **DigitalOcean**: Confirm token has "Write" scope
|
||||
4. **Google Cloud**: Service account needs "DNS Administrator" role
|
||||
|
||||
#### DNS Record Already Exists
|
||||
|
||||
**Symptom**: "Record already exists" error during certificate request.
|
||||
|
||||
**Causes**:
|
||||
- Previous challenge attempt left orphaned record
|
||||
- Manual DNS record with same name exists
|
||||
- Another ACME client managing the same domain
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Delete existing record**: Log in to DNS provider and remove the `_acme-challenge` TXT record
|
||||
2. **Wait for deletion**: Allow time for deletion to propagate
|
||||
3. **Retry certificate request**
|
||||
|
||||
#### CAA Record Issues
|
||||
|
||||
**Symptom**: Certificate Authority refuses to issue certificate despite successful DNS validation.
|
||||
|
||||
**Cause**: CAA (Certificate Authority Authorization) DNS records restrict which CAs can issue certificates.
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Check CAA records:**
|
||||
|
||||
```bash
|
||||
dig CAA example.com
|
||||
```
|
||||
|
||||
2. **Add Let's Encrypt to CAA** (if CAA records exist):
|
||||
|
||||
```
|
||||
example.com. CAA 0 issue "letsencrypt.org"
|
||||
example.com. CAA 0 issuewild "letsencrypt.org"
|
||||
```
|
||||
|
||||
3. **Remove restrictive CAA records** (if you don't need CAA enforcement)
|
||||
|
||||
#### Rate Limiting
|
||||
|
||||
**Symptom**: "Too many requests" or "Rate limit exceeded" errors.
|
||||
|
||||
**Causes**:
|
||||
- Too many certificate requests in short period
|
||||
- DNS provider API rate limits
|
||||
- Let's Encrypt rate limits
|
||||
|
||||
**Solutions**:
|
||||
|
||||
1. **Wait and retry**: Most rate limits reset within 1 hour
|
||||
2. **Use staging environment**: For testing, use Let's Encrypt staging to avoid production rate limits
|
||||
3. **Consolidate domains**: Use SANs or wildcards to reduce certificate count
|
||||
4. **Check provider limits**: Some DNS providers have low API rate limits
|
||||
|
||||
### DNS Provider-Specific Issues
|
||||
|
||||
#### Cloudflare
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "Invalid API Token" | Regenerate token with correct zone permissions |
|
||||
| "Zone not found" | Ensure domain is active in Cloudflare account |
|
||||
| "Rate limited" | Wait 5 minutes; Cloudflare allows 1200 requests/5 min |
|
||||
|
||||
#### Route53
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "Access Denied" | Check IAM policy includes all required actions |
|
||||
| "NoSuchHostedZone" | Verify hosted zone ID is correct |
|
||||
| "Throttling" | Implement exponential backoff; Route53 has strict rate limits |
|
||||
|
||||
#### DigitalOcean
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| "Unable to authenticate" | Regenerate token with Write scope |
|
||||
| "Domain not found" | Ensure domain is added to DigitalOcean DNS |
|
||||
|
||||
### Getting Help
|
||||
|
||||
If issues persist:
|
||||
|
||||
1. **Check Charon logs**: Look for detailed error messages in container logs
|
||||
2. **Enable debug mode**: Set `LOG_LEVEL=debug` for verbose logging
|
||||
3. **Search existing issues**: [GitHub Issues](https://github.com/Wikid82/charon/issues)
|
||||
4. **Open a new issue**: Include Charon version, provider type, and sanitized error messages
|
||||
|
||||
---
|
||||
|
||||
## Related Documentation
|
||||
|
||||
### Feature Guides
|
||||
|
||||
- [DNS Provider Types](./dns-providers.md) — RFC 2136, Webhook, and Script providers
|
||||
- [DNS Auto-Detection](./dns-auto-detection.md) — Automatic provider identification
|
||||
- [Multi-Credential Support](./multi-credential.md) — Managing multiple credentials per provider
|
||||
- [Key Rotation](./key-rotation.md) — Credential encryption and rotation
|
||||
|
||||
### General Documentation
|
||||
|
||||
- [Getting Started](../getting-started.md) — Initial Charon setup
|
||||
- [Security Best Practices](../security.md) — Securing your Charon installation
|
||||
- [API Reference](../api.md) — Programmatic certificate management
|
||||
- [Troubleshooting Guide](../troubleshooting/) — General troubleshooting
|
||||
|
||||
### External Resources
|
||||
|
||||
- [Let's Encrypt Documentation](https://letsencrypt.org/docs/)
|
||||
- [ACME Protocol RFC 8555](https://datatracker.ietf.org/doc/html/rfc8555)
|
||||
- [DNS-01 Challenge Specification](https://letsencrypt.org/docs/challenge-types/#dns-01-challenge)
|
||||
|
||||
---
|
||||
|
||||
*Last Updated: January 2026*
|
||||
*Charon Version: 0.1.0-beta*
|
||||
@@ -1,307 +0,0 @@
|
||||
# DNS Provider Types
|
||||
|
||||
This document describes the DNS provider types available in Charon for DNS-01 challenge validation during SSL certificate issuance.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon supports multiple DNS provider types to accommodate different deployment scenarios:
|
||||
|
||||
| Provider Type | Use Case | Security Level |
|
||||
|---------------|----------|----------------|
|
||||
| **API-Based** | Cloudflare, Route53, DigitalOcean, etc. | ✅ Recommended |
|
||||
| **RFC 2136** | Self-hosted BIND9, PowerDNS, Knot DNS | ✅ Recommended |
|
||||
| **Webhook** | Custom DNS APIs, automation platforms | ⚠️ Moderate |
|
||||
| **Script** | Legacy tools, custom integrations | ⚠️ High Risk |
|
||||
|
||||
---
|
||||
|
||||
## RFC 2136 (Dynamic DNS)
|
||||
|
||||
RFC 2136 Dynamic DNS Update allows Charon to directly update DNS records on authoritative DNS servers that support the protocol, using TSIG authentication for security.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Self-hosted BIND9, PowerDNS, or Knot DNS servers
|
||||
- Enterprise environments with existing DNS infrastructure
|
||||
- Air-gapped networks without external API access
|
||||
- ISP or hosting provider managed DNS with RFC 2136 support
|
||||
|
||||
### Configuration
|
||||
|
||||
| Field | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `nameserver` | ✅ | — | DNS server hostname or IP address |
|
||||
| `tsig_key_name` | ✅ | — | TSIG key name (e.g., `acme-update.`) |
|
||||
| `tsig_key_secret` | ✅ | — | Base64-encoded TSIG key secret |
|
||||
| `port` | ❌ | `53` | DNS server port |
|
||||
| `tsig_algorithm` | ❌ | `hmac-sha256` | TSIG algorithm (see below) |
|
||||
| `zone` | ❌ | — | DNS zone override (auto-detected if not set) |
|
||||
|
||||
### TSIG Algorithms
|
||||
|
||||
| Algorithm | Recommendation |
|
||||
|-----------|----------------|
|
||||
| `hmac-sha256` | ✅ **Recommended** — Good balance of security and compatibility |
|
||||
| `hmac-sha384` | ✅ Secure — Higher security, wider key |
|
||||
| `hmac-sha512` | ✅ Secure — Maximum security |
|
||||
| `hmac-sha1` | ⚠️ Legacy — Use only if required by older systems |
|
||||
| `hmac-md5` | ❌ **Deprecated** — Avoid; cryptographically weak |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "rfc2136",
|
||||
"nameserver": "ns1.example.com",
|
||||
"port": 53,
|
||||
"tsig_key_name": "acme-update.",
|
||||
"tsig_key_secret": "base64EncodedSecretKey==",
|
||||
"tsig_algorithm": "hmac-sha256",
|
||||
"zone": "example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### Generating a TSIG Key (BIND9)
|
||||
|
||||
```bash
|
||||
# Generate a new TSIG key
|
||||
tsig-keygen -a hmac-sha256 acme-update > /etc/bind/acme-update.key
|
||||
|
||||
# Contents of generated key file:
|
||||
# key "acme-update" {
|
||||
# algorithm hmac-sha256;
|
||||
# secret "base64EncodedSecretKey==";
|
||||
# };
|
||||
```
|
||||
|
||||
### Security Notes
|
||||
|
||||
- **Network Security**: Ensure the DNS server is reachable from Charon (firewall rules, VPN)
|
||||
- **Key Permissions**: TSIG keys should have minimal permissions (only `_acme-challenge` records)
|
||||
- **Key Rotation**: Rotate TSIG keys periodically (recommended: every 90 days)
|
||||
- **TLS Not Supported**: RFC 2136 uses UDP/TCP without encryption; use network-level security
|
||||
|
||||
---
|
||||
|
||||
## Webhook Provider
|
||||
|
||||
The Webhook provider enables integration with custom DNS APIs or automation platforms by sending HTTP requests to user-defined endpoints.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Custom internal DNS management APIs
|
||||
- Integration with automation platforms (Ansible AWX, Rundeck, etc.)
|
||||
- DNS providers without native Charon support
|
||||
- Multi-system orchestration workflows
|
||||
|
||||
### Configuration
|
||||
|
||||
| Field | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `create_url` | ✅ | — | URL to call when creating TXT records |
|
||||
| `delete_url` | ✅ | — | URL to call when deleting TXT records |
|
||||
| `auth_header` | ❌ | — | HTTP header name for authentication (e.g., `Authorization`) |
|
||||
| `auth_value` | ❌ | — | HTTP header value (e.g., `Bearer token123`) |
|
||||
| `timeout_seconds` | ❌ | `30` | Request timeout in seconds |
|
||||
| `retry_count` | ❌ | `3` | Number of retry attempts on failure |
|
||||
| `insecure_skip_verify` | ❌ | `false` | Skip TLS verification (⚠️ dev only) |
|
||||
|
||||
### URL Template Variables
|
||||
|
||||
The following variables are available in `create_url` and `delete_url`:
|
||||
|
||||
| Variable | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `{{fqdn}}` | Full record name | `_acme-challenge.example.com` |
|
||||
| `{{domain}}` | Base domain | `example.com` |
|
||||
| `{{value}}` | TXT record value | `dGVzdC12YWx1ZQ==` |
|
||||
| `{{ttl}}` | Record TTL | `120` |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "webhook",
|
||||
"create_url": "https://dns-api.example.com/records?action=create&fqdn={{fqdn}}&value={{value}}",
|
||||
"delete_url": "https://dns-api.example.com/records?action=delete&fqdn={{fqdn}}",
|
||||
"auth_header": "Authorization",
|
||||
"auth_value": "Bearer your-api-token",
|
||||
"timeout_seconds": 30,
|
||||
"retry_count": 3
|
||||
}
|
||||
```
|
||||
|
||||
### Webhook Request Format
|
||||
|
||||
**Create Request:**
|
||||
|
||||
```http
|
||||
POST {{create_url}}
|
||||
Content-Type: application/json
|
||||
{{auth_header}}: {{auth_value}}
|
||||
|
||||
{
|
||||
"fqdn": "_acme-challenge.example.com",
|
||||
"domain": "example.com",
|
||||
"value": "challenge-token-value",
|
||||
"ttl": 120
|
||||
}
|
||||
```
|
||||
|
||||
**Delete Request:**
|
||||
|
||||
```http
|
||||
POST {{delete_url}}
|
||||
Content-Type: application/json
|
||||
{{auth_header}}: {{auth_value}}
|
||||
|
||||
{
|
||||
"fqdn": "_acme-challenge.example.com",
|
||||
"domain": "example.com"
|
||||
}
|
||||
```
|
||||
|
||||
### Expected Responses
|
||||
|
||||
| Status Code | Meaning |
|
||||
|-------------|---------|
|
||||
| `200`, `201`, `204` | Success |
|
||||
| `4xx` | Client error — check configuration |
|
||||
| `5xx` | Server error — will retry based on `retry_count` |
|
||||
|
||||
### Security Notes
|
||||
|
||||
- **HTTPS Required**: Non-localhost URLs must use HTTPS
|
||||
- **Authentication**: Always use `auth_header` and `auth_value` for production
|
||||
- **Timeouts**: Set appropriate timeouts to avoid blocking certificate issuance
|
||||
- **`insecure_skip_verify`**: Never enable in production; only for local development with self-signed certs
|
||||
|
||||
---
|
||||
|
||||
## Script Provider
|
||||
|
||||
The Script provider executes shell scripts to manage DNS records, enabling integration with legacy systems or tools without API access.
|
||||
|
||||
### ⚠️ HIGH-RISK PROVIDER
|
||||
|
||||
> **Warning**: Scripts execute with container privileges. Only use when no other option is available. Thoroughly audit all scripts before deployment.
|
||||
|
||||
### Use Cases
|
||||
|
||||
- Legacy DNS management tools (nsupdate wrappers, custom CLIs)
|
||||
- Systems requiring SSH-based updates
|
||||
- Complex multi-step DNS workflows
|
||||
- Air-gapped environments with local tooling
|
||||
|
||||
### Configuration
|
||||
|
||||
| Field | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `script_path` | ✅ | — | Path to script (must be in `/scripts/`) |
|
||||
| `timeout_seconds` | ❌ | `60` | Maximum script execution time |
|
||||
| `env_vars` | ❌ | — | Environment variables (`KEY=VALUE` format) |
|
||||
|
||||
### Script Interface
|
||||
|
||||
Scripts receive DNS operation details via environment variables:
|
||||
|
||||
| Variable | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `DNS_ACTION` | Operation type | `create` or `delete` |
|
||||
| `DNS_FQDN` | Full record name | `_acme-challenge.example.com` |
|
||||
| `DNS_DOMAIN` | Base domain | `example.com` |
|
||||
| `DNS_VALUE` | TXT record value (create only) | `challenge-token` |
|
||||
| `DNS_TTL` | Record TTL (create only) | `120` |
|
||||
|
||||
**Exit Codes:**
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| `0` | Success |
|
||||
| `1` | Failure (generic) |
|
||||
| `2` | Configuration error |
|
||||
|
||||
### Example Configuration
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "script",
|
||||
"script_path": "/scripts/dns-update.sh",
|
||||
"timeout_seconds": 60,
|
||||
"env_vars": "DNS_SERVER=ns1.example.com,SSH_KEY_PATH=/secrets/dns-key"
|
||||
}
|
||||
```
|
||||
|
||||
### Example Script
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# /scripts/dns-update.sh
|
||||
set -euo pipefail
|
||||
|
||||
case "$DNS_ACTION" in
|
||||
create)
|
||||
echo "Creating TXT record: $DNS_FQDN = $DNS_VALUE"
|
||||
nsupdate -k /etc/bind/keys/update.key <<EOF
|
||||
server $DNS_SERVER
|
||||
update add $DNS_FQDN $DNS_TTL TXT "$DNS_VALUE"
|
||||
send
|
||||
EOF
|
||||
;;
|
||||
delete)
|
||||
echo "Deleting TXT record: $DNS_FQDN"
|
||||
nsupdate -k /etc/bind/keys/update.key <<EOF
|
||||
server $DNS_SERVER
|
||||
update delete $DNS_FQDN TXT
|
||||
send
|
||||
EOF
|
||||
;;
|
||||
*)
|
||||
echo "Unknown action: $DNS_ACTION" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
```
|
||||
|
||||
### Security Requirements
|
||||
|
||||
| Requirement | Details |
|
||||
|-------------|---------|
|
||||
| **Script Location** | Must be in `/scripts/` directory (enforced) |
|
||||
| **Permissions** | Script must be executable (`chmod +x`) |
|
||||
| **Audit** | Review all scripts before deployment |
|
||||
| **Secrets** | Use mounted secrets, never hardcode credentials |
|
||||
| **Timeouts** | Set appropriate timeouts to prevent hanging |
|
||||
|
||||
### Security Notes
|
||||
|
||||
- **Container Privileges**: Scripts run with full container privileges
|
||||
- **Path Restriction**: Scripts must reside in `/scripts/` to prevent arbitrary execution
|
||||
- **No User Input**: Script path cannot contain user-supplied data
|
||||
- **Logging**: All script executions are logged to audit trail
|
||||
- **Resource Limits**: Use `timeout_seconds` to prevent runaway scripts
|
||||
- **Testing**: Test scripts thoroughly in non-production before deployment
|
||||
|
||||
---
|
||||
|
||||
## Provider Comparison
|
||||
|
||||
| Feature | RFC 2136 | Webhook | Script |
|
||||
|---------|----------|---------|--------|
|
||||
| **Setup Complexity** | Medium | Low | High |
|
||||
| **Security** | High (TSIG) | Medium (HTTPS) | Low (shell) |
|
||||
| **Flexibility** | DNS servers only | HTTP APIs | Unlimited |
|
||||
| **Debugging** | DNS tools | HTTP logs | Script logs |
|
||||
| **Recommended For** | Self-hosted DNS | Custom APIs | Legacy only |
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [DNS Provider Auto-Detection](./dns-auto-detection.md) — Automatic provider identification
|
||||
- [Multi-Credential DNS Support](./multi-credential.md) — Managing multiple credentials per provider
|
||||
- [Key Rotation](./key-rotation.md) — Credential rotation best practices
|
||||
- [Audit Logging](./audit-logging.md) — Tracking DNS operations
|
||||
|
||||
---
|
||||
|
||||
_Last Updated: January 2026_
|
||||
_Version: 1.4.0_
|
||||
@@ -1,151 +0,0 @@
|
||||
---
|
||||
title: Docker Auto-Discovery
|
||||
description: Automatically find and proxy Docker containers with one click
|
||||
category: integration
|
||||
---
|
||||
|
||||
# Docker Auto-Discovery
|
||||
|
||||
Already running apps in Docker? Charon automatically finds your containers and offers one-click proxy setup. Supports both local Docker installations and remote Docker servers.
|
||||
|
||||
## Overview
|
||||
|
||||
Docker auto-discovery eliminates manual IP address hunting and port memorization. Charon queries the Docker API to list running containers, extracts their network information, and lets you create proxy configurations with a single click.
|
||||
|
||||
### How It Works
|
||||
|
||||
1. Charon connects to Docker via socket or TCP
|
||||
2. Queries running containers and their exposed ports
|
||||
3. Displays container list with network details
|
||||
4. You select a container and assign a domain
|
||||
5. Charon creates the proxy configuration automatically
|
||||
|
||||
## Why Use This
|
||||
|
||||
### Eliminate IP Address Hunting
|
||||
|
||||
- No more running `docker inspect` to find container IPs
|
||||
- No more updating configs when containers restart with new IPs
|
||||
- Container name resolution handles dynamic addressing
|
||||
|
||||
### Accelerate Development
|
||||
|
||||
- Spin up a new service, proxy it in seconds
|
||||
- Test different versions by proxying multiple containers
|
||||
- Remove proxies as easily as you create them
|
||||
|
||||
### Simplify Team Workflows
|
||||
|
||||
- Developers create their own proxy entries
|
||||
- No central config file bottlenecks
|
||||
- Self-service infrastructure access
|
||||
|
||||
## Configuration
|
||||
|
||||
### Docker Socket Mounting
|
||||
|
||||
For Charon to discover containers, it needs Docker API access.
|
||||
|
||||
**Docker Compose:**
|
||||
```yaml
|
||||
services:
|
||||
charon:
|
||||
image: charon:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
```
|
||||
|
||||
**Docker Run:**
|
||||
```bash
|
||||
docker run -v /var/run/docker.sock:/var/run/docker.sock:ro charon
|
||||
```
|
||||
|
||||
> **Security Note**: The socket grants significant access. Use read-only mode (`:ro`) and consider Docker socket proxies for production.
|
||||
|
||||
### Remote Docker Server Support
|
||||
|
||||
Connect to Docker hosts over TCP:
|
||||
|
||||
1. Go to **Settings** → **Docker**
|
||||
2. Click **Add Remote Host**
|
||||
3. Enter connection details:
|
||||
- **Name**: Friendly identifier
|
||||
- **Host**: IP or hostname
|
||||
- **Port**: Docker API port (default: 2375/2376)
|
||||
- **TLS**: Enable for secure connections
|
||||
4. Upload TLS certificates if required
|
||||
5. Click **Test Connection**, then **Save**
|
||||
|
||||
## Container Selection Workflow
|
||||
|
||||
### Viewing Available Containers
|
||||
|
||||
1. Navigate to **Hosts** → **Add Host**
|
||||
2. Click **Select from Docker**
|
||||
3. Choose Docker host (local or remote)
|
||||
4. Browse running containers
|
||||
|
||||
### Container List Display
|
||||
|
||||
Each container shows:
|
||||
|
||||
- **Name**: Container name
|
||||
- **Image**: Source image and tag
|
||||
- **Ports**: Exposed ports and mappings
|
||||
- **Networks**: Connected Docker networks
|
||||
- **Status**: Running, paused, etc.
|
||||
|
||||
### Creating a Proxy
|
||||
|
||||
1. Click a container row to select it
|
||||
2. If multiple ports are exposed, choose the target port
|
||||
3. Enter the domain name for this proxy
|
||||
4. Configure SSL options
|
||||
5. Click **Create Host**
|
||||
|
||||
### Automatic Updates
|
||||
|
||||
When containers restart:
|
||||
|
||||
- Charon continues proxying to the container name
|
||||
- Docker's internal DNS resolves the new IP
|
||||
- No manual intervention required
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Network Selection
|
||||
|
||||
If a container is on multiple networks, specify which network Charon should use for routing:
|
||||
|
||||
1. Edit the host after creation
|
||||
2. Go to **Advanced** → **Docker**
|
||||
3. Select the preferred network
|
||||
|
||||
### Port Override
|
||||
|
||||
Override the auto-detected port:
|
||||
|
||||
1. Edit the host
|
||||
2. Change the backend URL port manually
|
||||
3. Useful for containers with non-standard port configurations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Cause | Solution |
|
||||
|-------|-------|----------|
|
||||
| No containers shown | Socket not mounted | Add Docker socket volume |
|
||||
| Connection refused | Remote Docker not configured | Enable TCP API on Docker host |
|
||||
| Container not proxied | Container not running | Start the container |
|
||||
| Wrong IP resolved | Multi-network container | Specify network in advanced settings |
|
||||
|
||||
## Security Considerations
|
||||
|
||||
- **Socket Access**: Docker socket provides root-equivalent access. Mount read-only.
|
||||
- **Remote Connections**: Always use TLS for remote Docker hosts.
|
||||
- **Network Isolation**: Use Docker networks to segment container communication.
|
||||
|
||||
## Related
|
||||
|
||||
- [Web UI](web-ui.md) - Point & click management
|
||||
- [SSL Certificates](ssl-certificates.md) - Automatic HTTPS for proxied containers
|
||||
- [Back to Features](../features.md)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
---
|
||||
title: Zero-Downtime Updates
|
||||
description: Make changes without interrupting your users
|
||||
---
|
||||
|
||||
# Zero-Downtime Updates
|
||||
|
||||
Make changes without interrupting your users. Update domains, modify security rules, or add new services instantly. Your sites stay up while you work—no container restarts needed.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon leverages Caddy's live reload capability to apply configuration changes without dropping connections. When you save changes in the UI, Caddy gracefully transitions to the new configuration while maintaining all active connections.
|
||||
|
||||
This means your users experience zero interruption—even during significant configuration changes.
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **No Downtime**: Active connections remain unaffected
|
||||
- **Instant Changes**: New configuration takes effect immediately
|
||||
- **Safe Iteration**: Make frequent adjustments without risk
|
||||
- **Production Friendly**: Update live systems confidently
|
||||
|
||||
## How It Works
|
||||
|
||||
When you save configuration changes:
|
||||
|
||||
1. Charon generates updated Caddy configuration
|
||||
2. Caddy validates the new configuration
|
||||
3. If valid, Caddy atomically swaps to the new config
|
||||
4. Existing connections continue on old config until complete
|
||||
5. New connections use the updated configuration
|
||||
|
||||
The entire process typically completes in milliseconds.
|
||||
|
||||
## What Can Be Changed Live
|
||||
|
||||
These changes apply instantly without any restart:
|
||||
|
||||
| Change Type | Live Reload |
|
||||
|-------------|-------------|
|
||||
| Add/remove proxy hosts | ✅ Yes |
|
||||
| Modify upstream servers | ✅ Yes |
|
||||
| Update SSL certificates | ✅ Yes |
|
||||
| Change access lists | ✅ Yes |
|
||||
| Modify headers | ✅ Yes |
|
||||
| Update redirects | ✅ Yes |
|
||||
| Add/remove domains | ✅ Yes |
|
||||
|
||||
## CrowdSec Integration Note
|
||||
|
||||
> **Important**: CrowdSec integration requires a one-time container restart when first enabled or when changing the CrowdSec API endpoint.
|
||||
|
||||
After the initial setup, CrowdSec decisions update automatically without restart. Only the connection to the CrowdSec API requires the restart.
|
||||
|
||||
To minimize disruption:
|
||||
|
||||
1. Configure CrowdSec during a maintenance window
|
||||
2. After restart, all future updates are live
|
||||
|
||||
## Validation and Rollback
|
||||
|
||||
Charon validates all configuration changes before applying:
|
||||
|
||||
- **Syntax Validation**: Catches configuration errors
|
||||
- **Connection Testing**: Verifies upstream availability
|
||||
- **Automatic Rollback**: Invalid configs are rejected
|
||||
|
||||
If validation fails, your current configuration remains active and an error message explains the issue.
|
||||
|
||||
## Monitoring Changes
|
||||
|
||||
View configuration change history:
|
||||
|
||||
1. Check the **Real-Time Logs** for reload events
|
||||
2. Review **Settings** → **Backup** for configuration snapshots
|
||||
|
||||
## Related
|
||||
|
||||
- [Backup & Restore](backup-restore.md)
|
||||
- [Real-Time Logs](logs.md)
|
||||
- [CrowdSec Integration](crowdsec.md)
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,85 +0,0 @@
|
||||
---
|
||||
title: Multi-Language Support
|
||||
description: Interface available in English, Spanish, French, German, and Chinese
|
||||
---
|
||||
|
||||
# Multi-Language Support
|
||||
|
||||
Charon speaks your language. The interface is available in English, Spanish, French, German, and Chinese. Switch languages instantly in settings—no reload required.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon's interface is fully localized, making it accessible to users worldwide. All UI elements, error messages, and documentation links adapt to your selected language. Language switching happens instantly in the browser without requiring a page reload or server restart.
|
||||
|
||||
## Supported Languages
|
||||
|
||||
| Language | Code | Status |
|
||||
|----------|------|--------|
|
||||
| English | `en` | Complete (default) |
|
||||
| Spanish | `es` | Complete |
|
||||
| French | `fr` | Complete |
|
||||
| German | `de` | Complete |
|
||||
| Chinese (Simplified) | `zh` | Complete |
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Native Experience**: Use Charon in your preferred language
|
||||
- **Team Accessibility**: Support multilingual teams
|
||||
- **Instant Switching**: Change languages without interruption
|
||||
- **Complete Coverage**: All UI elements are translated
|
||||
|
||||
## Changing Language
|
||||
|
||||
To change the interface language:
|
||||
|
||||
1. Click your **username** in the top-right corner
|
||||
2. Select **Settings**
|
||||
3. Find the **Language** dropdown
|
||||
4. Select your preferred language
|
||||
|
||||
The interface updates immediately—no reload required.
|
||||
|
||||
### Per-User Setting
|
||||
|
||||
Language preference is stored per user account. Each team member can use Charon in their preferred language independently.
|
||||
|
||||
## Browser Language Detection
|
||||
|
||||
On first visit, Charon attempts to detect your browser's language preference. If a supported language matches, it's selected automatically. You can override this in settings at any time.
|
||||
|
||||
## What Gets Translated
|
||||
|
||||
- Navigation menus and buttons
|
||||
- Form labels and placeholders
|
||||
- Error and success messages
|
||||
- Tooltips and help text
|
||||
- Confirmation dialogs
|
||||
|
||||
## What Stays in English
|
||||
|
||||
Some technical content remains in English for consistency:
|
||||
|
||||
- Log messages (from Caddy/CrowdSec)
|
||||
- API responses
|
||||
- Configuration file syntax
|
||||
- Domain names and URLs
|
||||
|
||||
## Contributing Translations
|
||||
|
||||
Help improve Charon's translations or add new languages:
|
||||
|
||||
1. Review the [Contributing Translations Guide](../../CONTRIBUTING_TRANSLATIONS.md)
|
||||
2. Translation files are in the frontend `locales/` directory
|
||||
3. Submit improvements via pull request
|
||||
|
||||
We welcome contributions for:
|
||||
|
||||
- New language additions
|
||||
- Translation corrections
|
||||
- Context improvements
|
||||
|
||||
## Related
|
||||
|
||||
- [Contributing Translations](../../CONTRIBUTING_TRANSLATIONS.md)
|
||||
- [Settings](../getting-started/configuration.md)
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
title: Real-Time Logs
|
||||
description: Watch requests flow through your proxy in real-time
|
||||
---
|
||||
|
||||
# Real-Time Logs
|
||||
|
||||
Watch requests flow through your proxy in real-time. Filter by domain, status code, or time range to troubleshoot issues quickly. All the visibility you need without diving into container logs.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon provides real-time log streaming via WebSocket, giving you instant visibility into all proxy traffic and security events. The logging system includes two main views:
|
||||
|
||||
- **Access Logs**: All HTTP requests flowing through Caddy
|
||||
- **Security Logs**: Cerberus Dashboard showing CrowdSec decisions and WAF events
|
||||
|
||||
Logs stream directly to your browser with minimal latency, eliminating the need to SSH into containers or parse log files manually.
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Instant Troubleshooting**: See requests as they happen to diagnose issues in real-time
|
||||
- **Security Monitoring**: Watch for blocked threats and suspicious activity
|
||||
- **No CLI Required**: Everything accessible through the web interface
|
||||
- **Persistent Connection**: WebSocket keeps the stream open without polling
|
||||
|
||||
## Log Viewer Controls
|
||||
|
||||
The log viewer provides intuitive controls for managing the log stream:
|
||||
|
||||
| Control | Function |
|
||||
|---------|----------|
|
||||
| **Pause/Resume** | Temporarily stop the stream to examine specific entries |
|
||||
| **Clear** | Remove all displayed logs (doesn't affect server logs) |
|
||||
| **Auto-scroll** | Automatically scroll to newest entries (toggle on/off) |
|
||||
|
||||
## Filtering Options
|
||||
|
||||
Filter logs to focus on what matters:
|
||||
|
||||
- **Level**: Filter by severity (info, warning, error)
|
||||
- **Source**: Filter by service (caddy, crowdsec, cerberus)
|
||||
- **Text Search**: Free-text search across all log fields
|
||||
- **Time Range**: View logs from specific time periods
|
||||
|
||||
### Server-Side Query Parameters
|
||||
|
||||
For advanced filtering, use query parameters when connecting:
|
||||
|
||||
```text
|
||||
/api/logs/stream?level=error&source=crowdsec&limit=1000
|
||||
```
|
||||
|
||||
## WebSocket Connection
|
||||
|
||||
The log viewer displays connection status in the header:
|
||||
|
||||
- **Connected**: Green indicator, logs streaming
|
||||
- **Reconnecting**: Yellow indicator, automatic retry in progress
|
||||
- **Disconnected**: Red indicator, manual reconnect available
|
||||
|
||||
### Troubleshooting Connection Issues
|
||||
|
||||
If the WebSocket disconnects frequently:
|
||||
|
||||
1. Check browser console for errors
|
||||
2. Verify no proxy is blocking WebSocket upgrades
|
||||
3. Ensure the Charon container has sufficient resources
|
||||
4. Check for network timeouts on long-idle connections
|
||||
|
||||
## Related
|
||||
|
||||
- [WebSocket Support](websocket.md)
|
||||
- [CrowdSec Integration](crowdsec.md)
|
||||
- [Back to Features](../features.md)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,553 +0,0 @@
|
||||
# Notification System
|
||||
|
||||
Charon's notification system keeps you informed about important events in your infrastructure through multiple channels, including Discord, Slack, Gotify, Telegram, and custom webhooks.
|
||||
|
||||
## Overview
|
||||
|
||||
Notifications can be triggered by various events:
|
||||
|
||||
- **SSL Certificate Events**: Issued, renewed, or failed
|
||||
- **Uptime Monitoring**: Host status changes (up/down)
|
||||
- **Security Events**: WAF blocks, CrowdSec alerts, ACL violations
|
||||
- **System Events**: Configuration changes, backup completions
|
||||
|
||||
## Supported Services
|
||||
|
||||
| Service | JSON Templates | Native API | Rich Formatting |
|
||||
|---------|----------------|------------|-----------------|
|
||||
| **Discord** | ✅ Yes | ✅ Webhooks | ✅ Embeds |
|
||||
| **Slack** | ✅ Yes | ✅ Incoming Webhooks | ✅ Block Kit |
|
||||
| **Gotify** | ✅ Yes | ✅ REST API | ✅ Extras |
|
||||
| **Generic Webhook** | ✅ Yes | ✅ HTTP POST | ✅ Custom |
|
||||
| **Telegram** | ❌ No | ✅ Bot API | ⚠️ Markdown |
|
||||
|
||||
### Why JSON Templates?
|
||||
|
||||
JSON templates give you complete control over notification formatting, allowing you to:
|
||||
|
||||
- **Customize appearance**: Use rich embeds, colors, and formatting
|
||||
- **Add metadata**: Include custom fields, timestamps, and links
|
||||
- **Optimize visibility**: Structure messages for better readability
|
||||
- **Integrate seamlessly**: Match your team's existing notification styles
|
||||
|
||||
## Configuration
|
||||
|
||||
### Basic Setup
|
||||
|
||||
1. Navigate to **Settings** → **Notifications**
|
||||
2. Click **"Add Provider"**
|
||||
3. Select your service type
|
||||
4. Enter the webhook URL
|
||||
5. Configure notification triggers
|
||||
6. Save your provider
|
||||
|
||||
### JSON Template Support
|
||||
|
||||
For services supporting JSON (Discord, Slack, Gotify, Generic, Webhook), you can choose from three template options:
|
||||
|
||||
#### 1. Minimal Template (Default)
|
||||
|
||||
Simple, clean notifications with essential information:
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "{{.Title}}: {{.Message}}"
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
|
||||
- You want low-noise notifications
|
||||
- Space is limited (mobile notifications)
|
||||
- Only essential info is needed
|
||||
|
||||
#### 2. Detailed Template
|
||||
|
||||
Comprehensive notifications with all available context:
|
||||
|
||||
```json
|
||||
{
|
||||
"embeds": [{
|
||||
"title": "{{.Title}}",
|
||||
"description": "{{.Message}}",
|
||||
"color": {{.Color}},
|
||||
"timestamp": "{{.Timestamp}}",
|
||||
"fields": [
|
||||
{"name": "Event Type", "value": "{{.EventType}}", "inline": true},
|
||||
{"name": "Host", "value": "{{.HostName}}", "inline": true}
|
||||
]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Use when:**
|
||||
|
||||
- You need full event context
|
||||
- Multiple team members review notifications
|
||||
- Historical tracking is important
|
||||
|
||||
#### 3. Custom Template
|
||||
|
||||
Create your own template with complete control over structure and formatting.
|
||||
|
||||
**Use when:**
|
||||
|
||||
- Standard templates don't meet your needs
|
||||
- You have specific formatting requirements
|
||||
- Integrating with custom systems
|
||||
|
||||
## Service-Specific Examples
|
||||
|
||||
### Discord Webhooks
|
||||
|
||||
Discord supports rich embeds with colors, fields, and timestamps.
|
||||
|
||||
#### Basic Embed
|
||||
|
||||
```json
|
||||
{
|
||||
"embeds": [{
|
||||
"title": "{{.Title}}",
|
||||
"description": "{{.Message}}",
|
||||
"color": {{.Color}},
|
||||
"timestamp": "{{.Timestamp}}"
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### Advanced Embed with Fields
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "Charon Alerts",
|
||||
"avatar_url": "https://example.com/charon-icon.png",
|
||||
"embeds": [{
|
||||
"title": "🚨 {{.Title}}",
|
||||
"description": "{{.Message}}",
|
||||
"color": {{.Color}},
|
||||
"timestamp": "{{.Timestamp}}",
|
||||
"fields": [
|
||||
{
|
||||
"name": "Event Type",
|
||||
"value": "{{.EventType}}",
|
||||
"inline": true
|
||||
},
|
||||
{
|
||||
"name": "Severity",
|
||||
"value": "{{.Severity}}",
|
||||
"inline": true
|
||||
},
|
||||
{
|
||||
"name": "Host",
|
||||
"value": "{{.HostName}}",
|
||||
"inline": false
|
||||
}
|
||||
],
|
||||
"footer": {
|
||||
"text": "Charon Notification System"
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
**Available Discord Colors:**
|
||||
|
||||
- `2326507` - Blue (info)
|
||||
- `15158332` - Red (error)
|
||||
- `16776960` - Yellow (warning)
|
||||
- `3066993` - Green (success)
|
||||
|
||||
### Slack Webhooks
|
||||
|
||||
Slack uses Block Kit for rich message formatting.
|
||||
|
||||
#### Basic Block
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "{{.Title}}",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "{{.Title}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "{{.Message}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Advanced Block with Context
|
||||
|
||||
```json
|
||||
{
|
||||
"text": "{{.Title}}",
|
||||
"blocks": [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "🔔 {{.Title}}",
|
||||
"emoji": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "*Event:* {{.EventType}}\n*Message:* {{.Message}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "section",
|
||||
"fields": [
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Host:*\n{{.HostName}}"
|
||||
},
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
"text": "*Time:*\n{{.Timestamp}}"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "context",
|
||||
"elements": [
|
||||
{
|
||||
"type": "mrkdwn",
|
||||
"text": "Notification from Charon"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Slack Markdown Tips:**
|
||||
|
||||
- `*bold*` for emphasis
|
||||
- `_italic_` for subtle text
|
||||
- `~strike~` for deprecated info
|
||||
- `` `code` `` for technical details
|
||||
- Use `\n` for line breaks
|
||||
|
||||
### Gotify Webhooks
|
||||
|
||||
Gotify supports JSON payloads with priority levels and extras.
|
||||
|
||||
#### Basic Message
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "{{.Title}}",
|
||||
"message": "{{.Message}}",
|
||||
"priority": 5
|
||||
}
|
||||
```
|
||||
|
||||
#### Advanced Message with Extras
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "{{.Title}}",
|
||||
"message": "{{.Message}}",
|
||||
"priority": {{.Priority}},
|
||||
"extras": {
|
||||
"client::display": {
|
||||
"contentType": "text/markdown"
|
||||
},
|
||||
"client::notification": {
|
||||
"click": {
|
||||
"url": "https://your-charon-instance.com"
|
||||
}
|
||||
},
|
||||
"charon": {
|
||||
"event_type": "{{.EventType}}",
|
||||
"host_name": "{{.HostName}}",
|
||||
"timestamp": "{{.Timestamp}}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Gotify Priority Levels:**
|
||||
|
||||
- `0` - Very low
|
||||
- `2` - Low
|
||||
- `5` - Normal (default)
|
||||
- `8` - High
|
||||
- `10` - Very high (emergency)
|
||||
|
||||
### Generic Webhooks
|
||||
|
||||
For custom integrations, use any JSON structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"notification": {
|
||||
"type": "{{.EventType}}",
|
||||
"level": "{{.Severity}}",
|
||||
"title": "{{.Title}}",
|
||||
"body": "{{.Message}}",
|
||||
"metadata": {
|
||||
"host": "{{.HostName}}",
|
||||
"timestamp": "{{.Timestamp}}",
|
||||
"source": "charon"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Template Variables
|
||||
|
||||
All services support these variables in JSON templates:
|
||||
|
||||
| Variable | Description | Example |
|
||||
|----------|-------------|---------|
|
||||
| `{{.Title}}` | Event title | "SSL Certificate Renewed" |
|
||||
| `{{.Message}}` | Event message/details | "Certificate for example.com renewed" |
|
||||
| `{{.EventType}}` | Type of event | "ssl_renewal", "uptime_down" |
|
||||
| `{{.Severity}}` | Event severity level | "info", "warning", "error" |
|
||||
| `{{.HostName}}` | Affected proxy host | "example.com" |
|
||||
| `{{.Timestamp}}` | ISO 8601 timestamp | "2025-12-24T10:30:00Z" |
|
||||
| `{{.Color}}` | Color code (integer) | 2326507 (blue) |
|
||||
| `{{.Priority}}` | Numeric priority (1-10) | 5 |
|
||||
|
||||
### Event-Specific Variables
|
||||
|
||||
Some events include additional variables:
|
||||
|
||||
**SSL Certificate Events:**
|
||||
|
||||
- `{{.Domain}}` - Certificate domain
|
||||
- `{{.ExpiryDate}}` - Expiration date
|
||||
- `{{.DaysRemaining}}` - Days until expiry
|
||||
|
||||
**Uptime Events:**
|
||||
|
||||
- `{{.StatusChange}}` - "up_to_down" or "down_to_up"
|
||||
- `{{.ResponseTime}}` - Last response time in ms
|
||||
- `{{.Downtime}}` - Duration of downtime
|
||||
|
||||
**Security Events:**
|
||||
|
||||
- `{{.AttackerIP}}` - Source IP address
|
||||
- `{{.RuleID}}` - Triggered rule identifier
|
||||
- `{{.Action}}` - Action taken (block/log)
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Upgrading from Basic Webhooks
|
||||
|
||||
If you've been using webhook providers without JSON templates:
|
||||
|
||||
**Before (Basic webhook):**
|
||||
|
||||
```
|
||||
Type: webhook
|
||||
URL: https://discord.com/api/webhooks/...
|
||||
Template: (not available)
|
||||
```
|
||||
|
||||
**After (JSON template):**
|
||||
|
||||
```
|
||||
Type: discord
|
||||
URL: https://discord.com/api/webhooks/...
|
||||
Template: detailed (or custom)
|
||||
```
|
||||
|
||||
**Steps:**
|
||||
|
||||
1. Edit your existing provider
|
||||
2. Change type from `webhook` to the specific service (e.g., `discord`)
|
||||
3. Select a template (minimal, detailed, or custom)
|
||||
4. Test the notification
|
||||
5. Save changes
|
||||
|
||||
### Testing Your Template
|
||||
|
||||
Before saving, always test your template:
|
||||
|
||||
1. Click **"Send Test Notification"** in the provider form
|
||||
2. Check your notification channel (Discord/Slack/etc.)
|
||||
3. Verify formatting, colors, and all fields appear correctly
|
||||
4. Adjust template if needed
|
||||
5. Test again until satisfied
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Template Validation Errors
|
||||
|
||||
**Error:** `Invalid JSON template`
|
||||
|
||||
**Solution:** Validate your JSON using a tool like [jsonlint.com](https://jsonlint.com). Common issues:
|
||||
|
||||
- Missing closing braces `}`
|
||||
- Trailing commas
|
||||
- Unescaped quotes in strings
|
||||
|
||||
**Error:** `Template variable not found: {{.CustomVar}}`
|
||||
|
||||
**Solution:** Only use supported template variables listed above.
|
||||
|
||||
### Notification Not Received
|
||||
|
||||
**Checklist:**
|
||||
|
||||
1. ✅ Provider is enabled
|
||||
2. ✅ Event type is configured for notifications
|
||||
3. ✅ Webhook URL is correct
|
||||
4. ✅ Service (Discord/Slack/etc.) is online
|
||||
5. ✅ Test notification succeeds
|
||||
6. ✅ Check Charon logs for errors: `docker logs charon | grep notification`
|
||||
|
||||
### Discord Embed Not Showing
|
||||
|
||||
**Cause:** Embeds require specific structure.
|
||||
|
||||
**Solution:** Ensure your template includes the `embeds` array:
|
||||
|
||||
```json
|
||||
{
|
||||
"embeds": [
|
||||
{
|
||||
"title": "{{.Title}}",
|
||||
"description": "{{.Message}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Slack Message Appears Plain
|
||||
|
||||
**Cause:** Block Kit requires specific formatting.
|
||||
|
||||
**Solution:** Use `blocks` array with proper types:
|
||||
|
||||
```json
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "{{.Message}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Start Simple
|
||||
|
||||
Begin with the **minimal** template and only customize if you need more information.
|
||||
|
||||
### 2. Test Thoroughly
|
||||
|
||||
Always test notifications before relying on them for critical alerts.
|
||||
|
||||
### 3. Use Color Coding
|
||||
|
||||
Consistent colors help quickly identify severity:
|
||||
|
||||
- 🔴 Red: Errors, outages
|
||||
- 🟡 Yellow: Warnings
|
||||
- 🟢 Green: Success, recovery
|
||||
- 🔵 Blue: Informational
|
||||
|
||||
### 4. Group Related Events
|
||||
|
||||
Configure multiple providers for different event types:
|
||||
|
||||
- Critical alerts → Discord (with mentions)
|
||||
- Info notifications → Slack (general channel)
|
||||
- All events → Gotify (personal alerts)
|
||||
|
||||
### 5. Rate Limit Awareness
|
||||
|
||||
Be mindful of service limits:
|
||||
|
||||
- **Discord**: 5 requests per 2 seconds per webhook
|
||||
- **Slack**: 1 request per second per workspace
|
||||
- **Gotify**: No strict limits (self-hosted)
|
||||
|
||||
### 6. Keep Templates Maintainable
|
||||
|
||||
- Document custom templates
|
||||
- Version control your templates
|
||||
- Test after service updates
|
||||
|
||||
## Advanced Use Cases
|
||||
|
||||
### Multi-Channel Routing
|
||||
|
||||
Create separate providers for different severity levels:
|
||||
|
||||
```
|
||||
Provider: Discord Critical
|
||||
Events: uptime_down, ssl_failure
|
||||
Template: Custom with @everyone mention
|
||||
|
||||
Provider: Slack Info
|
||||
Events: ssl_renewal, backup_success
|
||||
Template: Minimal
|
||||
|
||||
Provider: Gotify All
|
||||
Events: * (all)
|
||||
Template: Detailed
|
||||
```
|
||||
|
||||
### Conditional Formatting
|
||||
|
||||
Use template logic (if supported by your service):
|
||||
|
||||
```json
|
||||
{
|
||||
"embeds": [{
|
||||
"title": "{{.Title}}",
|
||||
"description": "{{.Message}}",
|
||||
"color": {{if eq .Severity "error"}}15158332{{else}}2326507{{end}}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
### Integration with Automation
|
||||
|
||||
Forward notifications to automation tools:
|
||||
|
||||
```json
|
||||
{
|
||||
"webhook_type": "charon_notification",
|
||||
"trigger_workflow": true,
|
||||
"data": {
|
||||
"event": "{{.EventType}}",
|
||||
"host": "{{.HostName}}",
|
||||
"action_required": {{if eq .Severity "error"}}true{{else}}false{{end}}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Discord Webhook Documentation](https://discord.com/developers/docs/resources/webhook)
|
||||
- [Slack Block Kit Builder](https://api.slack.com/block-kit)
|
||||
- [Gotify API Documentation](https://gotify.net/docs/)
|
||||
- [Charon Security Guide](../security.md)
|
||||
|
||||
## Need Help?
|
||||
|
||||
- 💬 [Ask in Discussions](https://github.com/Wikid82/charon/discussions)
|
||||
- 🐛 [Report Issues](https://github.com/Wikid82/charon/issues)
|
||||
- 📖 [View Full Documentation](https://wikid82.github.io/charon/)
|
||||
@@ -1,348 +0,0 @@
|
||||
# Plugin Security Guide
|
||||
|
||||
This guide covers security configuration and deployment patterns for Charon's plugin system. For general plugin installation and usage, see [Custom Plugins](./custom-plugins.md).
|
||||
|
||||
## Overview
|
||||
|
||||
Charon supports external DNS provider plugins via Go's plugin system. Because plugins execute **in-process** with full memory access, they must be treated as trusted code. This guide explains how to:
|
||||
|
||||
- Configure signature-based allowlisting
|
||||
- Deploy plugins securely in containers
|
||||
- Mitigate common attack vectors
|
||||
|
||||
---
|
||||
|
||||
## Plugin Signature Allowlisting
|
||||
|
||||
Charon supports SHA-256 signature verification to ensure only approved plugins are loaded.
|
||||
|
||||
### Environment Variable
|
||||
|
||||
```bash
|
||||
CHARON_PLUGIN_SIGNATURES='{"pluginname": "sha256:..."}'
|
||||
```
|
||||
|
||||
**Key format**: Plugin name **without** the `.so` extension.
|
||||
|
||||
### Behavior Matrix
|
||||
|
||||
| `CHARON_PLUGIN_SIGNATURES` Value | Behavior |
|
||||
|----------------------------------|----------|
|
||||
| Unset or empty (`""`) | **Permissive mode** — All plugins are loaded (backward compatible) |
|
||||
| Set to `{}` | **Strict block-all** — No external plugins are loaded |
|
||||
| Set with entries | **Allowlist mode** — Only listed plugins with matching signatures are loaded |
|
||||
|
||||
### Examples
|
||||
|
||||
**Permissive mode (default)**:
|
||||
```bash
|
||||
# Unset — all plugins load without verification
|
||||
unset CHARON_PLUGIN_SIGNATURES
|
||||
```
|
||||
|
||||
**Strict block-all**:
|
||||
```bash
|
||||
# Empty object — no external plugins will load
|
||||
export CHARON_PLUGIN_SIGNATURES='{}'
|
||||
```
|
||||
|
||||
**Allowlist specific plugins**:
|
||||
```bash
|
||||
# Only powerdns and custom-provider plugins are allowed
|
||||
export CHARON_PLUGIN_SIGNATURES='{"powerdns": "sha256:a1b2c3d4...", "custom-provider": "sha256:e5f6g7h8..."}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Generating Plugin Signatures
|
||||
|
||||
To add a plugin to your allowlist, compute its SHA-256 signature:
|
||||
|
||||
```bash
|
||||
sha256sum myplugin.so | awk '{print "sha256:" $1}'
|
||||
```
|
||||
|
||||
**Example output**:
|
||||
```
|
||||
sha256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2
|
||||
```
|
||||
|
||||
Use this value in your `CHARON_PLUGIN_SIGNATURES` JSON:
|
||||
|
||||
```bash
|
||||
export CHARON_PLUGIN_SIGNATURES='{"myplugin": "sha256:a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2"}'
|
||||
```
|
||||
|
||||
> **⚠️ Important**: The key is the plugin name **without** `.so`. Use `myplugin`, not `myplugin.so`.
|
||||
|
||||
---
|
||||
|
||||
## Container Deployment Recommendations
|
||||
|
||||
### Read-Only Plugin Mount (Critical)
|
||||
|
||||
**Always mount the plugin directory as read-only in production**:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
charon:
|
||||
image: charon:latest
|
||||
volumes:
|
||||
- ./plugins:/app/plugins:ro # Read-only mount
|
||||
environment:
|
||||
- CHARON_PLUGINS_DIR=/app/plugins
|
||||
- CHARON_PLUGIN_SIGNATURES={"powerdns": "sha256:..."}
|
||||
```
|
||||
|
||||
This prevents runtime modification of plugin files, mitigating:
|
||||
- Time-of-check to time-of-use (TOCTOU) attacks
|
||||
- Malicious plugin replacement after signature verification
|
||||
|
||||
### Non-Root Execution
|
||||
|
||||
Run Charon as a non-root user:
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
services:
|
||||
charon:
|
||||
image: charon:latest
|
||||
user: "1000:1000" # Non-root user
|
||||
# ...
|
||||
```
|
||||
|
||||
Or in Dockerfile:
|
||||
```dockerfile
|
||||
FROM charon:latest
|
||||
USER charon
|
||||
```
|
||||
|
||||
### Directory Permissions
|
||||
|
||||
Plugin directories must **not** be world-writable. Charon enforces this at startup.
|
||||
|
||||
| Permission | Result |
|
||||
|------------|--------|
|
||||
| `0755` or stricter | ✅ Allowed |
|
||||
| `0777` (world-writable) | ❌ Rejected — plugin loading disabled |
|
||||
|
||||
**Set secure permissions**:
|
||||
```bash
|
||||
chmod 755 /path/to/plugins
|
||||
chmod 644 /path/to/plugins/*.so # Or 755 for executable
|
||||
```
|
||||
|
||||
### Complete Secure Deployment Example
|
||||
|
||||
```yaml
|
||||
# docker-compose.production.yml
|
||||
services:
|
||||
charon:
|
||||
image: charon:latest
|
||||
user: "1000:1000"
|
||||
read_only: true
|
||||
security_opt:
|
||||
- no-new-privileges:true
|
||||
volumes:
|
||||
- ./plugins:/app/plugins:ro
|
||||
- ./data:/app/data
|
||||
environment:
|
||||
- CHARON_PLUGINS_DIR=/app/plugins
|
||||
- CHARON_PLUGIN_SIGNATURES={"powerdns": "sha256:abc123..."}
|
||||
tmpfs:
|
||||
- /tmp
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## TOCTOU Mitigation
|
||||
|
||||
Time-of-check to time-of-use (TOCTOU) vulnerabilities occur when a file is modified between signature verification and loading. Mitigate with:
|
||||
|
||||
### 1. Read-Only Mounts (Primary Defense)
|
||||
|
||||
Mount the plugin directory as read-only (`:ro`). This prevents modification after startup.
|
||||
|
||||
### 2. Atomic File Replacement for Updates
|
||||
|
||||
When updating plugins, use atomic operations to avoid partial writes:
|
||||
|
||||
```bash
|
||||
# 1. Copy new plugin to temporary location
|
||||
cp new_plugin.so /tmp/plugin.so.new
|
||||
|
||||
# 2. Atomically replace the old plugin
|
||||
mv /tmp/plugin.so.new /app/plugins/plugin.so
|
||||
|
||||
# 3. Restart Charon to reload plugins
|
||||
docker compose restart charon
|
||||
```
|
||||
|
||||
> **⚠️ Warning**: `cp` followed by direct write to the plugin directory is **not atomic** and creates a window for exploitation.
|
||||
|
||||
### 3. Signature Re-Verification on Reload
|
||||
|
||||
After updating plugins, always update your `CHARON_PLUGIN_SIGNATURES` with the new hash before restarting.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Checking if a Plugin Loaded
|
||||
|
||||
**Check startup logs**:
|
||||
```bash
|
||||
docker compose logs charon | grep -i plugin
|
||||
```
|
||||
|
||||
**Expected success output**:
|
||||
```
|
||||
INFO Loaded DNS provider plugin type=powerdns name="PowerDNS" version="1.0.0"
|
||||
INFO Loaded 1 external DNS provider plugins (0 failed)
|
||||
```
|
||||
|
||||
**If using allowlist**:
|
||||
```
|
||||
INFO Plugin signature allowlist enabled with 2 entries
|
||||
```
|
||||
|
||||
**Via API**:
|
||||
```bash
|
||||
curl http://localhost:8080/api/admin/plugins \
|
||||
-H "Authorization: Bearer YOUR-TOKEN"
|
||||
```
|
||||
|
||||
### Common Error Messages
|
||||
|
||||
#### `plugin not in allowlist`
|
||||
|
||||
**Cause**: The plugin filename (without `.so`) is not in `CHARON_PLUGIN_SIGNATURES`.
|
||||
|
||||
**Solution**: Add the plugin to your allowlist:
|
||||
```bash
|
||||
# Get the signature
|
||||
sha256sum powerdns.so | awk '{print "sha256:" $1}'
|
||||
|
||||
# Add to environment
|
||||
export CHARON_PLUGIN_SIGNATURES='{"powerdns": "sha256:YOUR_HASH_HERE"}'
|
||||
```
|
||||
|
||||
#### `signature mismatch for plugin`
|
||||
|
||||
**Cause**: The plugin file's SHA-256 hash doesn't match the allowlist.
|
||||
|
||||
**Solution**:
|
||||
1. Verify you have the correct plugin file
|
||||
2. Re-compute the signature: `sha256sum plugin.so`
|
||||
3. Update `CHARON_PLUGIN_SIGNATURES` with the correct hash
|
||||
|
||||
#### `plugin directory has insecure permissions`
|
||||
|
||||
**Cause**: The plugin directory is world-writable (mode `0777` or similar).
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
chmod 755 /path/to/plugins
|
||||
chmod 644 /path/to/plugins/*.so
|
||||
```
|
||||
|
||||
#### `invalid CHARON_PLUGIN_SIGNATURES JSON`
|
||||
|
||||
**Cause**: Malformed JSON in the environment variable.
|
||||
|
||||
**Solution**: Validate your JSON:
|
||||
```bash
|
||||
echo '{"powerdns": "sha256:abc123"}' | jq .
|
||||
```
|
||||
|
||||
Common issues:
|
||||
- Missing quotes around keys or values
|
||||
- Trailing commas
|
||||
- Single quotes instead of double quotes
|
||||
|
||||
#### Permission denied when loading plugin
|
||||
|
||||
**Cause**: File permissions too restrictive or ownership mismatch.
|
||||
|
||||
**Solution**:
|
||||
```bash
|
||||
# Check current permissions
|
||||
ls -la /path/to/plugins/
|
||||
|
||||
# Fix permissions
|
||||
chmod 644 /path/to/plugins/*.so
|
||||
chown charon:charon /path/to/plugins/*.so
|
||||
```
|
||||
|
||||
### Debugging Checklist
|
||||
|
||||
1. **Is the plugin directory configured?**
|
||||
```bash
|
||||
echo $CHARON_PLUGINS_DIR
|
||||
```
|
||||
|
||||
2. **Does the plugin file exist?**
|
||||
```bash
|
||||
ls -la $CHARON_PLUGINS_DIR/*.so
|
||||
```
|
||||
|
||||
3. **Are directory permissions secure?**
|
||||
```bash
|
||||
stat -c "%a %n" $CHARON_PLUGINS_DIR
|
||||
# Should be 755 or stricter
|
||||
```
|
||||
|
||||
4. **Is the signature correct?**
|
||||
```bash
|
||||
sha256sum $CHARON_PLUGINS_DIR/myplugin.so
|
||||
```
|
||||
|
||||
5. **Is the JSON valid?**
|
||||
```bash
|
||||
echo "$CHARON_PLUGIN_SIGNATURES" | jq .
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security Implications
|
||||
|
||||
### What Plugins Can Access
|
||||
|
||||
Plugins run **in-process** with Charon and have access to:
|
||||
|
||||
| Resource | Access Level |
|
||||
|----------|--------------|
|
||||
| System memory | Full read/write |
|
||||
| Database credentials | Full access |
|
||||
| API tokens and secrets | Full access |
|
||||
| File system | Charon's permissions |
|
||||
| Network | Unrestricted outbound |
|
||||
|
||||
### Risk Assessment
|
||||
|
||||
| Risk | Mitigation |
|
||||
|------|------------|
|
||||
| Malicious plugin code | Signature allowlisting, code review |
|
||||
| Plugin replacement attack | Read-only mounts, atomic updates |
|
||||
| World-writable directory | Automatic permission verification |
|
||||
| Supply chain compromise | Verify plugin source, pin signatures |
|
||||
|
||||
### Best Practices Summary
|
||||
|
||||
1. ✅ **Enable signature allowlisting** in production
|
||||
2. ✅ **Mount plugin directory read-only** (`:ro`)
|
||||
3. ✅ **Run as non-root user**
|
||||
4. ✅ **Use strict directory permissions** (`0755` or stricter)
|
||||
5. ✅ **Verify plugin source** before deployment
|
||||
6. ✅ **Update signatures** after plugin updates
|
||||
7. ❌ **Never use permissive mode** in production
|
||||
8. ❌ **Never install plugins from untrusted sources**
|
||||
|
||||
---
|
||||
|
||||
## See Also
|
||||
|
||||
- [Custom Plugins](./custom-plugins.md) — Plugin installation and usage
|
||||
- [Security Policy](../../SECURITY.md) — Security reporting and policies
|
||||
- [Plugin Development Guide](../development/plugin-development.md) — Building custom plugins
|
||||
@@ -1,135 +0,0 @@
|
||||
---
|
||||
title: Smart Proxy Headers
|
||||
description: Automatic X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto headers
|
||||
category: networking
|
||||
---
|
||||
|
||||
# Smart Proxy Headers
|
||||
|
||||
Your backend applications need to know the real client IP address, not Charon's. Standard headers like X-Real-IP, X-Forwarded-For, and X-Forwarded-Proto are added automatically.
|
||||
|
||||
## Overview
|
||||
|
||||
When traffic passes through a reverse proxy, your backend loses visibility into the original client connection. Without proxy headers, every request appears to come from Charon's IP address, breaking logging, rate limiting, geolocation, and security features.
|
||||
|
||||
### Standard Proxy Headers
|
||||
|
||||
| Header | Purpose | Example Value |
|
||||
|--------|---------|---------------|
|
||||
| **X-Real-IP** | Original client IP address | `203.0.113.42` |
|
||||
| **X-Forwarded-For** | Chain of proxy IPs | `203.0.113.42, 10.0.0.1` |
|
||||
| **X-Forwarded-Proto** | Original protocol (HTTP/HTTPS) | `https` |
|
||||
| **X-Forwarded-Host** | Original host header | `example.com` |
|
||||
| **X-Forwarded-Port** | Original port number | `443` |
|
||||
|
||||
## Why These Headers Matter
|
||||
|
||||
### Client IP Detection
|
||||
|
||||
Without X-Real-IP, your application sees Charon's internal IP for every request:
|
||||
|
||||
- **Logging**: All logs show the same IP, making debugging impossible
|
||||
- **Rate Limiting**: Cannot throttle abusive clients
|
||||
- **Geolocation**: Location services return proxy location, not user location
|
||||
- **Analytics**: Traffic analytics become meaningless
|
||||
|
||||
### HTTPS Enforcement
|
||||
|
||||
X-Forwarded-Proto tells your backend the original protocol:
|
||||
|
||||
- **Redirect Loops**: Backend sees HTTP, redirects to HTTPS, Charon proxies as HTTP, infinite loop
|
||||
- **Secure Cookies**: Applications need to know when to set `Secure` flag
|
||||
- **Mixed Content**: Helps applications generate correct absolute URLs
|
||||
|
||||
### Virtual Host Routing
|
||||
|
||||
X-Forwarded-Host preserves the original domain:
|
||||
|
||||
- **Multi-tenant Apps**: Route requests to correct tenant
|
||||
- **URL Generation**: Generate correct links in emails, redirects
|
||||
|
||||
## Configuration
|
||||
|
||||
### Default Behavior
|
||||
|
||||
| Host Type | Proxy Headers |
|
||||
|-----------|---------------|
|
||||
| New hosts | **Enabled** by default |
|
||||
| Existing hosts (pre-upgrade) | **Disabled** (preserves existing behavior) |
|
||||
|
||||
### Enabling/Disabling
|
||||
|
||||
1. Navigate to **Hosts** → Select your host
|
||||
2. Go to **Advanced** tab
|
||||
3. Toggle **Proxy Headers** on or off
|
||||
4. Click **Save**
|
||||
|
||||
### Backend Configuration Requirements
|
||||
|
||||
Your backend must trust proxy headers from Charon. Common configurations:
|
||||
|
||||
**Node.js/Express:**
|
||||
```javascript
|
||||
app.set('trust proxy', true);
|
||||
```
|
||||
|
||||
**Django:**
|
||||
```python
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
USE_X_FORWARDED_HOST = True
|
||||
```
|
||||
|
||||
**Rails:**
|
||||
```ruby
|
||||
config.action_dispatch.trusted_proxies = [IPAddr.new('10.0.0.0/8')]
|
||||
```
|
||||
|
||||
**PHP/Laravel:**
|
||||
```php
|
||||
// In TrustProxies middleware
|
||||
protected $proxies = '*';
|
||||
```
|
||||
|
||||
## When to Enable vs Disable
|
||||
|
||||
### Enable When
|
||||
|
||||
- Backend needs real client IP for logging or security
|
||||
- Application generates absolute URLs
|
||||
- Using secure cookies with HTTPS termination at proxy
|
||||
- Rate limiting or geolocation features are needed
|
||||
|
||||
### Disable When
|
||||
|
||||
- Backend is an external service you don't control
|
||||
- Proxying to another reverse proxy that handles headers
|
||||
- Legacy application that misinterprets forwarded headers
|
||||
- Security policy requires hiding internal topology
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Trusted Proxies
|
||||
|
||||
Only trust proxy headers from known sources. If your backend blindly trusts X-Forwarded-For, attackers can spoof their IP by injecting fake headers.
|
||||
|
||||
### Header Injection Prevention
|
||||
|
||||
Charon sanitizes incoming proxy headers before adding its own, preventing header injection attacks where malicious clients send fake forwarded headers.
|
||||
|
||||
### IP Chain Verification
|
||||
|
||||
When multiple proxies exist, verify the entire X-Forwarded-For chain rather than trusting only the first or last IP.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Likely Cause | Solution |
|
||||
|-------|--------------|----------|
|
||||
| Backend shows wrong IP | Headers not enabled | Enable proxy headers for host |
|
||||
| Redirect loop | Backend doesn't trust X-Forwarded-Proto | Configure backend trust settings |
|
||||
| Wrong URLs in emails | Missing X-Forwarded-Host trust | Enable host header forwarding |
|
||||
|
||||
## Related
|
||||
|
||||
- [Security Headers](security-headers.md) - Browser security headers
|
||||
- [SSL Certificates](ssl-certificates.md) - HTTPS configuration
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,113 +0,0 @@
|
||||
---
|
||||
title: Rate Limiting
|
||||
description: Prevent abuse by limiting requests per user or IP address
|
||||
---
|
||||
|
||||
# Rate Limiting
|
||||
|
||||
Prevent abuse by limiting how many requests a user or IP address can make. Stop brute-force attacks, API abuse, and resource exhaustion with simple, configurable limits.
|
||||
|
||||
## Overview
|
||||
|
||||
Rate limiting controls how frequently clients can make requests to your proxied services. When a client exceeds the configured limit, additional requests receive a `429 Too Many Requests` response until the limit resets.
|
||||
|
||||
Key concepts:
|
||||
|
||||
- **Requests per Second (RPS)** — Sustained request rate allowed
|
||||
- **Burst Limit** — Short-term spike allowance above RPS
|
||||
- **Time Window** — Period over which limits are calculated
|
||||
- **Per-IP Tracking** — Each client IP has independent limits
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Brute-Force Prevention** — Stop password guessing attacks
|
||||
- **API Protection** — Prevent excessive API consumption
|
||||
- **Resource Management** — Protect backend services from overload
|
||||
- **Fair Usage** — Ensure equitable access across all users
|
||||
- **Cost Control** — Limit expensive operations
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enabling Rate Limiting
|
||||
|
||||
1. Navigate to **Proxy Hosts**
|
||||
2. Edit or create a proxy host
|
||||
3. Go to the **Advanced** tab
|
||||
4. Toggle **Rate Limiting** to enabled
|
||||
5. Configure your limits
|
||||
|
||||
### Parameters
|
||||
|
||||
| Parameter | Description | Example |
|
||||
|-----------|-------------|---------|
|
||||
| **Requests/Second** | Sustained rate limit | `10` = 10 requests per second |
|
||||
| **Burst Limit** | Temporary spike allowance | `50` = allow 50 rapid requests |
|
||||
| **Time Window** | Reset period in seconds | `60` = limits reset every minute |
|
||||
|
||||
### Understanding Burst vs Sustained Rate
|
||||
|
||||
```text
|
||||
Sustained Rate: 10 req/sec
|
||||
Burst Limit: 50
|
||||
|
||||
Behavior:
|
||||
- Client can send 50 requests instantly (burst)
|
||||
- Then limited to 10 req/sec until burst refills
|
||||
- Burst tokens refill at the sustained rate
|
||||
```
|
||||
|
||||
This allows legitimate traffic spikes (page loads with many assets) while preventing sustained abuse.
|
||||
|
||||
### Recommended Configurations
|
||||
|
||||
| Use Case | RPS | Burst | Window |
|
||||
|----------|-----|-------|--------|
|
||||
| Public website | 20 | 100 | 60s |
|
||||
| Login endpoint | 5 | 10 | 60s |
|
||||
| API endpoint | 30 | 60 | 60s |
|
||||
| Static assets | 100 | 500 | 60s |
|
||||
|
||||
## Dashboard Integration
|
||||
|
||||
### Status Badge
|
||||
|
||||
When rate limiting is enabled, the proxy host displays a **Rate Limited** badge on:
|
||||
|
||||
- Proxy host list view
|
||||
- Host detail page
|
||||
|
||||
### Active Summary Card
|
||||
|
||||
The dashboard shows an **Active Rate Limiting** summary card displaying:
|
||||
|
||||
- Number of hosts with rate limiting enabled
|
||||
- Current configuration summary
|
||||
- Link to manage settings
|
||||
|
||||
## Response Headers
|
||||
|
||||
Rate-limited responses include helpful headers:
|
||||
|
||||
```http
|
||||
HTTP/1.1 429 Too Many Requests
|
||||
Retry-After: 5
|
||||
X-RateLimit-Limit: 10
|
||||
X-RateLimit-Remaining: 0
|
||||
X-RateLimit-Reset: 1642000000
|
||||
```
|
||||
|
||||
Clients can use these headers to implement backoff strategies.
|
||||
|
||||
## Best Practices
|
||||
|
||||
- **Start Generous** — Begin with higher limits and tighten based on observed traffic
|
||||
- **Monitor Logs** — Watch for legitimate users hitting limits
|
||||
- **Separate Endpoints** — Use different limits for different proxy hosts
|
||||
- **Combine with WAF** — Rate limiting + WAF provides layered protection
|
||||
|
||||
## Related
|
||||
|
||||
- [Access Control](./access-control.md) — IP-based access restrictions
|
||||
- [CrowdSec Integration](./crowdsec.md) — Automatic attacker blocking
|
||||
- [Proxy Hosts](./proxy-hosts.md) — Configure rate limits per host
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,119 +0,0 @@
|
||||
---
|
||||
title: HTTP Security Headers
|
||||
description: Automatic security headers including CSP, HSTS, and more
|
||||
category: security
|
||||
---
|
||||
|
||||
# HTTP Security Headers
|
||||
|
||||
Modern browsers expect specific security headers to protect your users. Charon automatically adds industry-standard headers including Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, and X-Content-Type-Options.
|
||||
|
||||
## Overview
|
||||
|
||||
HTTP security headers instruct browsers how to handle your content securely. Without them, your site remains vulnerable to clickjacking, XSS attacks, protocol downgrades, and MIME-type confusion. Charon provides a visual interface for configuring these headers without memorizing complex syntax.
|
||||
|
||||
### Supported Headers
|
||||
|
||||
| Header | Purpose |
|
||||
|--------|---------|
|
||||
| **HSTS** | Forces HTTPS connections, prevents downgrade attacks |
|
||||
| **Content-Security-Policy** | Controls resource loading, mitigates XSS |
|
||||
| **X-Frame-Options** | Prevents clickjacking via iframe embedding |
|
||||
| **X-Content-Type-Options** | Stops MIME-type sniffing attacks |
|
||||
| **Referrer-Policy** | Controls referrer information leakage |
|
||||
| **Permissions-Policy** | Restricts browser feature access (camera, mic, geolocation) |
|
||||
| **Cross-Origin-Opener-Policy** | Isolates browsing context |
|
||||
| **Cross-Origin-Resource-Policy** | Controls cross-origin resource sharing |
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Browser Protection**: Modern browsers actively check for security headers
|
||||
- **Compliance**: Many security audits and standards require specific headers
|
||||
- **Defense in Depth**: Headers add protection even if application code has vulnerabilities
|
||||
- **No Code Changes**: Protect legacy applications without modifying source code
|
||||
|
||||
## Security Presets
|
||||
|
||||
Charon offers three ready-to-use presets based on your security requirements:
|
||||
|
||||
### Basic (Production Safe)
|
||||
|
||||
Balanced security suitable for most production sites. Enables essential protections without breaking typical web functionality.
|
||||
|
||||
- HSTS enabled (1 year, includeSubdomains)
|
||||
- X-Frame-Options: SAMEORIGIN
|
||||
- X-Content-Type-Options: nosniff
|
||||
- Referrer-Policy: strict-origin-when-cross-origin
|
||||
|
||||
### Strict (High Security)
|
||||
|
||||
Enhanced security for applications handling sensitive data. May require CSP tuning for inline scripts.
|
||||
|
||||
- All Basic headers plus:
|
||||
- Content-Security-Policy with restrictive defaults
|
||||
- Permissions-Policy denying sensitive features
|
||||
- X-Frame-Options: DENY
|
||||
|
||||
### Paranoid (Maximum)
|
||||
|
||||
Maximum security for high-value targets. Expect to customize CSP directives for your specific application.
|
||||
|
||||
- All Strict headers plus:
|
||||
- CSP with nonce-based script execution
|
||||
- Cross-Origin policies fully restricted
|
||||
- All permissions denied by default
|
||||
|
||||
## Configuration
|
||||
|
||||
### Using Presets
|
||||
|
||||
1. Navigate to **Hosts** → Select your host → **Security Headers**
|
||||
2. Choose a preset from the dropdown
|
||||
3. Review the applied headers in the preview
|
||||
4. Click **Save** to apply
|
||||
|
||||
### Custom Header Profiles
|
||||
|
||||
Create reusable header configurations:
|
||||
|
||||
1. Go to **Settings** → **Security Profiles**
|
||||
2. Click **Create Profile**
|
||||
3. Name your profile (e.g., "API Servers", "Public Sites")
|
||||
4. Configure individual headers
|
||||
5. Save and apply to multiple hosts
|
||||
|
||||
### Interactive CSP Builder
|
||||
|
||||
The CSP Builder provides a visual interface for constructing Content-Security-Policy:
|
||||
|
||||
1. Select directive (script-src, style-src, img-src, etc.)
|
||||
2. Add allowed sources (self, specific domains, unsafe-inline)
|
||||
3. Preview the generated policy
|
||||
4. Test against your site before applying
|
||||
|
||||
## Security Score Calculator
|
||||
|
||||
Each host displays a security score from 0-100 based on enabled headers:
|
||||
|
||||
| Score Range | Rating | Description |
|
||||
|-------------|--------|-------------|
|
||||
| 90-100 | Excellent | All recommended headers configured |
|
||||
| 70-89 | Good | Core protections in place |
|
||||
| 50-69 | Fair | Basic headers only |
|
||||
| 0-49 | Poor | Missing critical headers |
|
||||
|
||||
## When to Use Each Preset
|
||||
|
||||
| Scenario | Recommended Preset |
|
||||
|----------|-------------------|
|
||||
| Marketing sites, blogs | Basic |
|
||||
| E-commerce, user accounts | Strict |
|
||||
| Banking, healthcare, government | Paranoid |
|
||||
| Internal tools | Basic or Strict |
|
||||
| APIs (no browser UI) | Minimal or disabled |
|
||||
|
||||
## Related
|
||||
|
||||
- [Proxy Headers](proxy-headers.md) - Backend communication headers
|
||||
- [Access Lists](access-lists.md) - IP-based access control
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,77 +0,0 @@
|
||||
---
|
||||
title: Automatic HTTPS Certificates
|
||||
description: Automatic SSL certificate provisioning and renewal via Let's Encrypt or ZeroSSL
|
||||
---
|
||||
|
||||
# Automatic HTTPS Certificates
|
||||
|
||||
Charon automatically obtains free SSL certificates from Let's Encrypt or ZeroSSL, installs them, and renews them before they expire—all without you lifting a finger.
|
||||
|
||||
## Overview
|
||||
|
||||
When you create a proxy host with HTTPS enabled, Charon handles the entire certificate lifecycle:
|
||||
|
||||
1. **Automatic Provisioning** — Requests a certificate from your chosen provider
|
||||
2. **Domain Validation** — Completes the ACME challenge automatically
|
||||
3. **Installation** — Configures Caddy to use the new certificate
|
||||
4. **Renewal** — Renews certificates before they expire (typically 30 days before)
|
||||
5. **Smart Cleanup** — Removes certificates when you delete hosts
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Zero Configuration** — Works out of the box with sensible defaults
|
||||
- **Free Certificates** — Both Let's Encrypt and ZeroSSL provide certificates at no cost
|
||||
- **Always Valid** — Automatic renewal prevents certificate expiration
|
||||
- **No Downtime** — Certificate updates happen seamlessly
|
||||
|
||||
## SSL Provider Selection
|
||||
|
||||
Navigate to **Settings → Default Settings** to choose your SSL provider:
|
||||
|
||||
| Provider | Best For | Rate Limits |
|
||||
|----------|----------|-------------|
|
||||
| **Auto** | Most users | Caddy selects automatically |
|
||||
| **Let's Encrypt (Production)** | Production sites | 50 certs/domain/week |
|
||||
| **Let's Encrypt (Staging)** | Testing & development | Unlimited (untrusted certs) |
|
||||
| **ZeroSSL** | Alternative to LE, or if rate-limited | 3 certs/domain/90 days (free tier) |
|
||||
|
||||
### When to Use Each Provider
|
||||
|
||||
- **Auto**: Recommended for most users. Caddy intelligently selects the best provider.
|
||||
- **Let's Encrypt Production**: When you need trusted certificates and are within rate limits.
|
||||
- **Let's Encrypt Staging**: When testing your setup—certificates are not trusted by browsers but have no rate limits.
|
||||
- **ZeroSSL**: When you've hit Let's Encrypt rate limits or prefer an alternative CA.
|
||||
|
||||
## Dashboard Certificate Status
|
||||
|
||||
The **Certificate Status Card** on your dashboard shows:
|
||||
|
||||
- Total certificates managed
|
||||
- Certificates expiring soon (within 30 days)
|
||||
- Any failed certificate requests
|
||||
|
||||
Click on any certificate to view details including expiration date, domains covered, and issuer information.
|
||||
|
||||
## Smart Certificate Cleanup
|
||||
|
||||
When you delete a proxy host, Charon automatically:
|
||||
|
||||
1. Removes the certificate from Caddy's configuration
|
||||
2. Cleans up any associated ACME data
|
||||
3. Frees up rate limit quota for new certificates
|
||||
|
||||
This prevents certificate accumulation and keeps your system tidy.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Certificate not issued | Ensure ports 80/443 are accessible from the internet |
|
||||
| Rate limit exceeded | Switch to Let's Encrypt Staging or ZeroSSL temporarily |
|
||||
| Domain validation failed | Verify DNS points to your Charon server |
|
||||
|
||||
## Related
|
||||
|
||||
- [Proxy Hosts](./proxy-hosts.md) — Configure HTTPS for your services
|
||||
- [DNS Providers](./dns-providers.md) — Use DNS challenge for wildcard certificates
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,148 +0,0 @@
|
||||
---
|
||||
title: Verified Builds
|
||||
description: Cryptographic signatures, SLSA provenance, and SBOM for every release
|
||||
---
|
||||
|
||||
# Verified Builds
|
||||
|
||||
Know exactly what you're running. Every Charon release includes cryptographic signatures, SLSA provenance attestation, and a Software Bill of Materials (SBOM). Enterprise-grade supply chain security for everyone.
|
||||
|
||||
## Overview
|
||||
|
||||
Supply chain attacks are increasingly common. Charon protects you with multiple verification layers that prove the image you're running was built from the official source code, hasn't been tampered with, and contains no hidden dependencies.
|
||||
|
||||
### Security Artifacts
|
||||
|
||||
| Artifact | Purpose | Standard |
|
||||
|----------|---------|----------|
|
||||
| **Cosign Signature** | Cryptographic proof of origin | Sigstore |
|
||||
| **SLSA Provenance** | Build process attestation | SLSA Level 3 |
|
||||
| **SBOM** | Complete dependency inventory | SPDX/CycloneDX |
|
||||
|
||||
## Why Supply Chain Security Matters
|
||||
|
||||
| Threat | Mitigation |
|
||||
|--------|------------|
|
||||
| **Compromised CI/CD** | SLSA provenance verifies build source |
|
||||
| **Malicious maintainer** | Signatures require private key access |
|
||||
| **Dependency hijacking** | SBOM enables vulnerability scanning |
|
||||
| **Registry tampering** | Signatures detect unauthorized changes |
|
||||
| **Audit requirements** | Complete traceability for compliance |
|
||||
|
||||
## Verifying Image Signatures
|
||||
|
||||
### Prerequisites
|
||||
|
||||
```bash
|
||||
# Install Cosign
|
||||
# macOS
|
||||
brew install cosign
|
||||
|
||||
# Linux
|
||||
curl -LO https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64
|
||||
chmod +x cosign-linux-amd64 && sudo mv cosign-linux-amd64 /usr/local/bin/cosign
|
||||
```
|
||||
|
||||
### Verify a Charon Image
|
||||
|
||||
```bash
|
||||
# Verify signature (keyless - uses Sigstore public transparency log)
|
||||
cosign verify ghcr.io/wikid82/charon:latest \
|
||||
--certificate-identity-regexp='https://github.com/Wikid82/charon/.*' \
|
||||
--certificate-oidc-issuer='https://token.actions.githubusercontent.com'
|
||||
|
||||
# Successful output shows:
|
||||
# Verification for ghcr.io/wikid82/charon:latest --
|
||||
# The following checks were performed on each of these signatures:
|
||||
# - The cosign claims were validated
|
||||
# - The signatures were verified against the specified public key
|
||||
```
|
||||
|
||||
### Verify SLSA Provenance
|
||||
|
||||
```bash
|
||||
# Install slsa-verifier
|
||||
go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest
|
||||
|
||||
# Verify provenance attestation
|
||||
slsa-verifier verify-image ghcr.io/wikid82/charon:latest \
|
||||
--source-uri github.com/Wikid82/charon \
|
||||
--source-tag v2.0.0
|
||||
```
|
||||
|
||||
## Software Bill of Materials (SBOM)
|
||||
|
||||
### What's Included
|
||||
|
||||
The SBOM lists every component in the image:
|
||||
|
||||
- Go modules and versions
|
||||
- System packages (Alpine)
|
||||
- Frontend npm dependencies
|
||||
- Build tools used
|
||||
|
||||
### Retrieving the SBOM
|
||||
|
||||
```bash
|
||||
# Download SBOM attestation
|
||||
cosign download sbom ghcr.io/wikid82/charon:latest > charon-sbom.spdx.json
|
||||
|
||||
# View in human-readable format
|
||||
cat charon-sbom.spdx.json | jq '.packages[] | {name, version}'
|
||||
```
|
||||
|
||||
### Vulnerability Scanning
|
||||
|
||||
Use the SBOM with vulnerability scanners:
|
||||
|
||||
```bash
|
||||
# Scan with Trivy
|
||||
trivy sbom charon-sbom.spdx.json
|
||||
|
||||
# Scan with Grype
|
||||
grype sbom:charon-sbom.spdx.json
|
||||
```
|
||||
|
||||
## SLSA Provenance Details
|
||||
|
||||
SLSA (Supply-chain Levels for Software Artifacts) provenance includes:
|
||||
|
||||
| Field | Content |
|
||||
|-------|---------|
|
||||
| `buildType` | GitHub Actions workflow |
|
||||
| `invocation` | Commit SHA, branch, workflow run |
|
||||
| `materials` | Source repository, dependencies |
|
||||
| `builder` | GitHub-hosted runner details |
|
||||
|
||||
### Example Provenance
|
||||
|
||||
```json
|
||||
{
|
||||
"buildType": "https://github.com/slsa-framework/slsa-github-generator",
|
||||
"invocation": {
|
||||
"configSource": {
|
||||
"uri": "git+https://github.com/Wikid82/charon@refs/tags/v2.0.0",
|
||||
"entryPoint": ".github/workflows/release.yml"
|
||||
}
|
||||
},
|
||||
"materials": [{
|
||||
"uri": "git+https://github.com/Wikid82/charon",
|
||||
"digest": {"sha1": "abc123..."}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
## Enterprise Compliance
|
||||
|
||||
These artifacts support compliance requirements:
|
||||
|
||||
- **SOC 2**: Demonstrates secure build practices
|
||||
- **FedRAMP**: Provides software supply chain documentation
|
||||
- **PCI DSS**: Enables change management auditing
|
||||
- **NIST SSDF**: Aligns with secure development framework
|
||||
|
||||
## Related
|
||||
|
||||
- [Security Hardening](security-hardening.md) - Runtime security features
|
||||
- [Coraza WAF](coraza-waf.md) - Application firewall
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,117 +0,0 @@
|
||||
---
|
||||
title: Dark Mode & Modern UI
|
||||
description: Toggle between light and dark themes with a clean, modern interface
|
||||
---
|
||||
|
||||
# Dark Mode & Modern UI
|
||||
|
||||
Easy on the eyes, day or night. Toggle between light and dark themes to match your preference. The clean, modern interface makes managing complex setups feel simple.
|
||||
|
||||
## Overview
|
||||
|
||||
Charon's interface is built with **Tailwind CSS v4** and a modern React component library. Dark mode is the default, with automatic system preference detection and manual override support.
|
||||
|
||||
### Design Philosophy
|
||||
|
||||
- **Dark-first**: Optimized for low-light environments and reduced eye strain
|
||||
- **Semantic colors**: Consistent meaning across light and dark modes
|
||||
- **Accessibility-first**: WCAG 2.1 AA compliant with focus management
|
||||
- **Responsive**: Works seamlessly on desktop, tablet, and mobile
|
||||
|
||||
## Why a Modern UI Matters
|
||||
|
||||
| Feature | Benefit |
|
||||
|---------|---------|
|
||||
| **Dark Mode** | Reduced eye strain during long sessions |
|
||||
| **Semantic Tokens** | Consistent, predictable color behavior |
|
||||
| **Component Library** | Professional, polished interactions |
|
||||
| **Keyboard Navigation** | Full functionality without a mouse |
|
||||
| **Screen Reader Support** | Accessible to all users |
|
||||
|
||||
## Theme System
|
||||
|
||||
### Color Tokens
|
||||
|
||||
Charon uses semantic color tokens that automatically adapt:
|
||||
|
||||
| Token | Light Mode | Dark Mode | Usage |
|
||||
|-------|------------|-----------|-------|
|
||||
| `--background` | White | Slate 950 | Page backgrounds |
|
||||
| `--foreground` | Slate 900 | Slate 50 | Primary text |
|
||||
| `--primary` | Blue 600 | Blue 500 | Actions, links |
|
||||
| `--destructive` | Red 600 | Red 500 | Delete, errors |
|
||||
| `--muted` | Slate 100 | Slate 800 | Secondary surfaces |
|
||||
| `--border` | Slate 200 | Slate 700 | Dividers, outlines |
|
||||
|
||||
### Switching Themes
|
||||
|
||||
1. Click the **theme toggle** in the top navigation
|
||||
2. Choose: **Light**, **Dark**, or **System**
|
||||
3. Preference is saved to local storage
|
||||
|
||||
## Component Library
|
||||
|
||||
### Core Components
|
||||
|
||||
| Component | Purpose | Accessibility |
|
||||
|-----------|---------|---------------|
|
||||
| **Badge** | Status indicators, tags | Color + icon redundancy |
|
||||
| **Alert** | Notifications, warnings | ARIA live regions |
|
||||
| **Dialog** | Modal interactions | Focus trap, ESC to close |
|
||||
| **DataTable** | Sortable data display | Keyboard navigation |
|
||||
| **Tooltip** | Contextual help | Delay for screen readers |
|
||||
| **DropdownMenu** | Action menus | Arrow key navigation |
|
||||
|
||||
### Status Indicators
|
||||
|
||||
Visual status uses color AND icons for accessibility:
|
||||
|
||||
- ✅ **Online** - Green badge with check icon
|
||||
- ⚠️ **Warning** - Yellow badge with alert icon
|
||||
- ❌ **Offline** - Red badge with X icon
|
||||
- ⏳ **Pending** - Gray badge with clock icon
|
||||
|
||||
## Accessibility Features
|
||||
|
||||
### WCAG 2.1 Compliance
|
||||
|
||||
- **Color contrast**: Minimum 4.5:1 for text, 3:1 for UI elements
|
||||
- **Focus indicators**: Visible focus rings on all interactive elements
|
||||
- **Text scaling**: UI adapts to browser zoom up to 200%
|
||||
- **Motion**: Respects `prefers-reduced-motion`
|
||||
|
||||
### Keyboard Navigation
|
||||
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| `Tab` | Move between interactive elements |
|
||||
| `Enter` / `Space` | Activate buttons, links |
|
||||
| `Escape` | Close dialogs, dropdowns |
|
||||
| `Arrow keys` | Navigate within menus, tables |
|
||||
|
||||
### Screen Reader Support
|
||||
|
||||
- Semantic HTML structure with landmarks
|
||||
- ARIA labels on icon-only buttons
|
||||
- Live regions for dynamic content updates
|
||||
- Skip links for main content access
|
||||
|
||||
## Customization
|
||||
|
||||
### CSS Variables Override
|
||||
|
||||
Advanced users can customize the theme via CSS:
|
||||
|
||||
```css
|
||||
/* Custom brand colors */
|
||||
:root {
|
||||
--primary: 210 100% 50%; /* Custom blue */
|
||||
--radius: 0.75rem; /* Rounder corners */
|
||||
}
|
||||
```
|
||||
|
||||
## Related
|
||||
|
||||
- [Notifications](notifications.md) - Visual notification system
|
||||
- [REST API](api.md) - Programmatic access
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,528 +0,0 @@
|
||||
# Uptime Monitoring
|
||||
|
||||
Charon's uptime monitoring system continuously checks the availability of your proxy hosts and alerts you when issues occur. The system is designed to minimize false positives while quickly detecting real problems.
|
||||
|
||||
## Overview
|
||||
|
||||
Uptime monitoring performs automated health checks on your proxy hosts at regular intervals, tracking:
|
||||
|
||||
- **Host availability** (TCP connectivity)
|
||||
- **Response times** (latency measurements)
|
||||
- **Status history** (uptime/downtime tracking)
|
||||
- **Failure patterns** (debounced detection)
|
||||
|
||||
## How It Works
|
||||
|
||||
### Check Cycle
|
||||
|
||||
1. **Scheduled Checks**: Every 60 seconds (default), Charon checks all enabled hosts
|
||||
2. **Port Detection**: Uses the proxy host's `ForwardPort` for TCP checks
|
||||
3. **Connection Test**: Attempts TCP connection with configurable timeout
|
||||
4. **Status Update**: Records success/failure in database
|
||||
5. **Notification Trigger**: Sends alerts on status changes (if configured)
|
||||
|
||||
### Failure Debouncing
|
||||
|
||||
To prevent false alarms from transient network issues, Charon uses **failure debouncing**:
|
||||
|
||||
**How it works:**
|
||||
|
||||
- A host must **fail 2 consecutive checks** before being marked "down"
|
||||
- Single failures are logged but don't trigger status changes
|
||||
- Counter resets immediately on any successful check
|
||||
|
||||
**Why this matters:**
|
||||
|
||||
- Network hiccups don't cause false alarms
|
||||
- Container restarts don't trigger unnecessary alerts
|
||||
- Transient DNS issues are ignored
|
||||
- You only get notified about real problems
|
||||
|
||||
**Example scenario:**
|
||||
|
||||
```
|
||||
Check 1: ✅ Success → Status: Up, Failure Count: 0
|
||||
Check 2: ❌ Failed → Status: Up, Failure Count: 1 (no alert)
|
||||
Check 3: ❌ Failed → Status: Down, Failure Count: 2 (alert sent!)
|
||||
Check 4: ✅ Success → Status: Up, Failure Count: 0 (recovery alert)
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Timeout Settings
|
||||
|
||||
**Default TCP timeout:** 10 seconds
|
||||
|
||||
This timeout determines how long Charon waits for a TCP connection before considering it failed.
|
||||
|
||||
**Increase timeout if:**
|
||||
|
||||
- You have slow networks
|
||||
- Hosts are geographically distant
|
||||
- Containers take time to warm up
|
||||
- You see intermittent false "down" alerts
|
||||
|
||||
**Decrease timeout if:**
|
||||
|
||||
- You want faster failure detection
|
||||
- Your hosts are on local network
|
||||
- Response times are consistently fast
|
||||
|
||||
**Note:** Timeout settings are currently set in the backend configuration. A future release will make this configurable via the UI.
|
||||
|
||||
### Retry Behavior
|
||||
|
||||
When a check fails, Charon automatically retries:
|
||||
|
||||
- **Max retries:** 2 attempts
|
||||
- **Retry delay:** 2 seconds between attempts
|
||||
- **Timeout per attempt:** 10 seconds (configurable)
|
||||
|
||||
**Total check time calculation:**
|
||||
|
||||
```
|
||||
Max time = (timeout × max_retries) + (retry_delay × (max_retries - 1))
|
||||
= (10s × 2) + (2s × 1)
|
||||
= 22 seconds worst case
|
||||
```
|
||||
|
||||
### Check Interval
|
||||
|
||||
**Default:** 60 seconds
|
||||
|
||||
The interval between check cycles for all hosts.
|
||||
|
||||
**Performance considerations:**
|
||||
|
||||
- Shorter intervals = faster detection but higher CPU/network usage
|
||||
- Longer intervals = lower overhead but slower failure detection
|
||||
- Recommended: 30-120 seconds depending on criticality
|
||||
|
||||
## Enabling Uptime Monitoring
|
||||
|
||||
### For a Single Host
|
||||
|
||||
1. Navigate to **Proxy Hosts**
|
||||
2. Click **Edit** on the host
|
||||
3. Scroll to **Uptime Monitoring** section
|
||||
4. Toggle **"Enable Uptime Monitoring"** to ON
|
||||
5. Click **Save**
|
||||
|
||||
### For Multiple Hosts (Bulk)
|
||||
|
||||
1. Navigate to **Proxy Hosts**
|
||||
2. Select checkboxes for hosts to monitor
|
||||
3. Click **"Bulk Apply"** button
|
||||
4. Find **"Uptime Monitoring"** section
|
||||
5. Toggle the switch to **ON**
|
||||
6. Check **"Apply to selected hosts"**
|
||||
7. Click **"Apply Changes"**
|
||||
|
||||
## Monitoring Dashboard
|
||||
|
||||
### Host Status Display
|
||||
|
||||
Each monitored host shows:
|
||||
|
||||
- **Status Badge**: 🟢 Up / 🔴 Down
|
||||
- **Response Time**: Last successful check latency
|
||||
- **Uptime Percentage**: Success rate over time
|
||||
- **Last Check**: Timestamp of most recent check
|
||||
|
||||
### Status Page
|
||||
|
||||
View all monitored hosts at a glance:
|
||||
|
||||
1. Navigate to **Dashboard** → **Uptime Status**
|
||||
2. See real-time status of all hosts
|
||||
3. Click any host for detailed history
|
||||
4. Filter by status (up/down/all)
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### False Positive: Host Shown as Down but Actually Up
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Host shows "down" in Charon
|
||||
- Service is accessible directly
|
||||
- Status changes back to "up" shortly after
|
||||
|
||||
**Common causes:**
|
||||
|
||||
1. **Timeout too short for slow network**
|
||||
|
||||
**Solution:** Increase TCP timeout in configuration
|
||||
|
||||
2. **Container warmup time exceeds timeout**
|
||||
|
||||
**Solution:** Use longer timeout or optimize container startup
|
||||
|
||||
3. **Network congestion during check**
|
||||
|
||||
**Solution:** Debouncing (already enabled) should handle this automatically
|
||||
|
||||
4. **Firewall blocking health checks**
|
||||
|
||||
**Solution:** Ensure Charon container can reach proxy host ports
|
||||
|
||||
5. **Multiple checks running concurrently**
|
||||
|
||||
**Solution:** Automatic synchronization ensures checks complete before next cycle
|
||||
|
||||
**Diagnostic steps:**
|
||||
|
||||
```bash
|
||||
# Check Charon logs for timing info
|
||||
docker logs charon 2>&1 | grep "Host TCP check completed"
|
||||
|
||||
# Look for retry attempts
|
||||
docker logs charon 2>&1 | grep "Retrying TCP check"
|
||||
|
||||
# Check failure count patterns
|
||||
docker logs charon 2>&1 | grep "failure_count"
|
||||
|
||||
# View host status changes
|
||||
docker logs charon 2>&1 | grep "Host status changed"
|
||||
```
|
||||
|
||||
### False Negative: Host Shown as Up but Actually Down
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Host shows "up" in Charon
|
||||
- Service returns errors or is inaccessible
|
||||
- No down alerts received
|
||||
|
||||
**Common causes:**
|
||||
|
||||
1. **TCP port open but service not responding**
|
||||
|
||||
**Explanation:** Uptime monitoring only checks TCP connectivity, not application health
|
||||
|
||||
**Solution:** Consider implementing application-level health checks (future feature)
|
||||
|
||||
2. **Service accepts connections but returns errors**
|
||||
|
||||
**Solution:** Monitor application logs separately; TCP checks don't validate responses
|
||||
|
||||
3. **Partial service degradation**
|
||||
|
||||
**Solution:** Use multiple monitoring providers for critical services
|
||||
|
||||
**Current limitation:** Charon performs TCP health checks only. HTTP-based health checks are planned for a future release.
|
||||
|
||||
### Intermittent Status Flapping
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Status rapidly changes between up/down
|
||||
- Multiple notifications in short time
|
||||
- Logs show alternating success/failure
|
||||
|
||||
**Causes:**
|
||||
|
||||
1. **Marginal network conditions**
|
||||
|
||||
**Solution:** Increase failure threshold (requires configuration change)
|
||||
|
||||
2. **Resource exhaustion on target host**
|
||||
|
||||
**Solution:** Investigate target host performance, increase resources
|
||||
|
||||
3. **Shared network congestion**
|
||||
|
||||
**Solution:** Consider dedicated monitoring network or VLAN
|
||||
|
||||
**Mitigation:**
|
||||
|
||||
The built-in debouncing (2 consecutive failures required) should prevent most flapping. If issues persist, check:
|
||||
|
||||
```bash
|
||||
# Review consecutive check results
|
||||
docker logs charon 2>&1 | grep -A 2 "Host TCP check completed" | grep "host_name"
|
||||
|
||||
# Check response time trends
|
||||
docker logs charon 2>&1 | grep "elapsed_ms"
|
||||
```
|
||||
|
||||
### No Notifications Received
|
||||
|
||||
**Checklist:**
|
||||
|
||||
1. ✅ Uptime monitoring is enabled for the host
|
||||
2. ✅ Notification provider is configured and enabled
|
||||
3. ✅ Provider is set to trigger on uptime events
|
||||
4. ✅ Status has actually changed (check logs)
|
||||
5. ✅ Debouncing threshold has been met (2 consecutive failures)
|
||||
|
||||
**Debug notifications:**
|
||||
|
||||
```bash
|
||||
# Check for notification attempts
|
||||
docker logs charon 2>&1 | grep "notification"
|
||||
|
||||
# Look for uptime-related notifications
|
||||
docker logs charon 2>&1 | grep "uptime_down\|uptime_up"
|
||||
|
||||
# Verify notification service is working
|
||||
docker logs charon 2>&1 | grep "Failed to send notification"
|
||||
```
|
||||
|
||||
### High CPU Usage from Monitoring
|
||||
|
||||
**Symptoms:**
|
||||
|
||||
- Charon container using excessive CPU
|
||||
- System becomes slow during check cycles
|
||||
- Logs show slow check times
|
||||
|
||||
**Solutions:**
|
||||
|
||||
1. **Reduce number of monitored hosts**
|
||||
|
||||
Monitor only critical services; disable monitoring for non-essential hosts
|
||||
|
||||
2. **Increase check interval**
|
||||
|
||||
Change from 60s to 120s to reduce frequency
|
||||
|
||||
3. **Optimize Docker resource allocation**
|
||||
|
||||
Ensure adequate CPU/memory allocated to Charon container
|
||||
|
||||
4. **Check for network issues**
|
||||
|
||||
Slow DNS or network problems can cause checks to hang
|
||||
|
||||
**Monitor check performance:**
|
||||
|
||||
```bash
|
||||
# View check duration distribution
|
||||
docker logs charon 2>&1 | grep "elapsed_ms" | tail -50
|
||||
|
||||
# Count concurrent checks
|
||||
docker logs charon 2>&1 | grep "All host checks completed"
|
||||
```
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Port Detection
|
||||
|
||||
Charon automatically determines which port to check:
|
||||
|
||||
**Priority order:**
|
||||
|
||||
1. **ProxyHost.ForwardPort**: Preferred, most reliable
|
||||
2. **URL extraction**: Fallback for hosts without proxy configuration
|
||||
3. **Default ports**: 80 (HTTP) or 443 (HTTPS) if port not specified
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
Host: example.com
|
||||
Forward Port: 8080
|
||||
→ Checks: example.com:8080
|
||||
|
||||
Host: api.example.com
|
||||
URL: https://api.example.com/health
|
||||
Forward Port: (not set)
|
||||
→ Checks: api.example.com:443
|
||||
```
|
||||
|
||||
### Concurrent Check Processing
|
||||
|
||||
All host checks run concurrently for better performance:
|
||||
|
||||
- Each host checked in separate goroutine
|
||||
- WaitGroup ensures all checks complete before next cycle
|
||||
- Prevents database race conditions
|
||||
- No single slow host blocks other checks
|
||||
|
||||
**Performance characteristics:**
|
||||
|
||||
- **Sequential checks** (old): `time = hosts × timeout`
|
||||
- **Concurrent checks** (current): `time = max(individual_check_times)`
|
||||
|
||||
**Example:** With 10 hosts and 10s timeout:
|
||||
|
||||
- Sequential: ~100 seconds minimum
|
||||
- Concurrent: ~10 seconds (if all succeed on first try)
|
||||
|
||||
### Database Storage
|
||||
|
||||
Uptime data is stored efficiently:
|
||||
|
||||
**UptimeHost table:**
|
||||
|
||||
- `status`: Current status ("up"/"down")
|
||||
- `failure_count`: Consecutive failure counter
|
||||
- `last_check`: Timestamp of last check
|
||||
- `response_time`: Last successful response time
|
||||
|
||||
**UptimeMonitor table:**
|
||||
|
||||
- Links monitors to proxy hosts
|
||||
- Stores check configuration
|
||||
- Tracks enabled state
|
||||
|
||||
**Heartbeat records** (future):
|
||||
|
||||
- Detailed history of each check
|
||||
- Used for uptime percentage calculations
|
||||
- Queryable for historical analysis
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Monitor Critical Services Only
|
||||
|
||||
Don't monitor every host. Focus on:
|
||||
|
||||
- Production services
|
||||
- User-facing applications
|
||||
- External dependencies
|
||||
- High-availability requirements
|
||||
|
||||
**Skip monitoring for:**
|
||||
|
||||
- Development/test instances
|
||||
- Internal tools with built-in redundancy
|
||||
- Services with their own monitoring
|
||||
|
||||
### 2. Configure Appropriate Notifications
|
||||
|
||||
**Critical services:**
|
||||
|
||||
- Multiple notification channels (Discord + Slack)
|
||||
- Immediate alerts (no batching)
|
||||
- On-call team notifications
|
||||
|
||||
**Non-critical services:**
|
||||
|
||||
- Single notification channel
|
||||
- Digest/batch notifications (future feature)
|
||||
- Email to team (low priority)
|
||||
|
||||
### 3. Review False Positives
|
||||
|
||||
If you receive false alarms:
|
||||
|
||||
1. Check logs to understand why
|
||||
2. Adjust timeout if needed
|
||||
3. Verify network stability
|
||||
4. Consider increasing failure threshold (future config option)
|
||||
|
||||
### 4. Regular Status Review
|
||||
|
||||
Weekly review of:
|
||||
|
||||
- Uptime percentages (identify problematic hosts)
|
||||
- Response time trends (detect degradation)
|
||||
- Notification frequency (too many alerts?)
|
||||
- False positive rate (refine configuration)
|
||||
|
||||
### 5. Combine with Application Monitoring
|
||||
|
||||
Uptime monitoring checks **availability**, not **functionality**.
|
||||
|
||||
Complement with:
|
||||
|
||||
- Application-level health checks
|
||||
- Error rate monitoring
|
||||
- Performance metrics (APM tools)
|
||||
- User experience monitoring
|
||||
|
||||
## Planned Improvements
|
||||
|
||||
Future enhancements under consideration:
|
||||
|
||||
- [ ] **HTTP health check support** - Check specific endpoints with status code validation
|
||||
- [ ] **Configurable failure threshold** - Adjust consecutive failure count via UI
|
||||
- [ ] **Custom check intervals per host** - Different intervals for different criticality levels
|
||||
- [ ] **Response time alerts** - Notify on degraded performance, not just failures
|
||||
- [ ] **Notification batching** - Group multiple alerts to reduce noise
|
||||
- [ ] **Maintenance windows** - Disable alerts during scheduled maintenance
|
||||
- [ ] **Historical graphs** - Visual uptime trends over time
|
||||
- [ ] **Status page export** - Public status page for external visibility
|
||||
|
||||
## Monitoring the Monitors
|
||||
|
||||
How do you know if Charon's monitoring is working?
|
||||
|
||||
**Check Charon's own health:**
|
||||
|
||||
```bash
|
||||
# Verify check cycle is running
|
||||
docker logs charon 2>&1 | grep "All host checks completed" | tail -5
|
||||
|
||||
# Confirm recent checks happened
|
||||
docker logs charon 2>&1 | grep "Host TCP check completed" | tail -20
|
||||
|
||||
# Look for any errors in monitoring system
|
||||
docker logs charon 2>&1 | grep "ERROR.*uptime\|ERROR.*monitor"
|
||||
```
|
||||
|
||||
**Expected log pattern:**
|
||||
|
||||
```
|
||||
INFO[...] All host checks completed host_count=5
|
||||
DEBUG[...] Host TCP check completed elapsed_ms=156 host_name=example.com success=true
|
||||
```
|
||||
|
||||
**Warning signs:**
|
||||
|
||||
- No "All host checks completed" messages in recent logs
|
||||
- Checks taking longer than expected (>30s with 10s timeout)
|
||||
- Frequent timeout errors
|
||||
- High failure_count values
|
||||
|
||||
## API Integration
|
||||
|
||||
Uptime monitoring data is accessible via API:
|
||||
|
||||
**Get uptime status:**
|
||||
|
||||
```bash
|
||||
GET /api/uptime/hosts
|
||||
Authorization: Bearer <token>
|
||||
```
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"hosts": [
|
||||
{
|
||||
"id": "123",
|
||||
"name": "example.com",
|
||||
"status": "up",
|
||||
"last_check": "2025-12-24T10:30:00Z",
|
||||
"response_time": 156,
|
||||
"failure_count": 0,
|
||||
"uptime_percentage": 99.8
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**Programmatic monitoring:**
|
||||
|
||||
Use this API to integrate Charon's uptime data with:
|
||||
|
||||
- External monitoring dashboards (Grafana, etc.)
|
||||
- Incident response systems (PagerDuty, etc.)
|
||||
- Custom alerting tools
|
||||
- Status page generators
|
||||
|
||||
## Additional Resources
|
||||
|
||||
- [Notification Configuration Guide](notifications.md)
|
||||
- [Proxy Host Setup](../getting-started.md)
|
||||
- [Troubleshooting Guide](../troubleshooting/)
|
||||
- [Security Best Practices](../security.md)
|
||||
|
||||
## Need Help?
|
||||
|
||||
- 💬 [Ask in Discussions](https://github.com/Wikid82/charon/discussions)
|
||||
- 🐛 [Report Issues](https://github.com/Wikid82/charon/issues)
|
||||
- 📖 [View Full Documentation](https://wikid82.github.io/charon/)
|
||||
@@ -1,90 +0,0 @@
|
||||
---
|
||||
title: Web Application Firewall (WAF)
|
||||
description: Protect against OWASP Top 10 vulnerabilities with Coraza WAF
|
||||
---
|
||||
|
||||
# Web Application Firewall (WAF)
|
||||
|
||||
Stop common attacks like SQL injection, cross-site scripting (XSS), and path traversal before they reach your applications. Powered by Coraza, the WAF protects your apps from the OWASP Top 10 vulnerabilities.
|
||||
|
||||
## Overview
|
||||
|
||||
The Web Application Firewall inspects every HTTP/HTTPS request and blocks malicious payloads before they reach your backend services. Charon uses [Coraza](https://coraza.io/), a high-performance, open-source WAF engine compatible with the OWASP Core Rule Set (CRS).
|
||||
|
||||
Protected attack types include:
|
||||
|
||||
- **SQL Injection** — Blocks database manipulation attempts
|
||||
- **Cross-Site Scripting (XSS)** — Prevents script injection attacks
|
||||
- **Path Traversal** — Stops directory traversal exploits
|
||||
- **Remote Code Execution** — Blocks command injection
|
||||
- **Zero-Day Exploits** — CRS updates provide protection against newly discovered vulnerabilities
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Defense in Depth** — Add a security layer in front of your applications
|
||||
- **OWASP CRS** — Industry-standard ruleset trusted by enterprises
|
||||
- **Low Latency** — Coraza processes rules efficiently with minimal overhead
|
||||
- **Flexible Modes** — Choose between monitoring and active blocking
|
||||
|
||||
## Configuration
|
||||
|
||||
### Enabling WAF
|
||||
|
||||
1. Navigate to **Proxy Hosts**
|
||||
2. Edit or create a proxy host
|
||||
3. In the **Security** tab, toggle **Web Application Firewall**
|
||||
4. Select your preferred mode
|
||||
|
||||
### Operating Modes
|
||||
|
||||
| Mode | Behavior | Use Case |
|
||||
|------|----------|----------|
|
||||
| **Monitor** | Logs threats but allows traffic | Testing rules, reducing false positives |
|
||||
| **Block** | Actively blocks malicious requests | Production protection |
|
||||
|
||||
**Recommendation**: Start in Monitor mode to review detected threats, then switch to Block mode once you're confident in the rules.
|
||||
|
||||
### Per-Host Configuration
|
||||
|
||||
WAF can be enabled independently for each proxy host:
|
||||
|
||||
- Enable for public-facing applications
|
||||
- Disable for internal services or APIs with custom security
|
||||
- Mix modes across different hosts as needed
|
||||
|
||||
## Zero-Day Protection
|
||||
|
||||
The OWASP Core Rule Set is regularly updated to address:
|
||||
|
||||
- Newly discovered CVEs
|
||||
- Emerging attack patterns
|
||||
- Bypass techniques
|
||||
|
||||
Charon includes the latest CRS version and receives updates through container image releases.
|
||||
|
||||
## Limitations
|
||||
|
||||
The WAF protects **HTTP and HTTPS traffic only**:
|
||||
|
||||
| Traffic Type | Protected |
|
||||
|--------------|-----------|
|
||||
| HTTP/HTTPS Proxy Hosts | ✅ Yes |
|
||||
| TCP/UDP Streams | ❌ No |
|
||||
| Non-HTTP protocols | ❌ No |
|
||||
|
||||
For TCP/UDP protection, use [CrowdSec](./crowdsec.md) or network-level firewalls.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Issue | Solution |
|
||||
|-------|----------|
|
||||
| Legitimate requests blocked | Switch to Monitor mode and review logs |
|
||||
| High latency | Check if complex rules are triggering; consider rule tuning |
|
||||
| WAF not activating | Verify the proxy host has WAF enabled in Security tab |
|
||||
|
||||
## Related
|
||||
|
||||
- [CrowdSec Integration](./crowdsec.md) — Behavioral threat detection
|
||||
- [Access Control](./access-control.md) — IP and geo-based restrictions
|
||||
- [Proxy Hosts](./proxy-hosts.md) — Configure WAF per host
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,129 +0,0 @@
|
||||
---
|
||||
title: Point & Click Management
|
||||
description: Manage your reverse proxy through an intuitive web interface
|
||||
category: core
|
||||
---
|
||||
|
||||
# Point & Click Management
|
||||
|
||||
Say goodbye to editing configuration files and memorizing commands. Charon gives you a beautiful web interface where you simply type your domain name, select your backend service, and click save.
|
||||
|
||||
## Overview
|
||||
|
||||
Traditional reverse proxy configuration requires editing text files, understanding complex syntax, and reloading services. Charon replaces this workflow with an intuitive web interface that makes proxy management accessible to everyone.
|
||||
|
||||
### Key Capabilities
|
||||
|
||||
- **Form-Based Configuration**: Fill in fields instead of writing syntax
|
||||
- **Instant Validation**: Catch errors before they break your setup
|
||||
- **Live Preview**: See configuration changes before applying
|
||||
- **One-Click Actions**: Enable, disable, or delete hosts instantly
|
||||
|
||||
## Why Use This
|
||||
|
||||
### No Config Files Needed
|
||||
|
||||
- Never edit Caddyfile, nginx.conf, or Apache configs manually
|
||||
- Changes apply immediately without service restarts
|
||||
- Syntax errors become impossible—the UI validates everything
|
||||
|
||||
### Reduced Learning Curve
|
||||
|
||||
- New team members are productive in minutes
|
||||
- No need to memorize directives or options
|
||||
- Tooltips explain each setting's purpose
|
||||
|
||||
### Audit Trail
|
||||
|
||||
- See who changed what and when
|
||||
- Roll back to previous configurations
|
||||
- Track configuration drift over time
|
||||
|
||||
## Features
|
||||
|
||||
### Form-Based Host Creation
|
||||
|
||||
Creating a new proxy host takes seconds:
|
||||
|
||||
1. Click **Add Host**
|
||||
2. Enter domain name (e.g., `app.example.com`)
|
||||
3. Enter backend address (e.g., `http://192.168.1.100:3000`)
|
||||
4. Toggle SSL certificate option
|
||||
5. Click **Save**
|
||||
|
||||
### Bulk Operations
|
||||
|
||||
Manage multiple hosts efficiently:
|
||||
|
||||
- **Bulk Enable/Disable**: Select hosts and toggle status
|
||||
- **Bulk Delete**: Remove multiple hosts at once
|
||||
- **Bulk Export**: Download configurations for backup
|
||||
- **Clone Host**: Duplicate configuration to new domain
|
||||
|
||||
### Search and Filter
|
||||
|
||||
Find hosts quickly in large deployments:
|
||||
|
||||
- Search by domain name
|
||||
- Filter by status (enabled, disabled, error)
|
||||
- Filter by certificate status
|
||||
- Sort by name, creation date, or last modified
|
||||
|
||||
## Mobile-Friendly Design
|
||||
|
||||
Charon's responsive interface works on any device:
|
||||
|
||||
- **Phone**: Manage proxies from anywhere
|
||||
- **Tablet**: Full functionality with touch-friendly controls
|
||||
- **Desktop**: Complete dashboard with side-by-side panels
|
||||
|
||||
### Dark Mode Interface
|
||||
|
||||
Reduce eye strain during late-night maintenance:
|
||||
|
||||
- Automatic detection of system preference
|
||||
- Manual toggle in settings
|
||||
- High contrast for accessibility
|
||||
- Consistent styling across all components
|
||||
|
||||
## Configuration
|
||||
|
||||
### Accessing the UI
|
||||
|
||||
1. Open your browser to Charon's address (default: `http://localhost:81`)
|
||||
2. Log in with your credentials
|
||||
3. Dashboard displays all configured hosts
|
||||
|
||||
### Quick Actions
|
||||
|
||||
| Action | How To |
|
||||
|--------|--------|
|
||||
| Add new host | Click **+ Add Host** button |
|
||||
| Edit host | Click host row or edit icon |
|
||||
| Enable/Disable | Toggle switch in host row |
|
||||
| Delete host | Click delete icon, confirm |
|
||||
| View logs | Click host → **Logs** tab |
|
||||
|
||||
### Keyboard Shortcuts
|
||||
|
||||
| Shortcut | Action |
|
||||
|----------|--------|
|
||||
| `Ctrl/Cmd + N` | New host |
|
||||
| `Ctrl/Cmd + S` | Save current form |
|
||||
| `Ctrl/Cmd + F` | Focus search |
|
||||
| `Escape` | Close modal/cancel |
|
||||
|
||||
## Dashboard Overview
|
||||
|
||||
The main dashboard provides at-a-glance status:
|
||||
|
||||
- **Total Hosts**: Number of configured proxies
|
||||
- **Active/Inactive**: Hosts currently serving traffic
|
||||
- **Certificate Status**: SSL expiration warnings
|
||||
- **Recent Activity**: Latest configuration changes
|
||||
|
||||
## Related
|
||||
|
||||
- [Docker Integration](docker-integration.md) - Auto-discover containers
|
||||
- [Caddyfile Import](caddyfile-import.md) - Migrate existing configs
|
||||
- [Back to Features](../features.md)
|
||||
@@ -1,77 +0,0 @@
|
||||
---
|
||||
title: WebSocket Support
|
||||
description: Real-time WebSocket connections work out of the box
|
||||
---
|
||||
|
||||
# WebSocket Support
|
||||
|
||||
Real-time applications like chat servers, live dashboards, and collaborative tools work out of the box. Charon handles WebSocket connections automatically with no special configuration needed.
|
||||
|
||||
## Overview
|
||||
|
||||
WebSocket connections enable persistent, bidirectional communication between browsers and servers. Unlike traditional HTTP requests, WebSockets maintain an open connection for real-time data exchange.
|
||||
|
||||
Charon automatically detects and handles WebSocket upgrade requests, proxying them to your backend services transparently. This works for any application that uses WebSockets—no special configuration required.
|
||||
|
||||
## Why Use This
|
||||
|
||||
- **Zero Configuration**: WebSocket proxying works automatically
|
||||
- **Full Protocol Support**: Handles all WebSocket features including subprotocols
|
||||
- **Transparent Proxying**: Your applications don't know they're behind a proxy
|
||||
- **TLS Termination**: Secure WebSocket (wss://) connections handled automatically
|
||||
|
||||
## Common Use Cases
|
||||
|
||||
WebSocket support enables proxying for:
|
||||
|
||||
| Application Type | Examples |
|
||||
|-----------------|----------|
|
||||
| **Chat Applications** | Slack alternatives, support chat widgets |
|
||||
| **Live Dashboards** | Monitoring tools, analytics platforms |
|
||||
| **Collaborative Tools** | Real-time document editing, whiteboards |
|
||||
| **Gaming** | Multiplayer game servers, matchmaking |
|
||||
| **Notifications** | Push notifications, live alerts |
|
||||
| **Streaming** | Live data feeds, stock tickers |
|
||||
|
||||
## How It Works
|
||||
|
||||
When Caddy receives a request with WebSocket upgrade headers:
|
||||
|
||||
1. Caddy detects the `Upgrade: websocket` header
|
||||
2. The connection is upgraded from HTTP to WebSocket
|
||||
3. Traffic flows bidirectionally through the proxy
|
||||
4. Connection remains open until either side closes it
|
||||
|
||||
### Technical Details
|
||||
|
||||
Caddy handles these WebSocket aspects automatically:
|
||||
|
||||
- **Connection Upgrade**: Properly forwards upgrade headers
|
||||
- **Protocol Negotiation**: Passes through subprotocol selection
|
||||
- **Keep-Alive**: Maintains connection through proxy timeouts
|
||||
- **Graceful Close**: Handles WebSocket close frames correctly
|
||||
|
||||
## Configuration
|
||||
|
||||
No configuration is needed. Simply create a proxy host pointing to your WebSocket-enabled backend:
|
||||
|
||||
```text
|
||||
Backend: http://your-app:3000
|
||||
```
|
||||
|
||||
Your application's WebSocket connections (both `ws://` and `wss://`) will work automatically.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If WebSocket connections fail:
|
||||
|
||||
1. **Check Backend**: Ensure your app listens for WebSocket connections
|
||||
2. **Verify Port**: WebSocket uses the same port as HTTP
|
||||
3. **Test Directly**: Try connecting to the backend without the proxy
|
||||
4. **Check Logs**: Look for connection errors in real-time logs
|
||||
|
||||
## Related
|
||||
|
||||
- [Real-Time Logs](logs.md)
|
||||
- [Proxy Hosts](proxy-hosts.md)
|
||||
- [Back to Features](../features.md)
|
||||
Reference in New Issue
Block a user