ansible/CLAUDE.md
Phil dad7e887a8 feat: complete variable management implementation and update documentation
- Update remaining Docker Compose templates with centralized variables
- Fix service tag isolation to deploy individual services only
- Update all README files with variable management architecture
- Document variable hierarchy in DEPLOYMENT_LEARNINGS.md
- Add comprehensive variable usage patterns to CLAUDE.md
- Standardize domain references using {{ subdomains.* }} pattern
- Replace hardcoded network names with {{ docker.network_name }}
- Update hairpinning configuration to use variables

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-06 15:45:52 -06:00

7.3 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

This is a personal infrastructure Ansible playbook that automates deployment and management of 22+ self-hosted Docker services across two domains (thesatelliteoflove.com and nerder.land). The setup uses Tailscale VPN for secure networking and Caddy for reverse proxy with automated HTTPS.

Important: Always review DEPLOYMENT_LEARNINGS.md when working on this repository for lessons learned and troubleshooting guidance.

Common Commands

Initial Setup

# Install Ansible dependencies
ansible-galaxy install -r requirements.yml

# Bootstrap new server (creates user, installs Tailscale, security hardening)
ansible-playbook bootstrap.yml -i hosts.yml

# Deploy all Docker services
ansible-playbook site.yml -i hosts.yml

# Update DNS records in AWS Route53
ansible-playbook dns.yml -i hosts.yml

Service Management

# Deploy specific services using tags (now properly isolated)
ansible-playbook site.yml -i hosts.yml --tags caddy --vault-password-file vault_pass --extra-vars "@secrets.enc"
ansible-playbook site.yml -i hosts.yml --tags authentik --vault-password-file vault_pass --extra-vars "@secrets.enc"
ansible-playbook site.yml -i hosts.yml --tags mmdl --vault-password-file vault_pass --extra-vars "@secrets.enc"
ansible-playbook site.yml -i hosts.yml --tags docker --vault-password-file vault_pass --extra-vars "@secrets.enc"  # all docker services

# Deploy services by category (new organized structure)
ansible-playbook site.yml -i hosts.yml --tags infrastructure --vault-password-file vault_pass --extra-vars "@secrets.enc"
ansible-playbook site.yml -i hosts.yml --tags media,productivity --vault-password-file vault_pass --extra-vars "@secrets.enc"
ansible-playbook site.yml -i hosts.yml --tags development,monitoring --vault-password-file vault_pass --extra-vars "@secrets.enc"

# Deploy only infrastructure components
ansible-playbook site.yml -i hosts.yml --tags common,cron --vault-password-file vault_pass --extra-vars "@secrets.enc"

Architecture

Host Configuration

  • Bootstrap Host (netcup): 152.53.36.98 - Initial server setup target
  • Docker Host (docker-01): 100.70.169.99 - Main service deployment via Tailscale

Role Structure

  • bootstrap: Initial server hardening, user creation, Tailscale VPN setup
  • common: Basic system configuration, UFW firewall management
  • docker: Comprehensive service deployment (22+ containerized applications, organized by category)
  • cron: Scheduled task management (currently Warhammer RSS feed generation)

Docker Role Organization (Reorganized into Logical Categories)

The docker role is now organized into logical service groups under roles/docker/tasks/:

  • infrastructure/: Core platform components
    • Caddy (reverse proxy), Authentik (SSO), Dockge (container management)
  • development/: Development and collaboration tools
    • Gitea, Code Server, Matrix (Conduit)
  • media/: Content creation and consumption
    • Audiobookshelf, Calibre, Ghost blog, Pinchflat, Pinry, Karakeep, Manyfold
  • productivity/: Personal organization and document management
    • Paperless-NGX, MMDL, Baikal (CalDAV/CardDAV), Syncthing, Heyform, Dawarich, Pingvin
  • communication/: Social media and external communication
    • GoToSocial (Fediverse), Postiz (social media management)
  • monitoring/: System monitoring and alerts
    • Changedetection, Glance dashboard, AppriseAPI

Variable Management

Critical: This infrastructure uses a centralized variable hierarchy in group_vars/all/:

  • domains.yml: Domain and subdomain mappings (use {{ subdomains.service }})
  • infrastructure.yml: Network configuration, Docker settings ({{ docker.network_name }}, {{ docker.hairpin_ip }})
  • vault.yml: Encrypted secrets with vault_ prefix
  • services.yml: Service-specific configuration and feature flags

Important: All templates use variables instead of hardcoded values. Never hardcode domains, IPs, or secrets.

Data Structure

  • All service data stored in /opt/stacks/[service-name]/ on docker host
  • Docker Compose files generated from Jinja2 templates in roles/docker/templates/
  • Environment files templated for services requiring configuration
  • All configurations use centralized variables for consistency

Key Implementation Details

Template-Driven Configuration

The docker role uses Jinja2 templates exclusively for all services. When modifying services:

  • Update templates in roles/docker/templates/[service]-compose.yml.j2
  • Environment files use .env.j2 templates where needed
  • Task files organized by category in roles/docker/tasks/[category]/[service].yml
  • All services now use templated configurations (no static compose files)

DNS Management

The dns.yml playbook manages AWS Route53 records for both domains. All subdomains point to the netcup server (152.53.36.98), with Caddy handling internal routing to the docker host via Tailscale.

Security Architecture

  • Tailscale provides secure networking between management and service hosts
  • Services are network-isolated using Docker
  • Caddy handles SSL termination with automatic Let's Encrypt certificates
  • UFW firewall managed through Docker integration script

Service Dependencies

Many services depend on Authentik for SSO. When deploying new services, consider:

  • Whether SSO integration is needed
  • Caddy routing configuration for subdomain access
  • Network connectivity requirements within Docker stack
  • Hairpinning fixes for internal service-to-service communication

Hairpinning Resolution

Services inside Docker containers cannot reach external domains that resolve to the same server. Fix by adding extra_hosts mappings:

extra_hosts:
  - "{{ subdomains.auth }}:{{ docker.hairpin_ip }}"
  - "{{ subdomains.cal }}:{{ docker.hairpin_ip }}"

Common domains requiring hairpinning fixes:

  • {{ subdomains.auth }} (Authentik SSO)
  • {{ subdomains.cal }} (Baikal CalDAV)
  • Any service domain the container needs to communicate with

Note: Use variables instead of hardcoded values for maintainability.

Service-Specific Reference Configurations

Service Memories

  • pingvin is the service that responds on files.thesatelliteoflove.com

Variable Management Implementation Notes

Major Infrastructure Update: Variable management system was implemented to replace all hardcoded values with centralized variables.

Key Changes Made:

  • Created comprehensive group_vars/all/ structure
  • Updated all Docker Compose templates to use variables
  • Fixed service tag isolation (individual service tags now deploy only that service)
  • Standardized domain and network configuration
  • Organized secrets by service with consistent vault_ prefix

Service Tag Fix:

Critical: Service tags are now properly isolated. --tags mmdl deploys only MMDL (5 tasks), not the entire productivity category.

Template Pattern:

All templates now follow this pattern:

# Use variables, not hardcoded values
glance.url: "https://{{ subdomains.service }}/"
networks:
  default:
    external: true
    name: "{{ docker.network_name }}"
extra_hosts:
  - "{{ subdomains.auth }}:{{ docker.hairpin_ip }}"