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

61 lines
2.7 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
# 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.