# Personal Infrastructure

Репозиторий моей личной инфраструктуры: VPN, git-хостинг, автоматизация, реверс-прокси и всё, что будет добавляться дальше. Цель — держать в одном месте всё, что нужно, чтобы развернуть любой узел с нуля.

Принципы:

- **Docker — предпочтительный способ развёртывания.** Если можно завернуть в compose — заворачиваем.
- **Репозиторий — единственный источник правды.** На самих серверах ничего уникального жить не должно: все конфиги, compose-файлы, скрипты, артефакты, `.env` — в git. Сервер тянет нужную папку и поднимает её.
- **Секреты тоже в репо.** `.env` с паролями коммитим вместе с остальным (репо приватный). Приватные ключи (`ssh/tunnel_key` и т.п.) — туда же, как файлы рядом с compose.

## Структура репозитория

```
servers/
  inventory.yml          # источник правды о парке серверов
  <server-name>/         # одна папка на сервер, имя совпадает с inventory.servers[].name
    docker-compose.yml   # compose этого узла
    .env                 # переменные окружения узла (включая пароли)
    <service>/           # конфиги конкретных сервисов (xray, nginx, ...)
    ssh/                 # ключи и прочие чувствительные файлы
domains.yml              # источник правды о DNS-записях для всех доменов
CLAUDE.md                # этот файл — обзор и правила
README.md
```

`servers/inventory.yml` — реестр узлов: имена, адреса, роли, локации, ssh-настройки, список сервисов. Любые ответы про «какой сервер», «где что крутится», «какой у него IP» берём оттуда.

`domains.yml` — реестр DNS-записей. Для каждого домена перечислены все нужные записи (A, CNAME, TXT, MX и т.п.) с указанием либо узла из inventory (`server: <name>` — IP подтягивается), либо буквального значения (`value: ...`). Состояние DNS у регистратора должно совпадать с этим файлом.

Папка `servers/<name>/` содержит всё, что нужно для развёртывания этого узла. Имя папки = `name` в inventory.

## Где что прописывать при изменениях

**Добавили новый сервер:**
1. Запись в `servers/inventory.yml` (name, host, role, env, location, tags, services).
2. Папка `servers/<name>/` с `docker-compose.yml` и `.env`.
3. Если узлу нужен домен — добавить записи в `domains.yml` и прописать их у регистратора.
4. Если узел упоминается смысловой ролью (например, тут есть бэкенд для другого узла) — обновить соответствующие compose/конфиги, ссылаясь на роль, а не IP.

**Добавили сервис на существующий сервер:**
1. Сервис в `servers/<name>/docker-compose.yml`. Внешние — через traefik-метки (`traefik.http.routers.<name>.*`) с хостом из `.env`. Внутренние — только в сети `internal`.
2. Конфиги сервиса — в `servers/<name>/<service>/`, монтировать в контейнер read-only.
3. Новые переменные — в `.env` узла. В compose использовать `${VAR}`, не хардкодить.
4. Запись `services: [...]` у узла в `inventory.yml`.
5. Если сервис публикуется наружу — DNS-запись в `domains.yml` и у регистратора.

**Изменили IP / переехали:**
1. Только `inventory.yml` (поле `host`). Compose-файлы IP не содержат — там ссылки на сервисы по имени или на роли.
2. Проверить `domains.yml`: записи со ссылкой `server: <name>` подтянут новый IP автоматически — но у регистратора надо обновить вручную.

**Добавили / изменили домен:**
1. Запись в `domains.yml`: блок `domains` для домена, нужные `records`. Для записей, указывающих на наш узел — `server: <name>`, иначе `value: <строка>`.
2. Синхронизировать у регистратора. Состояние DNS должно совпадать с файлом.

**Добавили секрет:**
1. В `.env` узла либо как файл в `servers/<name>/ssh/` (или аналогичной служебной папке).
2. Никогда не хардкодить в compose или конфиг-файлах — только через `${VAR}` или монтируемый файл.

**Удалили сервис / сервер:**
1. Убрать запись из `inventory.yml` (или из `services` узла).
2. Удалить соответствующий блок из compose и папку с конфигами.

## Конвенции

- Адреса серверов — только в `inventory.yml`. В compose и доках ссылаемся на роли (`core`, `vpn-entry`, `reverse-proxy`, `vpn-exit` и т.п.).
- Сети compose: `proxy` для внешнего трафика через traefik, `internal` для межсервисной коммуникации и БД. Сервис в обеих сетях — только если ему правда нужен доступ и снаружи, и к внутренним зависимостям.
- Имя папки сервера = `name` в inventory, по роли, не по IP.
- Любой артефакт, без которого сервер не поднимется (compose, `.env`, конфиг, ключ) — лежит в `servers/<name>/` и коммитится в репо.
