Syncthing removal (was already decided, now fully removed): - roles/base/tasks/firewall.yml: remove 3 UFW rules (ports 22000/21027) - inventory/group_vars/all/main.yml: remove domain_sync, domain_mon, syncthing_basic_auth_htpasswd - roles/services/templates/env.j2: remove DOMAIN_SYNC - roles/services/templates/authelia/configuration.yml.j2: remove Syncthing 2FA rule - roles/services/tasks/directories.yml: remove syncthing/config and syncthing/data dirs - roles/services/defaults/main.yml: remove syncthing_image - roles/services/tasks/main.yml: remove syncthing image pull Security hardening: - inventory/group_vars/all/main.yml: move cloudflare_zone_id to vault - inventory/group_vars/all/vault.yml: add vault_cloudflare_zone_id .gitignore improvements: - add *.env, acme.json, *.log, editor dirs, venv, temp files Documentation (new): - docs/STATUS.md: all services, servers, known issues - docs/BACKLOG.md: prioritized task list, done/todo - docs/DECISIONS.md: architecture decisions and rationale - CLAUDE.md: rewritten with read-first docs, rules, full arch reference Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
4.9 KiB
Markdown
111 lines
4.9 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## ⚠️ ЧИТАЙ СНАЧАЛА
|
||
|
||
Перед любой работой прочитай эти файлы:
|
||
|
||
- **`docs/STATUS.md`** — текущее состояние всех сервисов, известные проблемы
|
||
- **`docs/BACKLOG.md`** — что нужно сделать (приоритеты), что уже сделано
|
||
- **`docs/DECISIONS.md`** — почему всё устроено именно так
|
||
|
||
После завершения работы **обнови** соответствующий документ.
|
||
|
||
---
|
||
|
||
## Правила работы
|
||
|
||
1. **Только через CI/CD** — никогда не фикси что-либо вручную на сервере. Внеси изменение, закоммить, запуши → CI/CD сам задеплоит. Потом проверь результат.
|
||
2. **Syncthing удалён** — не предлагай его вернуть, не упоминай как отсутствующий сервис.
|
||
3. **Секреты** — все в `inventory/group_vars/all/vault.yml` с префиксом `vault_`. В `main.yml` только алиасы `"{{ vault_* }}"`. Никаких plaintext секретов.
|
||
4. **Синтаксис-чек перед коммитом** — `ansible-playbook playbooks/deploy.yml --syntax-check`.
|
||
|
||
---
|
||
|
||
## Команды
|
||
|
||
```bash
|
||
# Prerequisites (один раз, на машине оператора)
|
||
ansible-galaxy collection install community.general community.docker ansible.posix
|
||
echo "yourpassword" > ~/.vault-password-file && chmod 600 ~/.vault-password-file
|
||
|
||
# Первичная настройка сервера (от root)
|
||
ansible-playbook playbooks/bootstrap.yml -u root
|
||
|
||
# Деплой основного сервера
|
||
ansible-playbook playbooks/deploy.yml
|
||
|
||
# Деплой tools-сервера
|
||
ansible-playbook playbooks/tools.yml
|
||
|
||
# Деплой всего сразу
|
||
ansible-playbook playbooks/site.yml
|
||
|
||
# Редактировать секреты
|
||
ansible-vault edit inventory/group_vars/all/vault.yml
|
||
|
||
# Проверка синтаксиса (без подключения к серверу)
|
||
ansible-playbook playbooks/deploy.yml --syntax-check
|
||
ansible-playbook playbooks/tools.yml --syntax-check
|
||
|
||
# Dry run
|
||
ansible-playbook playbooks/deploy.yml --check
|
||
|
||
# Только конкретная роль
|
||
ansible-playbook playbooks/deploy.yml --tags base
|
||
ansible-playbook playbooks/deploy.yml --tags docker
|
||
ansible-playbook playbooks/deploy.yml --tags services
|
||
ansible-playbook playbooks/deploy.yml --tags backup
|
||
```
|
||
|
||
---
|
||
|
||
## Архитектура
|
||
|
||
**Серверы:**
|
||
- `main` (87.249.49.32) — Traefik, Forgejo, Plane, Vaultwarden, Мониторинг, CI/CD runner
|
||
- `tools` (85.193.83.9) — Outline wiki, n8n, docker-mailserver, SnappyMail
|
||
|
||
**Трафик:** Internet → Cloudflare proxy → Traefik (80/443) → сервисы.
|
||
Порты 80/443 открыты только для IP-адресов Cloudflare (UFW whitelist).
|
||
|
||
**Секреты:** `inventory/group_vars/all/vault.yml` (Ansible Vault AES-256).
|
||
Пароль vault: `~/.vault-password-file` (в `.gitignore`, никогда не коммитить).
|
||
|
||
**TLS:** Wildcard сертификат `*.csrx.ru` через Cloudflare DNS-01 (Traefik certresolver).
|
||
|
||
**Роли:**
|
||
- `base` — UFW, fail2ban, sshd, deploy user
|
||
- `docker` — Docker CE + Compose plugin
|
||
- `services` — основной стек (templates → `/opt/services/`, docker compose up)
|
||
- `tools` — tools-стек (templates → `/opt/tools/`, docker compose up)
|
||
- `backup` — hourly backup script → S3 cold (`visual-backup/data/`)
|
||
|
||
**Шаблоны → файлы на сервере:**
|
||
- `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`
|
||
- `roles/services/templates/traefik/dynamic/routes.yml.j2` → `/opt/services/traefik/dynamic/routes.yml`
|
||
|
||
**Добавление нового сервиса на main:**
|
||
1. Добавить контейнер в `docker-compose.yml.j2` в сеть `backend`
|
||
2. Добавить роутер в `routes.yml.j2` (НЕ docker labels — используется file provider)
|
||
3. Добавить домен в `inventory/group_vars/all/main.yml`
|
||
4. Добавить DNS A-запись в Cloudflare
|
||
|
||
**Добавление сервиса на tools:**
|
||
1. Добавить контейнер в `roles/tools/templates/docker-compose.yml.j2`
|
||
2. Добавить роутер в `routes.yml.j2` с `url: "http://{{ ip_tools }}:PORT"`
|
||
3. Открыть порт в UFW (задача в `roles/tools/tasks/main.yml`)
|
||
|
||
---
|
||
|
||
## CI/CD
|
||
|
||
Push в `master` → Forgejo Actions запускает:
|
||
```
|
||
ansible-playbook playbooks/deploy.yml
|
||
ansible-playbook playbooks/tools.yml
|
||
```
|
||
Workflow: `.forgejo/workflows/deploy.yml`
|