- 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>
160 lines
7.3 KiB
Markdown
160 lines
7.3 KiB
Markdown
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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:
|
|
|
|
```yaml
|
|
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
|
|
- **Dawarich**: Based on production compose file at https://github.com/Freika/dawarich/blob/master/docker/docker-compose.production.yml
|
|
|
|
## 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:
|
|
```yaml
|
|
# 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 }}"
|
|
``` |