# 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: ```yaml # roles/myservice/meta/main.yml dependencies: - role: caddy ``` ### 2. Service Configuration Template Create a Caddy configuration template: ```yaml # roles/myservice/templates/myservice.caddy.j2 {{ service_domain }} { reverse_proxy {{ service_backend }} } ``` ### 3. Service Deployment In your service tasks: ```yaml # 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: ```caddyfile # 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: ```yaml - 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 ```caddyfile # roles/simple-api/templates/simple-api.caddy.j2 simple.jnss.me { reverse_proxy localhost:3000 } ``` ```yaml # 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 ```caddyfile # 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 ```caddyfile # roles/static-files/templates/static-files.caddy.j2 static.jnss.me { root * /var/www/static file_server browse } ``` ### API with Custom Headers ```caddyfile # 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 ```bash ls -la /etc/caddy/sites-enabled/ ``` ### Check Configuration Files ```bash cat /etc/caddy/sites-enabled/myservice.caddy ``` ### Validate Caddy Configuration ```bash caddy validate --config /etc/caddy/Caddyfile ``` ### Test Configuration Changes ```bash caddy fmt --overwrite /etc/caddy/Caddyfile ``` ### View Caddy Logs ```bash journalctl -u caddy -f ``` ### Reload Configuration ```bash systemctl reload caddy ``` ### Test Service Directly ```bash curl http://localhost:8080/health ``` ### Test Through Caddy ```bash 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 1. **Naming**: Use descriptive, unique configuration file names 2. **Domains**: Follow consistent domain patterns (e.g., `service.domain.com`) 3. **Templates**: Use Jinja2 variables for flexibility 4. **Health Checks**: Always include health check endpoints in services 5. **Dependencies**: Declare Caddy dependency in service role meta 6. **Testing**: Validate configuration before deployment 7. **Cleanup**: Remove .caddy files when removing services 8. **Version Control**: Track all configuration changes in git ## Service Deployment Checklist - [ ] Create service role with Caddy dependency - [ ] Create `.caddy.j2` template file - [ ] Deploy template to `{{ caddy_sites_enabled_dir }}/` - [ ] Set proper file permissions (root:caddy 0644) - [ ] Trigger `reload caddy` handler - [ ] Test service accessibility - [ ] Verify HTTPS certificate generation ## Support For issues or questions about the Caddy service configuration system: 1. Check Caddy logs: `journalctl -u caddy -f` 2. Validate configuration: `caddy validate --config /etc/caddy/Caddyfile` 3. Check file permissions: `ls -la /etc/caddy/sites-enabled/` 4. Test service directly before adding to Caddy 5. Use `ansible-playbook --check` for dry-run testing