infra/CLAUDE.md
jack a1b97f3e4b Initial commit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 19:39:26 +07:00

2.7 KiB

CLAUDE.md

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

Commands

# Prerequisites (once, on operator machine)
ansible-galaxy collection install community.general community.docker ansible.posix
echo "yourpassword" > ~/.vault-password-file && chmod 600 ~/.vault-password-file

# First-time server setup (run as root)
ansible-playbook playbooks/bootstrap.yml -u root

# Idempotent deploy (all subsequent runs)
ansible-playbook playbooks/deploy.yml

# Edit secrets
ansible-vault edit inventory/group_vars/all.vault.yml

# Check syntax without connecting
ansible-playbook playbooks/deploy.yml --syntax-check

# Dry run
ansible-playbook playbooks/deploy.yml --check

# Run only specific role
ansible-playbook playbooks/deploy.yml --tags base
ansible-playbook playbooks/deploy.yml --tags docker
ansible-playbook playbooks/deploy.yml --tags services

Architecture

Traffic flow: Internet → Traefik (ports 80/443, TLS via Let's Encrypt ACME) → services. Ports 80 and 443 are open on the server.

Secrets: All secrets live in inventory/group_vars/all.vault.yml (Ansible Vault, AES-256). The file all.yml references them via "{{ vault_* }}" aliases. The vault password must exist at ~/.vault-password-file on the operator machine — this path is in .gitignore and never committed.

Roles:

  • base — OS hardening: UFW (allow SSH + 80 + 443), fail2ban, sshd config, deploy user
  • docker — Docker CE + Compose plugin via official apt repo
  • services — renders Jinja2 templates → /opt/services/, then runs docker compose up

Templates → server files:

  • roles/services/templates/docker-compose.yml.j2/opt/services/docker-compose.yml
  • roles/services/templates/env.j2/opt/services/.env (mode 0600)
  • roles/services/templates/traefik/traefik.yml.j2/opt/services/traefik/traefik.yml
  • acme.json created at /opt/services/traefik/acme.json (mode 0600, mounted into Traefik)

Docker networks:

  • backend (internal) — traefik ↔ user-facing services
  • forgejo-db (internal) — forgejo ↔ its postgres
  • plane-internal (internal) — all plane components (api, worker, beat, db, redis, minio)

Adding a new service: add container to docker-compose.yml.j2 on the backend network with traefik.enable=true and traefik.http.routers.X.tls.certresolver=letsencrypt labels, add its domain variable to all.yml.

Deployment

DNS: add A-records for each subdomain → server IP (or wildcard * → IP).

Fill all.vault.yml → set domain_base in all.yml → run bootstrap + deploy. Traefik obtains TLS certificates automatically on first request to each domain.