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 userdocker— Docker CE + Compose plugin via official apt reposervices— renders Jinja2 templates →/opt/services/, then runsdocker compose up
Templates → server files:
roles/services/templates/docker-compose.yml.j2→/opt/services/docker-compose.ymlroles/services/templates/env.j2→/opt/services/.env(mode 0600)roles/services/templates/traefik/traefik.yml.j2→/opt/services/traefik/traefik.ymlacme.jsoncreated at/opt/services/traefik/acme.json(mode 0600, mounted into Traefik)
Docker networks:
backend(internal) — traefik ↔ user-facing servicesforgejo-db(internal) — forgejo ↔ its postgresplane-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.