7.0 KiB
7.0 KiB
Caddy Service Configuration
Overview
The Caddy role uses a simple file-based approach where services deploy configuration files to a sites-enabled directory. This follows standard nginx-like patterns and uses Caddy's import directive for automatic configuration loading.
Key Features
- Simple & Reliable: File-based configuration with no API dependencies
- Zero Downtime: Configuration reloads without service restarts
- Automatic HTTPS: New domains get certificates automatically
- Standard Pattern: Familiar nginx-like
sites-enabled/approach - Easy Debugging: Configuration files are plaintext and easily inspected
- Version Control Friendly: Configuration changes are tracked in git
Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Service Role │ │ sites-enabled/ │ │ Caddy Core │
│ (Ansible) │───▶│ *.caddy files │───▶│ (Routes) │
│ │ │ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
Usage Pattern
1. Service Role Structure
Create a service role with dependency on Caddy:
# roles/myservice/meta/main.yml
dependencies:
- role: caddy
2. Service Configuration Template
Create a Caddy configuration template:
# roles/myservice/templates/myservice.caddy.j2
{{ service_domain }} {
reverse_proxy {{ service_backend }}
}
3. Service Deployment
In your service tasks:
# roles/myservice/tasks/main.yml
- name: Deploy my service
# ... service deployment tasks
- name: Deploy Caddy configuration
template:
src: myservice.caddy.j2
dest: "{{ caddy_sites_enabled_dir }}/myservice.caddy"
owner: root
group: "{{ caddy_user }}"
mode: '0644'
notify: reload caddy
4. Advanced Configuration Example
For load balancing and custom headers:
# roles/myapi/templates/myapi.caddy.j2
{{ service_domain }} {
reverse_proxy localhost:8080 localhost:8081 {
lb_policy round_robin
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Custom-Header "MyValue"
}
}
5. Service Removal
To remove a service:
- name: Remove service configuration
file:
path: "{{ caddy_sites_enabled_dir }}/myservice.caddy"
state: absent
notify: reload caddy
Available Handlers
reload caddy
- Reloads Caddy configuration without restart
- Automatically triggered when .caddy files change
- Safe to run multiple times
Configuration Variables
Template Variables
| Variable | Required | Description | Example |
|---|---|---|---|
service_domain |
Yes | Domain for the service | "api.jnss.me" |
service_backend |
Yes | Backend address | "localhost:8080" |
Caddy Configuration
| Variable | Default | Description |
|---|---|---|
caddy_sites_enabled_dir |
"/etc/caddy/sites-enabled" |
Directory for service configs |
caddy_user |
"caddy" |
Caddy system user |
caddy_config_file |
"/etc/caddy/Caddyfile" |
Main Caddyfile path |
Security
- File Permissions: Configuration files owned by root:caddy (0644)
- Process Isolation: SystemD security restrictions
- Network Isolation: Firewall only opens 80/443
- Configuration Validation: Automatic syntax checking
Examples
Simple API Service
# roles/simple-api/templates/simple-api.caddy.j2
simple.jnss.me {
reverse_proxy localhost:3000
}
# roles/simple-api/tasks/main.yml
- name: Deploy simple API configuration
template:
src: simple-api.caddy.j2
dest: "{{ caddy_sites_enabled_dir }}/simple-api.caddy"
owner: root
group: "{{ caddy_user }}"
mode: '0644'
notify: reload caddy
Load Balanced Service
# roles/balanced-api/templates/balanced-api.caddy.j2
balanced.jnss.me {
reverse_proxy localhost:8080 localhost:8081 localhost:8082 {
lb_policy least_conn
health_timeout 5s
health_interval 30s
}
}
Static File Service
# roles/static-files/templates/static-files.caddy.j2
static.jnss.me {
root * /var/www/static
file_server browse
}
API with Custom Headers
# roles/api-service/templates/api-service.caddy.j2
api.jnss.me {
reverse_proxy localhost:8080 {
header_up Host {upstream_hostport}
header_up X-Real-IP {remote_host}
header_up X-Forwarded-Proto https
header_down -Server
}
}
Troubleshooting
List Service Configurations
ls -la /etc/caddy/sites-enabled/
Check Configuration Files
cat /etc/caddy/sites-enabled/myservice.caddy
Validate Caddy Configuration
caddy validate --config /etc/caddy/Caddyfile
Test Configuration Changes
caddy fmt --overwrite /etc/caddy/Caddyfile
View Caddy Logs
journalctl -u caddy -f
Reload Configuration
systemctl reload caddy
Test Service Directly
curl http://localhost:8080/health
Test Through Caddy
curl https://myservice.jnss.me/health
Directory Structure
After deployment, your configuration will look like:
/etc/caddy/
├── Caddyfile # Main config with "import sites-enabled/*"
└── sites-enabled/ # Service configurations
├── api.caddy # API service config
├── dashboard.caddy # Dashboard service config
└── static.caddy # Static files config
Best Practices
- Naming: Use descriptive, unique configuration file names
- Domains: Follow consistent domain patterns (e.g.,
service.domain.com) - Templates: Use Jinja2 variables for flexibility
- Health Checks: Always include health check endpoints in services
- Dependencies: Declare Caddy dependency in service role meta
- Testing: Validate configuration before deployment
- Cleanup: Remove .caddy files when removing services
- Version Control: Track all configuration changes in git
Service Deployment Checklist
- Create service role with Caddy dependency
- Create
.caddy.j2template file - Deploy template to
{{ caddy_sites_enabled_dir }}/ - Set proper file permissions (root:caddy 0644)
- Trigger
reload caddyhandler - Test service accessibility
- Verify HTTPS certificate generation
Support
For issues or questions about the Caddy service configuration system:
- Check Caddy logs:
journalctl -u caddy -f - Validate configuration:
caddy validate --config /etc/caddy/Caddyfile - Check file permissions:
ls -la /etc/caddy/sites-enabled/ - Test service directly before adding to Caddy
- Use
ansible-playbook --checkfor dry-run testing