Major Changes: - Add dual SSH mode system (passthrough default, dedicated fallback) - Refactor domain configuration to use direct specification pattern - Fix critical fail2ban security gap in dedicated mode - Separate HTTP and SSH domains for cleaner Git URLs
8.0 KiB
Service Domain Configuration Standard
Standard pattern for domain configuration in rick-infra service roles.
Architecture Philosophy
Rick-infra follows a direct domain specification pattern for service configuration:
# Direct and explicit
service_domain: "subdomain.jnss.me"
# NOT this (complex and inflexible)
service_subdomain: "subdomain"
service_domain: "{{ caddy_domain }}"
service_full_domain: "{{ service_subdomain }}.{{ service_domain }}"
Benefits
- Simplicity: One variable instead of three
- Flexibility: Can use any domain (subdomain, root, or completely different)
- Explicitness: Clear what domain the service uses
- No Forced Inheritance: Not tied to infrastructure
caddy_domain - Consistency: All services follow the same pattern
Standard Pattern
Basic Service (Single Domain)
For services that only need one domain:
# roles/service/defaults/main.yml
service_domain: "service.jnss.me"
# host_vars/host/main.yml (explicit override)
service_domain: "service.jnss.me"
Examples:
- Authentik:
authentik_domain: "auth.jnss.me" - Nextcloud:
nextcloud_domain: "cloud.jnss.me"
Advanced Service (Multiple Domains)
For services that need separate domains for different purposes:
# roles/service/defaults/main.yml
service_http_domain: "service.jnss.me" # Web interface
service_api_domain: "api.jnss.me" # API endpoint
service_ssh_domain: "jnss.me" # SSH/CLI operations
# host_vars/host/main.yml (explicit override)
service_http_domain: "service.jnss.me"
service_api_domain: "api.jnss.me"
service_ssh_domain: "jnss.me"
Example:
- Gitea:
gitea_http_domain: "git.jnss.me"(web interface)gitea_ssh_domain: "jnss.me"(Git operations)
Usage in Templates
Caddy Configuration
# roles/service/templates/service.caddy.j2
{{ service_domain }} {
reverse_proxy 127.0.0.1:{{ service_port }}
}
Application Configuration
# roles/service/templates/service.conf.j2
[server]
DOMAIN = {{ service_domain }}
ROOT_URL = https://{{ service_domain }}/
Task Display Messages
# roles/service/tasks/main.yml
- name: Display service information
debug:
msg: |
🌐 Web Interface: https://{{ service_domain }}
📍 Access your service at the domain above
Domain Selection Guidelines
Use Root Domain When:
- Service is the primary purpose of the infrastructure
- You want cleaner URLs (e.g., SSH:
git@jnss.mevsgit@git.jnss.me) - Industry standard uses root domain (e.g., GitHub uses
github.comfor SSH)
Use Subdomain When:
- Service is one of many
- You want explicit service identification
- You need clear separation between services
Use Different Domain When:
- Service needs to be on a different apex domain
- External service integration requires specific domain
- Multi-domain setup for geographical distribution
Examples by Service Type
Identity/Auth Service
authentik_domain: "auth.jnss.me"
Rationale: Auth subdomain is an industry standard
Storage Service
nextcloud_domain: "cloud.jnss.me"
Rationale: "cloud" clearly indicates storage/sync service
Git Service
gitea_http_domain: "git.jnss.me" # Web UI
gitea_ssh_domain: "jnss.me" # SSH operations
Rationale:
- HTTP uses
git.for clarity - SSH uses root domain to avoid
git@git.jnss.meredundancy - Matches GitHub/GitLab pattern
Monitoring Service
grafana_domain: "monitor.jnss.me"
prometheus_domain: "metrics.jnss.me"
Rationale: Different subdomains for different monitoring tools
Configuration Layers
1. Role Defaults (roles/service/defaults/main.yml)
Provide sensible defaults:
# Option A: Use specific domain (explicit)
service_domain: "service.jnss.me"
# Option B: Use caddy_domain if it makes sense (flexible)
service_domain: "service.{{ caddy_domain | default('localhost') }}"
# Recommendation: Use Option A for clarity
2. Host Variables (host_vars/hostname/main.yml)
Always explicitly set in production:
# =================================================================
# Service Configuration
# =================================================================
service_domain: "service.jnss.me"
Why explicit?
- Clear what domain is configured
- Easy to change without understanding defaults
- Easier to audit configuration
- Documentation in configuration itself
3. Group Variables (group_vars/production/main.yml)
For settings shared across production hosts:
# Common production settings
service_enable_ssl: true
service_require_auth: true
# Generally avoid setting domains in group_vars
# (domains are usually host-specific)
Anti-Patterns to Avoid
❌ Subdomain Composition
# DON'T DO THIS
service_subdomain: "service"
service_domain: "{{ caddy_domain }}"
service_full_domain: "{{ service_subdomain }}.{{ service_domain }}"
Problems:
- Complex (3 variables for 1 domain)
- Inflexible (can't use root or different domains)
- Forces inheritance from infrastructure variable
- Inconsistent with other services
❌ Implicit Inheritance
# DON'T DO THIS
service_domain: "{{ caddy_domain }}"
Problems:
- Not explicit what domain is used
- Harder to change
- Hides actual configuration
- Requires understanding of infrastructure variables
❌ Mixed Patterns
# DON'T DO THIS
authentik_domain: "auth.jnss.me" # Direct
nextcloud_subdomain: "cloud" # Composition
service_domain: "{{ caddy_domain }}" # Inheritance
Problems:
- Inconsistent
- Confusing for maintainers
- Different patterns for same purpose
Migration from Old Pattern
If you have services using the old subdomain composition pattern:
Step 1: Identify Current Variables
# Old pattern
service_subdomain: "service"
service_domain: "{{ caddy_domain }}"
service_full_domain: "{{ service_subdomain }}.{{ service_domain }}"
Step 2: Replace with Direct Domain
# New pattern
service_domain: "service.jnss.me"
Step 3: Update Template References
# Old
{{ service_full_domain }}
# New
{{ service_domain }}
Step 4: Remove Unused Variables
Delete service_subdomain and service_full_domain from defaults.
Step 5: Add Explicit Host Configuration
# host_vars/arch-vps/main.yml
service_domain: "service.jnss.me"
Testing Domain Configuration
Verify Caddy Configuration
# Check generated Caddy config
cat /etc/caddy/sites-enabled/service.caddy
# Test Caddy configuration syntax
caddy validate --config /etc/caddy/Caddyfile
# Check TLS certificate
curl -I https://service.jnss.me
Verify Application Configuration
# Check service configuration
cat /etc/service/config.ini | grep -i domain
# Test service accessibility
curl https://service.jnss.me
Verify DNS Resolution
# Check DNS resolution
dig service.jnss.me
# Test connectivity
nc -zv service.jnss.me 443
Checklist for New Services
When creating a new service role:
- Use direct domain specification (not subdomain composition)
- Define domain(s) in
roles/service/defaults/main.yml - Add explicit domain(s) to host_vars
- Update all templates to use domain variable(s)
- Document domain configuration in role README
- Follow naming convention:
service_domainorservice_[type]_domain - Test with different domain configurations
Summary
Standard Pattern:
# Defaults: Provide reasonable default
service_domain: "service.jnss.me"
# Host vars: Always explicit in production
service_domain: "service.jnss.me"
# Templates: Use variable directly
{{ service_domain }}
Key Principles:
- Direct and explicit
- One variable per domain
- No forced inheritance
- Consistent across all services
- Flexible for any domain pattern
Rick-Infra Domain Configuration Standard
Simple, flexible, and consistent domain configuration for all services.