- Add cal.thesatelliteoflove.com:172.20.0.5 to MMDL extra_hosts for internal communication - Update DEPLOYMENT_LEARNINGS.md with comprehensive hairpinning documentation - Update CLAUDE.md with hairpinning guidance and correct deployment commands - Document standard pattern for Docker container internal domain resolution 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
4.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 25+ 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
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,gitea --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 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 (25+ containerized applications)
- cron: Scheduled task management (currently Warhammer RSS feed generation)
Service Categories in Docker Role
- Infrastructure: Caddy (reverse proxy), Authentik (SSO), Dockge (container management)
- Development: Gitea, Code Server, Matrix (Conduit)
- Media: Audiobookshelf, Calibre, Ghost blog, Pinchflat
- Productivity: Paperless-NGX, TasksMD/MMDL, Baikal (CalDAV/CardDAV), Syncthing
- Communication: GoToSocial (Fediverse), Postiz (social media management)
- Monitoring: Changedetection, Glance dashboard, AppriseAPI
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
Key Implementation Details
Template-Driven Configuration
The docker role uses Jinja2 templates extensively. When modifying services:
- Update templates in
roles/docker/templates/[service]-compose.yml.j2
- Environment files use
.env.j2
templates where needed - Main task files in
roles/docker/tasks/
include service-specific deployment logic
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:
- "auth.thesatelliteoflove.com:172.20.0.5"
- "cal.thesatelliteoflove.com:172.20.0.5"
Common domains requiring hairpinning fixes:
auth.thesatelliteoflove.com
(Authentik SSO)cal.thesatelliteoflove.com
(Baikal CalDAV)- Any service domain the container needs to communicate with