From b532527f320cffb52d2f05ce5c9a0a28fa84e573 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 25 Feb 2026 21:01:06 +0300 Subject: [PATCH] some fix --- .gitignore | 4 + README.md | 2 +- docs/.DS_Store | Bin 0 -> 6148 bytes docs/architecture/architecture.md | 8 +- docs/backup/proxmox-phase1-backup.md | 6 +- docs/containers/container-100.md | 13 +- docs/containers/container-103.md | 61 ++++- docs/containers/container-109.md | 203 ++++++++++++++++ docs/network/network-topology.md | 80 ++++--- docs/network/vpn-mobileconfig-wireguard.md | 258 +++++++++++++++++++++ scripts/npm-add-proxy-vault.sh | 110 +++++++++ scripts/npm-fix-proxy-domain-names.sh | 16 ++ 12 files changed, 719 insertions(+), 42 deletions(-) create mode 100644 .gitignore create mode 100644 docs/.DS_Store create mode 100644 docs/containers/container-109.md create mode 100644 docs/network/vpn-mobileconfig-wireguard.md create mode 100644 scripts/npm-add-proxy-vault.sh create mode 100644 scripts/npm-fix-proxy-domain-names.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..080f619 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +# WireGuard mobileconfig contain private keys — do not commit +*.mobileconfig +docs/containers/wireguard-macos-ondemand.mobileconfig +docs/containers/wireguard-ios-ondemand.mobileconfig diff --git a/README.md b/README.md index 098e01e..da7b436 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ |----------|------------| | [Контейнер 100](docs/containers/container-100.md) | NPM, Homepage, AdGuard, Wallos, log-dashboard, vpn-route-check | | [Контейнер 101](docs/containers/container-101.md) | Nextcloud, PostgreSQL, Redis, хранилище «Игры» | -| [Контейнер 103](docs/containers/container-103.md) | Gitea, PostgreSQL, act_runner, CouchDB (Obsidian) | +| [Контейнер 103](docs/containers/container-103.md) | Gitea, PostgreSQL, act_runner, CouchDB (Obsidian), Vaultwarden | | [Контейнер 104](docs/containers/container-104.md) | Paperless-ngx, PostgreSQL, Redis | | [Контейнер 105](docs/containers/container-105.md) | RAG API (mini-lm), модели, векторы | | [Контейнер 107](docs/containers/container-107.md) | Invidious, Companion, PostgreSQL | diff --git a/docs/.DS_Store b/docs/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9fa7981c7c4d9dde063d02962d59202961b68017 GIT binary patch literal 6148 zcmeHK&2AGh5S~c`O;RA6Hh~s|6p;&3FGb>tx`ZN#5K2U~F`c98 z9Fcxm<|Jh-5>e&wAOH>wB8caDTZ3i5GVs4KAop$#d=Rv66F9Sf1Ajd1hN4Sb`%8Bi z263{r_04fGwUoYaaXFLCtz5c%CGQkg*9yf#sZ_dpZGGeVjg5}8*7f{@K_o`J_dtXq zs)i%>Vh{zr=Fsy4K4>NEZPE-*SjSoYt?M(^dwpu!Jswh@;;BKUdlWIoRla(^AG4%& zMsIhVeC$Ue3>zX2l0fkG%lM5rswM2O#`}Us90%;EK9sI_k3})zTukd#=yh3G=T(s; z;;`*Sk;ezDdfWhoLO10dD-b$1}p=A&wxB1%2Xt} z1}7TT(Lt5`eUSdNL@A`pw}iy9LD%3!BY8+rhZ5>gG*1lF;bbqHey+iZMjZ~QMy5Pw zWHc`nRHKu9pzg-~U#W2MNec%6z8@|C4R=o*}8BnyfC5l}SP$};dz8TbX3mz9J7 literal 0 HcmV?d00001 diff --git a/docs/architecture/architecture.md b/docs/architecture/architecture.md index 6f3a90e..823d101 100644 --- a/docs/architecture/architecture.md +++ b/docs/architecture/architecture.md @@ -29,6 +29,7 @@ | obsidian.katykhin.ru | — | | share.katykhin.ru | — | | video.katykhin.ru | Invidious | +| vault.katykhin.ru | Vaultwarden (менеджер паролей) | | wallos.katykhin.ru | Wallos | | _acme-challenge.call.katykhin.ru | Служебный (DNS-01 Let's Encrypt) | @@ -62,14 +63,15 @@ pct create 105 local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst \ |-----|-------------------------------|----------------|------------|---------------------| | 100 | NPM, Homepage, AdGuard, Wallos | 192.168.1.100 | 1 core, 2 GB | home.katykhin.ru, wallos.katykhin.ru, adguard.local. → [Контейнер 100 (подробно)](../containers/container-100.md) | | 101 | Nextcloud | 192.168.1.101 | 2 core, 3 GB | cloud.katykhin.ru. → [Контейнер 101 (подробно)](../containers/container-101.md) | -| 103 | Gitea, сервис Obsidian (5984) | 192.168.1.103 | 1 core, 2 GB | obsidian.katykhin.ru → [Контейнер 103 (подробно)](../containers/container-103.md) | +| 103 | Gitea, CouchDB (Obsidian), Vaultwarden | 192.168.1.103 | 1 core, 2 GB | obsidian.katykhin.ru, vault.katykhin.ru → [Контейнер 103 (подробно)](../containers/container-103.md) | | 104 | Paperless | 192.168.1.104 | 1 core, 2 GB | docs.katykhin.ru → [Контейнер 104 (подробно)](../containers/container-104.md) | | 105 | RAG-service | 192.168.1.105 | 1 core, 1 GB | mini-lm.katykhin.ru → [Контейнер 105 (подробно)](../containers/container-105.md) | | 107 | Invidious (misc) | 192.168.1.107 | 1 core, 2 GB | video.katykhin.ru → [Контейнер 107 (подробно)](../containers/container-107.md) | | 108 | Galene | 192.168.1.108 | 1 core, 256 MB | call.katykhin.ru → [Контейнер 108 (подробно)](../containers/container-108.md) | +| 109 | WireGuard VPN (local-vpn) | 192.168.1.109 | 1 core, 256 MB | Доступ по VPN (10.10.99.0/24); клиенты получают доступ к vault.katykhin.ru и LAN → [Контейнер 109 (подробно)](../containers/container-109.md) | | 200 | Immich, immich-pt и др. | 192.168.1.200 | 3 core, 10 GB | immich.katykhin.ru → [ВМ 200 (подробно)](../containers/container-200.md) | -*100–108 — LXC-контейнеры (pct), 200 — KVM-ВМ (qm).* Домены api, git, share и др. в NPM при необходимости добавить позже. +*100–109 — LXC-контейнеры (pct), 200 — KVM-ВМ (qm). Схема ID = последний октет IP соблюдена.* Домены api, git, share и др. в NPM при необходимости добавить позже. --- @@ -92,7 +94,7 @@ pct create 105 local:vztmpl/debian-12-standard_12.2-1_amd64.tar.zst \ ## Дополнительно - **Схема сети и зависимости:** полная топология (роутер, Proxmox, контейнеры, VPS), таблица IP/доменов, маршруты NPM, кто от кого зависит, единые точки отказа (SPOF). → [Схема сети и зависимости](../network/network-topology.md). -- **Homepage:** на контейнере 100, конфиг сервисов в `/opt/docker/homepage/config/services.yaml` (ссылки на NPM, Invidious, AdGuard, Immich, Galene и т.д.). +- **Homepage:** на контейнере 100, конфиг сервисов в `/opt/docker/homepage/config/services.yaml` (ссылки на NPM, Invidious, AdGuard, Immich, Galene, Vaultwarden и т.д.). - **VPN (VPS):** отдельный сервер 185.103.253.99, AmneziaWG для обхода блокировок. → [VPN-сервер (VPS, AmneziaWG)](../vps/vpn-vps-amneziawg.md). - **Роутер:** Netcraze Speedster, два WireGuard/AmneziaWG (Германия / США), маршрутизация части трафика через VPN. → [Роутер Netcraze Speedster](../network/router-netcraze-speedster.md). - **VPS Миран (СПБ):** боты (telegram-helper-bot, anonBot), prod-инфраструктура, STUN/TURN для Galene. → [VPS Миран: боты и STUN/TURN](../vps/vps-miran-bots.md). diff --git a/docs/backup/proxmox-phase1-backup.md b/docs/backup/proxmox-phase1-backup.md index 75202ec..986a229 100644 --- a/docs/backup/proxmox-phase1-backup.md +++ b/docs/backup/proxmox-phase1-backup.md @@ -225,7 +225,9 @@ tar -czf "$BACKUP_ROOT/etc-pve-$DATE.tar.gz" -C / etc/pve - [ ] Настроен бэкап `/etc/pve` (скрипт + cron) → `/mnt/backup/proxmox/etc-pve`. - [ ] Restic: cron на хосте, выгрузка нужных каталогов из `/mnt/backup` в Yandex S3, retention 7/4/6. - [ ] Yandex: ключи и endpoint зафиксированы, restic успешно пишет в бакет. -- [ ] Vaultwarden развёрнут (CT 107 или 103), секреты перенесены, бэкап данных Vaultwarden входит в restic. +- [x] Vaultwarden развёрнут (CT 103). +- [ ] Секреты перенесены в Vaultwarden. +- [ ] Бэкап данных Vaultwarden (`/opt/docker/vaultwarden/data`) включён в restic (Yandex S3). - [ ] Выполнено тестовое восстановление одного контейнера (другой VMID), проверена работоспособность. - [ ] В документации зафиксирована процедура полного восстановления Proxmox «с нуля». @@ -251,7 +253,7 @@ tar -czf "$BACKUP_ROOT/etc-pve-$DATE.tar.gz" -C / etc/pve | Где запускать бэкапы | Cron на хосте Proxmox: Backup Job (vzdump) + restic в Yandex. | | Retention локально | Только в Proxmox Job и в скрипте etc-pve; отдельного restic-репозитория локально не делаем. | | /etc/pve | Локально и в Yandex (через restic). | -| Пароли | Vaultwarden на CT 107 или 103. | +| Пароли | Vaultwarden на CT 103. | | Yandex | Бакет создан; ключи и endpoint зафиксировать при настройке restic. | | MinIO | Не используем; директории + restic (s3 для Yandex). | diff --git a/docs/containers/container-100.md b/docs/containers/container-100.md index 4217773..ce1a33a 100644 --- a/docs/containers/container-100.md +++ b/docs/containers/container-100.md @@ -106,7 +106,17 @@ docker restart adguard **Сеть:** proxy_network. **Основные файлы конфигурации:** -- `services.yaml` — список сервисов, виджеты (NPM, AdGuard, Proxmox и др.), ссылки, пинги. Пароли и токены виджетов хранятся здесь (не коммитить в открытый репозиторий). +- `services.yaml` — список сервисов, виджеты (NPM, AdGuard, Proxmox и др.), ссылки, пинги. Пароли и токены виджетов хранятся здесь (не коммитить в открытый репозиторий). В список сервисов добавлен **Vaultwarden** (менеджер паролей на контейнере 103): ссылка на `https://vault.katykhin.ru` (если в NPM настроен proxy) или на `http://192.168.1.103:8280` (доступ по LAN по IP). Пример записи в `services.yaml`: + + ```yaml + - Vaultwarden + description: Менеджер паролей (Bitwarden-совместимый) + icon: vaultwarden.png + href: https://vault.katykhin.ru + target: _blank + ``` + + (При использовании только LAN по IP укажите `href: http://192.168.1.103:8280`. Иконка: в [документации Homepage](https://gethomepage.dev/docs/services/) или локальный файл в `config/images/`.) - `docker.yaml` — подключение к Docker через dockerproxy (host/port). - `settings.yaml`, `widgets.yaml`, `bookmarks.yaml`, `custom.css`, `proxmox.yaml`, `kubernetes.yaml` при необходимости. @@ -254,5 +264,6 @@ docker logs vpn-route-check ## Связь с другими документами - [Архитектура и подключение](../architecture/architecture.md) — таблица контейнеров, домены, схема сети. +- [Контейнер 103 (Gitea, Vaultwarden)](container-103.md) — сервис Vaultwarden (менеджер паролей), добавляемый на дашборд Homepage. - [Выпуск сертификата Let's Encrypt (DNS-01)](../network/ssl-letsencrypt-dns01.md) — certbot, Beget API, интеграция с NPM. - [Роутер Netcraze Speedster](../network/router-netcraze-speedster.md) — VPN и telnet, используемые vpn-route-check. diff --git a/docs/containers/container-103.md b/docs/containers/container-103.md index 27b5b58..6c5a736 100644 --- a/docs/containers/container-103.md +++ b/docs/containers/container-103.md @@ -1,4 +1,4 @@ -# Контейнер 103 (Gitea): Gitea, PostgreSQL, act_runner, CouchDB (Obsidian) +# Контейнер 103 (Gitea): Gitea, PostgreSQL, act_runner, CouchDB (Obsidian), Vaultwarden Подробное описание LXC-контейнера **103** на Proxmox (192.168.1.103): Git-сервер Gitea с Actions (runner), база PostgreSQL, CouchDB для синхронизации Obsidian (домен obsidian.katykhin.ru). @@ -21,15 +21,17 @@ - **Debian (CT 103):** логин `root` (пароль — в менеджере паролей или как настраивал при установке). - **Gitea (веб):** http://192.168.1.103:3000 (или через NPM по домену git.katykhin.ru, если настроен). Учётные записи — пользователи Gitea. Репозитории могут иметь origin на Gitea; при необходимости пуш в GitHub — отдельный remote (например `github`), команда вида `git push github main`. - **CouchDB (Obsidian sync):** http://192.168.1.103:5984. Админ (пользователь **obsidian**) и пароль заданы в `/opt/docker/couchdb/local.d/local.ini` (секция `[admins]`); клиент Obsidian подключается по URL и своим учётным данным. + - **Vaultwarden (менеджер паролей):** http://192.168.1.103:8280 (только LAN, без домена). Админ-доступ по токену `ADMIN_TOKEN` из `/opt/docker/vaultwarden/.env` (файл только на сервере, не коммитить). --- ## Сервисы (Docker) -Два независимых набора сервисов: +Три набора сервисов: 1. **Gitea (compose)** — в `/opt/gitea/`: Gitea, PostgreSQL, act_runner. Сеть **gitea_default**. 2. **CouchDB** — запущен отдельным контейнером (без compose в репозитории), данные в `/opt/docker/couchdb/`. +3. **Vaultwarden (compose)** — в `/opt/docker/vaultwarden/`: менеджер паролей Vaultwarden (совместим с клиентами Bitwarden). | Контейнер | Образ | Порты (хост) | Назначение | |-----------------|--------------------------|------------------|------------| @@ -37,6 +39,7 @@ | gitea-db-1 | postgres:16-alpine | — | БД Gitea | | gitea-runner-1 | gitea/act_runner:latest | — | Gitea Actions (CI) | | couchdb | couchdb:3 | 5984 | Бэкенд синхронизации Obsidian (obsidian.katykhin.ru) | +| vaultwarden | vaultwarden/server:latest | 8280 | Менеджер паролей Vaultwarden (Bitwarden-совместимый), доступ из LAN | --- @@ -131,6 +134,59 @@ curl -s http://192.168.1.103:5984/ --- +## 5. Vaultwarden (менеджер паролей) + +**Назначение:** self-hosted менеджер паролей (совместим с официальными клиентами Bitwarden) для хранения всех кредов (Proxmox, контейнеры, БД, API-ключи и т.д.). + +**Каталог:** `/opt/docker/vaultwarden/` +**Compose:** `docker-compose.yml`. Запуск/обновление: + +```bash +cd /opt/docker/vaultwarden +docker compose pull +docker compose up -d +``` + +**Образ:** `vaultwarden/server:latest`. + +**Порты:** +- 8280 (хост) → 80 (контейнер). + +**Доступ в локальной сети:** с любого устройства в LAN (192.168.1.x) Vaultwarden уже доступен по адресу **`http://192.168.1.103:8280`** — дополнительная настройка не нужна. Клиенты Bitwarden на домашних устройствах можно настроить на этот URL. + +**Доступ по домену (опционально):** если нужен **https://vault.katykhin.ru** и из LAN, и по VPN, в NPM (контейнер 100) настраивают: +- **Proxy Host:** `vault.katykhin.ru` → upstream `192.168.1.103:8280`, включить SSL (Let's Encrypt или custom). +- **Access List:** создать список, разрешающий только подсети **192.168.1.0/24** (LAN) и **10.10.99.0/24** (WireGuard VPN); для всех остальных — отказ. Эту access list привязать к proxy host `vault.katykhin.ru`. Тогда с интернета без VPN доступ к домену будет закрыт; из дома и по VPN — открыт. +- В compose Vaultwarden при использовании домена задать `DOMAIN=https://vault.katykhin.ru` и перезапустить контейнер. + +**Тома:** +- `/opt/docker/vaultwarden/data` → `/data` (все данные Vaultwarden: база, вложения, и т.п.). + +**Переменные окружения (compose):** +- `WEBSOCKET_ENABLED=true` — включает поддержку веб-сокетов. +- `SIGNUPS_ALLOWED=false` — запрещает свободную регистрацию; пользователей создаёт админ. +- `INVITATIONS_ALLOWED=true` — разрешает приглашения. +- `DOMAIN=http://192.168.1.103:8280` — базовый URL (для LAN; при выдаче наружу поменять на `https://<домен>`). +- `ROCKET_PORT=80`, `ROCKET_ADDRESS=0.0.0.0` — HTTP-сервер внутри контейнера. +- `TZ=Europe/Moscow` — часовой пояс. + +**Файл `.env` (секреты):** + +- Путь: `/opt/docker/vaultwarden/.env`. +- В нём как минимум задаётся `ADMIN_TOKEN=<случайный токен>` для доступа к админке. +- Файл создаётся на хосте (права `600`), **не коммитить** в репозиторий и не копировать в открытые места. + +**Проверка работы:** + +```bash +docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}' | grep vaultwarden +curl -s http://127.0.0.1:8280/ | head -c 200 +``` + +После этого интерфейс открывается по **`http://192.168.1.103:8280`** из домашней сети. Клиенты Bitwarden (ПК, телефон в LAN) настраивают на этот URL — сервис уже открыт в локальной сети без NPM. Если позже добавить домен в NPM (см. выше), в клиентах можно перейти на `https://vault.katykhin.ru`. + +--- + ## Порты (сводка на хосте) | Порт | Сервис / примечание | @@ -138,6 +194,7 @@ curl -s http://192.168.1.103:5984/ | 3000 | Gitea (веб) | | 2222 | Gitea (SSH для git) | | 5984 | CouchDB (Obsidian sync) | +| 8280 | Vaultwarden (менеджер паролей, HTTP по IP из LAN) | --- diff --git a/docs/containers/container-109.md b/docs/containers/container-109.md new file mode 100644 index 0000000..6fe4466 --- /dev/null +++ b/docs/containers/container-109.md @@ -0,0 +1,203 @@ +# Контейнер 109 (local-vpn): локальный WireGuard VPN + +Подробное описание LXC-контейнера **109** на Proxmox (192.168.1.109): локальный VPN-сервер на WireGuard для доступа к внутренней сети и сервисам (в т.ч. Vaultwarden) только через зашифрованный туннель. + +--- + +## Общие сведения + +- **Хостнейм:** local-vpn +- **ID:** 109 +- **IP:** 192.168.1.109/24 +- **ОС:** Debian 12 (bookworm) +- **Ресурсы:** 1 core, 256 MB RAM, 1 GB диск на `local-lvm` +- **Доступ:** с Proxmox — `ssh root@192.168.1.150` → `pct exec 109 -- bash`. + +Назначение контейнера — поднимать локальный WireGuard, через который: + +- клиенты (iOS/macOS) получают доступ к сети `192.168.1.0/24` (LAN), +- DNS внутри VPN идёт через AdGuard на CT 100 (`192.168.1.100`), +- доступ к Vaultwarden (`vault.katykhin.ru` → NPM → 192.168.1.103:8280) можно ограничить **только через этот VPN** (ограничение на уровне NPM/фаервола, см. соответствующую документацию). + +--- + +## Создание контейнера + +Контейнер создан на Proxmox командой вида (выполнено на хосте 192.168.1.150): + +```bash +pct create 109 local:vztmpl/debian-12-standard_12.12-1_amd64.tar.zst \ + --hostname local-vpn \ + --cores 1 \ + --memory 256 \ + --rootfs local-lvm:1 \ + --net0 name=eth0,bridge=vmbr0,ip=192.168.1.109/24,gw=192.168.1.1,firewall=1 \ + --features keyctl=1,nesting=1 + +pct start 109 +``` + +--- + +## WireGuard (wg0) внутри контейнера + +### Пакеты и подготовка + +Внутри CT 109: + +```bash +apt-get update +apt-get install -y wireguard-tools iptables + +echo 'net.ipv4.ip_forward=1' > /etc/sysctl.d/99-wg-forward.conf +sysctl -p /etc/sysctl.d/99-wg-forward.conf +``` + +### Ключи и конфиг + +Ключи сервера и клиентов лежат в `/etc/wireguard/` (файлы `server.key/.pub`, `ios.key/.pub`, `macos.key/.pub`). +Основной конфиг интерфейса — `/etc/wireguard/wg0.conf`: + +```ini +[Interface] +Address = 10.10.99.1/24 +ListenPort = 43123 +PrivateKey = + +# Включение форвардинга LAN <-> VPN с NAT +PostUp = iptables -A FORWARD -i wg0 -o eth0 -s 10.10.99.0/24 -d 192.168.1.0/24 -j ACCEPT; \ + iptables -A FORWARD -i eth0 -o wg0 -d 10.10.99.0/24 -m state --state ESTABLISHED,RELATED -j ACCEPT; \ + iptables -t nat -A POSTROUTING -s 10.10.99.0/24 -o eth0 -j MASQUERADE +PostDown = iptables -D FORWARD -i wg0 -o eth0 -s 10.10.99.0/24 -d 192.168.1.0/24 -j ACCEPT; \ + iptables -D FORWARD -i eth0 -o wg0 -d 10.10.99.0/24 -m state --state ESTABLISHED,RELATED -j ACCEPT; \ + iptables -t nat -D POSTROUTING -s 10.10.99.0/24 -o eth0 -j MASQUERADE + +[Peer] +# iOS +PublicKey = +AllowedIPs = 10.10.99.2/32 + +[Peer] +# macOS +PublicKey = +AllowedIPs = 10.10.99.3/32 +``` + +- **Серверный адрес:** `10.10.99.1/24` (подсеть VPN). +- **Порт WireGuard:** `43123/UDP`. +- **NAT:** MASQUERADE на выход в `192.168.1.0/24`, чтобы не настраивать статические маршруты на роутере. + +### Запуск и автозапуск + +```bash +wg-quick up wg0 # ручной запуск +wg show # проверить состояние + +systemctl enable wg-quick@wg0 # автозапуск при старте CT +systemctl start wg-quick@wg0 +``` + +Проверка интерфейса: + +```bash +ip a show wg0 +``` + +Ожидаемый адрес: `10.10.99.1/24`. + +--- + +## Конфиги клиентов (split-tunnel + DNS через AdGuard) + +Клиентские конфиги удобно хранить в `/etc/wireguard/clients/` внутри CT (и оттуда забирать на устройства). + +### Базовые параметры для всех клиентов + +- **Адрес клиента в VPN:** `10.10.99.X/32` (уникальный для каждого устройства). +- **DNS:** `192.168.1.100` (AdGuard на CT 100). +- **Endpoint сервера:** `185.35.193.144:43123` (внешний IP + порт, проброшенный на CT 109). +- **Split tunnel:** + - `AllowedIPs = 10.10.99.0/24, 192.168.1.0/24` + → через VPN идут только: + - сама VPN-подсеть `10.10.99.0/24`, + - внутренняя сеть `192.168.1.0/24` (все домашние сервисы, в т.ч. NPM и Vaultwarden). + Весь остальной интернет идёт **напрямую** у клиента. + +Пример для iOS: + +```ini +[Interface] +Address = 10.10.99.2/32 +PrivateKey = +DNS = 192.168.1.100 + +[Peer] +PublicKey = +Endpoint = 185.35.193.144:43123 +AllowedIPs = 10.10.99.0/24, 192.168.1.0/24 +PersistentKeepalive = 25 +``` + +Пример для macOS: + +```ini +[Interface] +Address = 10.10.99.3/32 +PrivateKey = +DNS = 192.168.1.100 + +[Peer] +PublicKey = +Endpoint = 185.35.193.144:43123 +AllowedIPs = 10.10.99.0/24, 192.168.1.0/24 +PersistentKeepalive = 25 +``` + +> **Важно:** реальные ключи (`PrivateKey`, `PublicKey`) хранятся только в контейнере (`/etc/wireguard/*.key/.pub`) и **не попадают** в этот репозиторий. В примерах выше использовать плейсхолдеры и заменять их актуальными значениями при выдаче конфигов на устройства. + +--- + +## Firewall и ограничения доступа к Vaultwarden (общая схема) + +Идея ограничения доступа: + +- **На роутере (192.168.1.1):** + - открыть только UDP-порт `43123`, + - пробросить его на `192.168.1.109:43123` (CT 109), + - остальные порты для CT 109 снаружи не открывать. + +- **На Proxmox firewall (уровень ноды / CT 109):** + - разрешить входящий `UDP 43123` к CT 109, + - разрешить ESTABLISHED/RELATED, + - разрешить исходящий трафик из CT 109 в LAN (`192.168.1.0/24`) и к нужным внешним DNS (если потребуется). + +- **На уровне NPM (CT 100) / Vaultwarden (CT 103):** + - создать proxy host `vault.katykhin.ru` → upstream `192.168.1.103:8280`, + - ограничить доступ к этому хосту **только из VPN** — либо по исходному адресу (подсеть WireGuard `10.10.99.0/24`, если используется маршрутизация без NAT), либо по IP сервера VPN (`192.168.1.109`, если используется NAT в CT 109), + - отключить доступ к Vaultwarden из LAN напрямую по домену (и при желании по IP). + +Точная реализация правил на роутере и в NPM описывается в соответствующих документах (`router-netcraze-speedster`, `container-100` / NPM); здесь зафиксирована лишь роль контейнера 109 и параметры WireGuard. + +--- + +## On-Demand для iOS/macOS + +Для автоматического включения VPN **вне домашнего Wi‑Fi** используется профиль `.mobileconfig` с правилами On-Demand. Подробно: [Генерация .mobileconfig для WireGuard VPN (On-Demand)](../network/vpn-mobileconfig-wireguard.md). + +- если подключен Wi‑Fi с SSID из списка (например `HomeWiFi`) → VPN **отключён**; +- во всех остальных случаях (другой Wi‑Fi, сотовые данные) → VPN **включается автоматически**. + +**macOS:** профиль `wireguard-macos-ondemand.mobileconfig`. Перед установкой замени `HomeWiFi` на реальный SSID домашней сети (секция `OnDemandRules` → `SSIDMatch`). Установка: двойной клик по файлу → «Системные настройки» → «Профили» → установить. Туннель появится в приложении WireGuard. + +**iOS:** профиль `wireguard-ios-ondemand.mobileconfig`. То же правило: замени `HomeWiFi` на SSID домашней сети. Установка: отправить файл на iPhone (AirDrop, почта, файлы) → открыть → «Установить» в предложенном профиле → при необходимости «Настройки» → «Основные» → «VPN и управление устройством» → установить профиль. Туннель «Local VPN (WireGuard)» появится в приложении WireGuard; включи один раз вручную, далее On-Demand будет управлять подключением. + +Оба файла содержат приватные ключи и добавлены в `.gitignore` — в репозиторий не коммитить. + +--- + +## Связь с другими документами + +- [Архитектура и подключение](../architecture/architecture.md) — общее описание хостов, IP, доменов (контейнер 109 нужно добавить как исключение ID ↔ IP при необходимости). +- [Контейнер 100 (NPM)](container-100.md) — настройка proxy host `vault.katykhin.ru` и ограничение доступа только через VPN. +- [Контейнер 103 (Vaultwarden)](container-103.md) — сам сервис Vaultwarden и доступ по `192.168.1.103:8280` из LAN/VPN. +- [Роутер Netcraze Speedster](../network/router-netcraze-speedster.md) — проброс UDP 43123 и общие правила фаервола/маршрутизации. diff --git a/docs/network/network-topology.md b/docs/network/network-topology.md index 9624c33..0f4e946 100644 --- a/docs/network/network-topology.md +++ b/docs/network/network-topology.md @@ -11,37 +11,38 @@ ```mermaid flowchart TB subgraph External["Внешний мир"] - DNS["DNS (Beget)\n*.katykhin.ru → IP"] + DNS["DNS (Beget)
*.katykhin.ru → IP"] end subgraph Edge["Граница сети"] - Router["Роутер\n192.168.1.1\nпроброс 80/443 → .100"] + Router["Роутер
192.168.1.1
проброс 80/443 → .100"] end subgraph Gateway["Единая точка входа"] - NPM["NPM\nCT 100\nтерминация SSL, маршрут по Host"] + NPM["NPM
CT 100
терминация SSL, маршрут по Host"] end subgraph Backends["Сервисы"] - S101["Nextcloud\nCT 101"] - S103["Gitea / CouchDB\nCT 103"] - S104["Paperless\nCT 104"] - S105["RAG API\nCT 105"] - S107["Invidious\nCT 107"] - S108["Galene\nCT 108"] - S200["Immich\nVM 200"] + S101["Nextcloud
CT 101"] + S103["Gitea / CouchDB / Vaultwarden
CT 103"] + S104["Paperless
CT 104"] + S105["RAG API
CT 105"] + S107["Invidious
CT 107"] + S108["Galene
CT 108"] + S109["WireGuard VPN
CT 109
10.10.99.0/24"] + S200["Immich
VM 200"] end subgraph Data["Данные"] - D101["PostgreSQL\nRedis\nCT 101"] - D103["PostgreSQL\nCT 103"] - D104["PostgreSQL\nRedis\nCT 104"] - D107["PostgreSQL\nCT 107"] - D200["PostgreSQL\nRedis\nVM 200"] + D101["PostgreSQL
Redis
CT 101"] + D103["PostgreSQL
CT 103"] + D104["PostgreSQL
Redis
CT 104"] + D107["PostgreSQL
CT 107"] + D200["PostgreSQL
Redis
VM 200"] end subgraph External2["Внешние зависимости"] - coTURN["coTURN\nVPS Миран 185.147.80.190"] + coTURN["coTURN
VPS Миран 185.147.80.190"] end DNS --> Router @@ -53,6 +54,8 @@ flowchart TB NPM --> S107 NPM --> S108 NPM --> S200 + Router --> S109 + S109 -.->|"клиенты VPN
доступ к vault, LAN"| NPM S101 --> D101 S103 --> D103 @@ -87,6 +90,7 @@ flowchart TB - **Galene (108)** дополнительно зависит от **coTURN (VPS Миран)** для STUN/TURN — на графе это отдельная зависимость от внешнего узла. - **RAG (105)** без внешней БД в стеке — только NPM → Service. - **AdGuard, Homepage, Wallos** живут на том же хосте, что и NPM (CT 100), но логически стоят «рядом» с NPM (доступ к ним тоже через роутер и при необходимости через NPM). +- **Vaultwarden (vault.katykhin.ru):** доступ только из LAN (192.168.1.0/24) и из VPN (10.10.99.0/24). Публичный доступ из интернета закрыт; удалённо — только через WireGuard (CT 109). NPM Access List ограничивает приём по подсетям. --- @@ -102,22 +106,23 @@ flowchart TB │ VPN: AmneziaWG DE / US │ └───────────────┬───────────────┘ │ - ┌────────────────────┼────────────────────┐ - │ │ │ - ▼ ▼ ▼ - ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐ - │ Proxmox │ │ CT 100 │ │ Остальные CT/VM │ - │ 192.168.1.150│ │ 192.168.1.100 │ │ .101 .103 .104 │ - │ (гипервизор) │ │ NPM, AdGuard, │ │ .105 .107 .108 │ - │ │ │ Homepage, │ │ VM 200 .200 │ - │ pct / qm │ │ Wallos, etc. │ │ (бэкенды) │ - └──────────────┘ └───────┬────────┘ └────────┬────────┘ - │ │ │ - │ │ HTTPS по Host │ - │ └──────────────────────┘ - │ (NPM проксирует на бэкенды) - │ + ┌────────────────────┼────────────────────┬────────────────┐ + │ │ │ │ + ▼ ▼ ▼ ▼ + ┌──────────────┐ ┌────────────────┐ ┌─────────────────┐ ┌─────────────────┐ + │ Proxmox │ │ CT 100 │ │ Остальные CT/VM │ │ CT 109 │ + │ 192.168.1.150│ │ 192.168.1.100 │ │ .101 .103 .104 │ │ 192.168.1.109 │ + │ (гипервизор) │ │ NPM, AdGuard, │ │ .105 .107 .108 │ │ WireGuard VPN │ + │ │ │ Homepage, │ │ VM 200 .200 │ │ UDP 43123 │ + │ pct / qm │ │ Wallos, etc. │ │ (бэкенды) │ │ 10.10.99.0/24 │ + └──────────────┘ └───────┬────────┘ └────────┬────────┘ └────────┬────────┘ + │ │ │ │ + │ │ HTTPS по Host │ │ клиенты VPN + │ └──────────────────────┘ │ → vault, LAN + │ (NPM проксирует на бэкенды) │ + │ │ │ Туннели VPN (роутер ↔ VPS) + │ + входящий WireGuard на CT 109 (проброс UDP 43123) │ ├──────────────────────────────────────────────────┐ │ │ @@ -130,6 +135,8 @@ flowchart TB └──────────────────┘ └──────────────────┘ └──────────────────────┘ ``` +**Доступ к vault.katykhin.ru:** из LAN (192.168.1.0/24) или через WireGuard (CT 109): клиент подключается к 192.168.1.109:43123, получает IP из 10.10.99.0/24, после чего запросы к vault.katykhin.ru идут через NPM (Access List разрешает обе подсети). + **Поток публичного трафика:** Запрос из интернета (например `https://video.katykhin.ru`) → роутер (185.35.193.144:443) → проброс на 192.168.1.100:443 → NPM (контейнер 100) → по Host выбирается proxy host → запрос на бэкенд (например 192.168.1.107:3000 для Invidious). Ответ идёт обратно по той же цепочке. @@ -143,11 +150,12 @@ flowchart TB | **Proxmox** | 192.168.1.150 | Гипервизор (LXC + KVM) | Управление: `pct`, `qm` | | **CT 100** | 192.168.1.100 | NPM, Homepage, AdGuard, Wallos, log-dashboard, vpn-route-check | home.katykhin.ru, wallos.katykhin.ru, adguard.local; приём 80/443 | | **CT 101** | 192.168.1.101 | Nextcloud, PostgreSQL, Redis | cloud.katykhin.ru | -| **CT 103** | 192.168.1.103 | Gitea, PostgreSQL, act_runner, CouchDB (Obsidian) | git.katykhin.ru, obsidian.katykhin.ru | +| **CT 103** | 192.168.1.103 | Gitea, PostgreSQL, act_runner, CouchDB (Obsidian), Vaultwarden | git.katykhin.ru, obsidian.katykhin.ru, vault.katykhin.ru (LAN + VPN) | | **CT 104** | 192.168.1.104 | Paperless-ngx, PostgreSQL, Redis | docs.katykhin.ru | | **CT 105** | 192.168.1.105 | RAG API (mini-lm) | mini-lm.katykhin.ru | | **CT 107** | 192.168.1.107 | Invidious, Companion, PostgreSQL | video.katykhin.ru | | **CT 108** | 192.168.1.108 | Galene (видеозвонки) | call.katykhin.ru | +| **CT 109** | 192.168.1.109 | WireGuard VPN (local-vpn), UDP 43123 | Клиенты 10.10.99.0/24; доступ к vault, LAN, AdGuard DNS | | **VM 200** | 192.168.1.200 | Immich, PostgreSQL, Redis, ML, deduper, Power Tools, Public Share | immich.katykhin.ru, immich-pt.katykhin.ru, share.katykhin.ru | | **VPS DE** | 185.103.253.99 | AmneziaWG (обход блокировок) | Туннель с роутера (10.8.1.x) | | **VPS US** | 147.45.124.117 | AmneziaWG (второй выход) | Туннель с роутера | @@ -175,6 +183,7 @@ flowchart TB | mini-lm.katykhin.ru | 192.168.1.105:8000 | CT 105 | | git.katykhin.ru | 192.168.1.103:3000 | CT 103 | | obsidian.katykhin.ru | 192.168.1.103:5984 | CT 103 | +| vault.katykhin.ru | 192.168.1.103:8280 | CT 103 (Vaultwarden; доступ по Access List: LAN + VPN) | (Точный список proxy host — в NPM на CT 100; при добавлении доменов таблицу обновлять.) @@ -191,6 +200,7 @@ flowchart TB 4. **DNS (Beget)** — без записей *.katykhin.ru запросы не дойдут до твоего IP. - **Каждый бэкенд** (101, 103, 104, 105, 107, 108, 200) при доступе снаружи зависит от NPM и роутера; при доступе только из LAN может работать и без NPM (по IP и порту). +- **Vaultwarden (vault.katykhin.ru):** публичный доступ из интернета закрыт; разрешены только LAN (192.168.1.0/24) и клиенты WireGuard VPN (10.10.99.0/24). Удалённый доступ к vault — только через CT 109 (WireGuard). ### Внутри хостов @@ -201,6 +211,7 @@ flowchart TB - **Контейнеры 101, 103, 104, 107, 200:** каждый свой стек: приложение зависит от своей БД (PostgreSQL) и при необходимости от Redis. Порядок запуска: сначала БД/Redis, потом приложение (обычно задано в docker-compose через depends_on). - **Контейнер 105 (RAG):** один контейнер, без внешней БД в стеке. - **Контейнер 108 (Galene):** не зависит от других контейнеров в LAN; зависит от **внешнего coTURN** (VPS Миран 185.147.80.190) для STUN/TURN — без него видеозвонки могут не устанавливаться за строгим NAT/фаерволом. +- **Контейнер 109 (WireGuard VPN):** самостоятельный; от него зависят удалённые пользователи (доступ к vault.katykhin.ru и LAN через NPM после подключения к VPN). DNS для клиентов — AdGuard (CT 100). - **Immich (200):** зависит от PostgreSQL, Redis, при необходимости от immich-deduper (сеть и БД). ML-контейнер опционально (GPU). ### Внешние сервисы @@ -217,10 +228,11 @@ flowchart TB | **Роутер** | Весь доступ из интернета к домашней сети (в т.ч. все домены). Нет VPN-выхода, если туннели подняты на роутере. | Резервный роутер / запасной канал; доступ к управлению из LAN. | | **Proxmox (192.168.1.150)** | Все контейнеры и ВМ недоступны (они на нём запущены). | Резервное питание, мониторинг, бэкапы конфигов и данных. | | **Контейнер 100 (NPM)** | Публичный HTTPS ко всем сервисам: без NPM нет терминации SSL и маршрутизации. Сервисы по IP:порт из LAN могут быть доступны, если порты не закрыты. | Мониторинг NPM и Docker на 100; быстрый перезапуск; бэкап конфигов NPM. | +| **Контейнер 109 (WireGuard)** | Нет удалённого доступа по VPN к vault.katykhin.ru и к внутренним сервисам извне LAN. | Мониторинг сервиса wg-quick@wg0; проброс UDP 43123 на роутере; бэкап /etc/wireguard. | | **Certbot / Beget API** | Истечение сертификатов → браузеры начнут ругаться. Продление через DNS-01 зависит от Beget. | Следить за продлением (таймер certbot); иметь запасной способ выпуска (другой DNS или ручной сертификат). | | **DNS (Beget)** | Смена IP или потеря записей — домены перестанут вести на твой хост. | Ведение записей вручную/через API; при смене IP обновить A-записи. | | **VPS Миран (coTURN)** | Galene: проблемы с установкой видеозвонов за NAT. Остальные сервисы не зависят. | Локальный coTURN на 108 или другом хосте как запасной вариант. | -| **Конкретный бэкенд (101, 103, …)** | Падает только свой сервис (Nextcloud, Gitea, Invidious и т.д.). Остальные работают. | Зависимости внутри стека (БД первым) и мониторинг каждого хоста. | +| **Конкретный бэкенд (101, 103, …)** | Падает только свой сервис (Nextcloud, Gitea, Vaultwarden, Invidious и т.д.). Остальные работают. | Зависимости внутри стека (БД первым) и мониторинг каждого хоста. | --- @@ -228,6 +240,8 @@ flowchart TB - [Архитектура и подключение](../architecture/architecture.md) — общее описание, таблица контейнеров, поток запросов. - [Контейнер 100](../containers/container-100.md) — NPM, AdGuard, Homepage, порядок запуска. +- [Контейнер 109](../containers/container-109.md) — WireGuard VPN (local-vpn), доступ к vault и LAN. +- [Генерация .mobileconfig для WireGuard (On-Demand)](vpn-mobileconfig-wireguard.md) — как собрать профиль для iOS/macOS с автоматическим подключением вне дома. - [Роутер Netcraze Speedster](router-netcraze-speedster.md) — проброс портов, VPN. - [VPN-сервер (VPS, AmneziaWG)](../vps/vpn-vps-amneziawg.md) — туннели с роутера. - [VPS Миран: боты и STUN/TURN](../vps/vps-miran-bots.md) — coTURN для Galene. diff --git a/docs/network/vpn-mobileconfig-wireguard.md b/docs/network/vpn-mobileconfig-wireguard.md new file mode 100644 index 0000000..f4b0f49 --- /dev/null +++ b/docs/network/vpn-mobileconfig-wireguard.md @@ -0,0 +1,258 @@ +# Генерация .mobileconfig для WireGuard VPN (On-Demand) + +Как собрать Apple-профиль конфигурации (`.mobileconfig`) для WireGuard с правилами **On-Demand**: автоматическое подключение VPN вне домашней сети и отключение на домашнем Wi‑Fi. + +--- + +## Зачем нужен .mobileconfig + +- **Обычный конфиг WireGuard** — пользователь сам включает/выключает туннель. +- **Профиль .mobileconfig** — ставится в «Настройки» → «Профили» (macOS) или «Основные» → «VPN и управление устройством» (iOS). Туннель появляется в приложении WireGuard и может управляться **On-Demand**: система сама поднимает VPN, когда устройство не в доверенной сети (например не дома), и отключает на домашнем Wi‑Fi. + +В итоге: за пределами дома — всегда VPN, дома — без VPN, без ручного переключения. + +--- + +## Что должно быть готово на сервере + +- WireGuard поднят (например на [контейнере 109](../containers/container-109.md)). +- Для каждого клиента (macOS, iOS и т.д.): + - своя пара ключей (приватный + публичный); + - в `wg0.conf` на сервере добавлен `[Peer]` с `PublicKey` и `AllowedIPs` (один адрес из подсети VPN, например `10.10.99.2/32` для iOS, `10.10.99.3/32` для macOS). +- Внешний IP и порт сервера (например `185.35.193.144:43123`), проброс UDP на роутере на CT 109. + +Подсеть VPN в примерах: `10.10.99.0/24`; DNS в туннеле — AdGuard на `192.168.1.100`. + +--- + +## Структура профиля + +Файл `.mobileconfig` — это **XML plist** (Property List) с корневым словарём: + +| Ключ | Назначение | +|------|------------| +| `PayloadContent` | Массив payload’ов (в нашем случае один — VPN). | +| `PayloadDisplayName` | Название профиля в списке профилей. | +| `PayloadIdentifier` | Уникальный идентификатор (например `ru.katykhin.wireguard.local-vpn`). | +| `PayloadType` | `Configuration`. | +| `PayloadUUID` | Уникальный UUID профиля. | +| `PayloadVersion` | 1. | + +Внутри `PayloadContent` — один элемент типа **VPN**: + +| Ключ | Назначение | +|------|------------| +| `PayloadType` | `com.apple.vpn.managed` | +| `VPNSubType` | **macOS:** `com.wireguard.macos` — **iOS:** `com.wireguard.ios` | +| `UserDefinedName` | Имя туннеля в приложении WireGuard (например «Local VPN (WireGuard)»). | +| `VendorConfig` → `WgQuickConfig` | Строка с конфигом WireGuard в формате INI (как в обычном конфиге). | +| `VPN` → `RemoteAddress` | Адрес сервера (хост:порт). | +| `OnDemandEnabled` | `1` — включить On-Demand. | +| `OnDemandRules` | Массив правил: когда отключать VPN (например на домашнем Wi‑Fi) и когда подключать. | + +--- + +## Конфиг WireGuard внутри профиля (WgQuickConfig) + +В `WgQuickConfig` вставляется **ровно тот же текст**, что и в обычном клиентском конфиге WireGuard, например: + +```ini +[Interface] +Address = 10.10.99.3/32 +PrivateKey = <приватный-ключ-этого-клиента> +DNS = 192.168.1.100 + +[Peer] +PublicKey = <публичный-ключ-сервера> +Endpoint = 185.35.193.144:43123 +AllowedIPs = 10.10.99.0/24, 192.168.1.0/24 +PersistentKeepalive = 25 +``` + +- `Address` — один адрес из подсети VPN, уникальный для каждого устройства (в `wg0.conf` на сервере в `AllowedIPs` для этого peer должен быть этот же `/32`). +- `PrivateKey` — приватный ключ **клиента** (генерируется один раз и хранится только на устройстве / в профиле). +- `PublicKey` — публичный ключ **сервера** (из `/etc/wireguard/server.pub` на сервере). +- `Endpoint` — внешний IP или домен и порт WireGuard (проброс на роутере). +- `AllowedIPs` — какие сети пускать через VPN (подсеть VPN + LAN, если нужен доступ в домашнюю сеть). +- `PersistentKeepalive` — полезно для мобильных и NAT. + +Ключи в профиле — **секретные**; не коммитить `.mobileconfig` с реальными ключами в репозиторий (добавить в `.gitignore`). + +--- + +## Правила On-Demand (OnDemandRules) + +Массив словарей. Порядок важен: первое сработавшее правило применяется. + +1. **Отключить VPN на домашнем Wi‑Fi** — правило с `Action = Disconnect` и условием по Wi‑Fi: + - `InterfaceTypeMatch` = `WiFi`; + - `SSIDMatch` = массив SSID (например `["HomeWiFi"]` или `["Netcraze-1882"]`). + - Итог: если устройство в Wi‑Fi с этим SSID → VPN отключается. + +2. **Во всех остальных случаях — подключать** — правило без условий: + - `Action` = `Connect`. + - Итог: любой другой сеть (другой Wi‑Fi, сотовые данные) → VPN включается. + +Пример в plist: + +```xml +OnDemandRules + + + Action + Disconnect + InterfaceTypeMatch + WiFi + SSIDMatch + + HomeWiFi + + + + Action + Connect + + +``` + +Перед установкой профиля **замени** `HomeWiFi` на реальный SSID своей домашней сети. + +--- + +## Различия macOS и iOS + +- **VPNSubType:** + - macOS: `com.wireguard.macos` + - iOS: `com.wireguard.ios` +- Остальная структура (WgQuickConfig, OnDemandRules, SSIDMatch) — одинаковая. Обычно делают два файла: `wireguard-macos-ondemand.mobileconfig` и `wireguard-ios-ondemand.mobileconfig`, в каждом свой клиентский ключ и свой `Address` (например `.2/32` для iOS, `.3/32` для macOS), если на сервере заведены два разных peer’а. + +--- + +## Шаблон plist (минимум для одного туннеля) + +Ниже — скелет без подстановки ключей; в `WgQuickConfig` и в `SSIDMatch` нужно подставить свои значения. + +```xml + + + + + PayloadContent + + + PayloadDisplayName + VPN + PayloadType + com.apple.vpn.managed + PayloadVersion + 1 + PayloadIdentifier + ru.katykhin.wireguard.local-vpn.tunnel + PayloadUUID + A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D + UserDefinedName + Local VPN (WireGuard) + VPNType + VPN + VPNSubType + com.wireguard.macos + VendorConfig + + WgQuickConfig + [Interface] +Address = 10.10.99.3/32 +PrivateKey = ВСТАВЬ_ПРИВАТНЫЙ_КЛЮЧ_КЛИЕНТА +DNS = 192.168.1.100 + +[Peer] +PublicKey = ВСТАВЬ_ПУБЛИЧНЫЙ_КЛЮЧ_СЕРВЕРА +Endpoint = 185.35.193.144:43123 +AllowedIPs = 10.10.99.0/24, 192.168.1.0/24 +PersistentKeepalive = 25 + + + VPN + + RemoteAddress + 185.35.193.144:43123 + AuthenticationMethod + Password + + OnDemandEnabled + 1 + OnDemandRules + + + Action + Disconnect + InterfaceTypeMatch + WiFi + SSIDMatch + + HomeWiFi + + + + Action + Connect + + + + + PayloadDisplayName + WireGuard Local VPN (On-Demand) + PayloadIdentifier + ru.katykhin.wireguard.local-vpn + PayloadType + Configuration + PayloadUUID + B2C3D4E5-F6A7-5B6C-9D0E-1F2A3B4C5D6E + PayloadVersion + 1 + + +``` + +Для **iOS** замени `VPNSubType` на `com.wireguard.ios` и в `WgQuickConfig` задай свой `Address` (например `10.10.99.2/32`) и приватный ключ того peer’а, который добавлен для этого устройства в `wg0.conf`. + +--- + +## Генерация ключей (на сервере) + +На сервере WireGuard (например в CT 109): + +```bash +# Приватный ключ +wg genkey | tee client.key | wg pubkey > client.pub + +# Вывести для копирования в профиль +cat client.key # → PrivateKey в [Interface] +cat /etc/wireguard/server.pub # → PublicKey в [Peer] +``` + +Отдельные ключи для каждого устройства (например `ios.key`/`macos.key`) и соответствующие peer’ы в `wg0.conf` — см. [контейнер 109](../containers/container-109.md). + +--- + +## Безопасность + +- В `.mobileconfig` попадают **приватные ключи** клиента. Файл нужно хранить только на доверенных носителях и не коммитить в публичный репозиторий. +- В этом проекте файлы `*.mobileconfig` и конкретно `wireguard-macos-ondemand.mobileconfig`, `wireguard-ios-ondemand.mobileconfig` добавлены в `.gitignore`. +- Передавать профиль на устройство по защищённому каналу (AirDrop, личная почта, зашифрованный диск). + +--- + +## Установка профиля + +- **macOS:** двойной клик по `.mobileconfig` → откроются «Системные настройки» → «Профили» → установить. Туннель появится в приложении WireGuard; при необходимости один раз включите его вручную, далее On-Demand будет управлять подключением. +- **iOS:** отправить файл на устройство (AirDrop, почта, «Файлы») → открыть → «Установить» → при необходимости «Настройки» → «Основные» → «VPN и управление устройством» → установить профиль. Туннель появится в WireGuard; включите один раз вручную, затем работает On-Demand. + +После смены SSID или ключей — удалить старый профиль и установить новый. + +--- + +## Связь с другими документами + +- [Контейнер 109 (WireGuard)](../containers/container-109.md) — настройка сервера, ключи, клиентские конфиги, раздел «On-Demand для iOS/macOS». +- [Архитектура](../architecture/architecture.md) — таблица контейнеров, CT 109. +- [Схема сети](network-topology.md) — место VPN в топологии, доступ к vault.katykhin.ru. diff --git a/scripts/npm-add-proxy-vault.sh b/scripts/npm-add-proxy-vault.sh new file mode 100644 index 0000000..8762bb4 --- /dev/null +++ b/scripts/npm-add-proxy-vault.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Add vault.katykhin.ru → 192.168.1.103:8280 via NPM API + Access List (LAN + VPN only) +# Usage: NPM_EMAIL=j3tears100@gmail.com NPM_PASSWORD=xxx ./npm-add-proxy-vault.sh +# Run from host that can reach NPM, or: ssh root@192.168.1.150 "pct exec 100 -- bash -s" < scripts/npm-add-proxy-vault.sh +# (then set NPM_URL=http://127.0.0.1:81 and NPM_EMAIL/NPM_PASSWORD in env or below) +# NPM credentials: see docs/containers/container-100.md + +set -e +NPM_URL="${NPM_URL:-http://192.168.1.100:81}" +API="$NPM_URL/api" +NPM_EMAIL="${NPM_EMAIL:-j3tears100@gmail.com}" +NPM_PASSWORD="${NPM_PASSWORD:-kqEUubVq02DJTS8}" + +echo "1. Getting token..." +TOKEN=$(curl -s -X POST "$API/tokens" \ + -H "Content-Type: application/json" \ + -d "{\"identity\":\"$NPM_EMAIL\",\"secret\":\"$NPM_PASSWORD\"}" \ + | jq -r '.token // empty') + +if [ -z "$TOKEN" ]; then + echo "Failed to get token" + exit 1 +fi + +ACCESS_LIST_ID="" +echo "2. Creating access list (LAN + VPN only)..." +# NPM backend may expect 0/1 for booleans; try minimal payload if 500 +AL_PAYLOAD=$(jq -n \ + --arg name "Vaultwarden LAN+VPN" \ + '{ name: $name, satisfy_any: 0, pass_auth: 0 }') + +AL_RESP=$(curl -s -w "\n%{http_code}" -X POST "$API/nginx/access-lists" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$AL_PAYLOAD") +AL_HTTP=$(echo "$AL_RESP" | tail -1) +AL_BODY=$(echo "$AL_RESP" | sed '$d') + +if [ "$AL_HTTP" = "201" ] || [ "$AL_HTTP" = "200" ]; then + ACCESS_LIST_ID=$(echo "$AL_BODY" | jq -r '.id') + echo " Access list ID: $ACCESS_LIST_ID" +else + echo " Access list creation failed (HTTP $AL_HTTP): $AL_BODY" + echo " Creating proxy without access list; add list in NPM UI and attach to this proxy." + echo " In UI: Access Lists -> create 'Vaultwarden LAN+VPN', add Allow 192.168.1.0/24 and 10.10.99.0/24, then set it on vault.katykhin.ru proxy." +fi + +# NPM API may not expose adding IP allow items via API; add 192.168.1.0/24 and 10.10.99.0/24 in UI. + +echo "3. Finding certificate for vault.katykhin.ru..." +CERT_ID=$(curl -s -H "Authorization: Bearer $TOKEN" "$API/nginx/certificates" \ + | jq -r '.[] | select(.domain_names[]? == "vault.katykhin.ru") | .id' | head -1) + +if [ -z "$CERT_ID" ] || [ "$CERT_ID" = "null" ]; then + echo " Certificate not found in NPM. Adding from custom_ssl/npm-18..." + CERT_DIR="/opt/docker/nginx-proxy/data/custom_ssl/npm-18" + if [ -f "$CERT_DIR/fullchain.pem" ] && [ -f "$CERT_DIR/privkey.pem" ]; then + CERT_ESC=$(jq -Rs . < "$CERT_DIR/fullchain.pem") + KEY_ESC=$(jq -Rs . < "$CERT_DIR/privkey.pem") + CERT_RESP=$(curl -s -w "\n%{http_code}" -X POST "$API/nginx/certificates" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "{\"provider\":\"other\",\"domain_names\":[\"vault.katykhin.ru\"],\"nice_name\":\"vault.katykhin.ru\",\"meta\":{\"certificate\":$CERT_ESC,\"certificate_key\":$KEY_ESC}}") + CERT_HTTP=$(echo "$CERT_RESP" | tail -1) + CERT_BODY=$(echo "$CERT_RESP" | sed '$d') + if [ "$CERT_HTTP" = "201" ]; then + CERT_ID=$(echo "$CERT_BODY" | jq -r '.id') + echo " Certificate added, ID: $CERT_ID" + else + echo " Failed to add certificate (HTTP $CERT_HTTP): $CERT_BODY" + CERT_ID="" + fi + else + echo " Skip: no cert files in $CERT_DIR (run from inside CT 100)" + fi +fi + +echo "4. Creating proxy host vault.katykhin.ru -> 192.168.1.103:8280..." +PROXY_PAYLOAD=$(jq -n \ + --arg cert "$CERT_ID" \ + --arg alid "$ACCESS_LIST_ID" \ + '{ + domain_names: ["vault.katykhin.ru"], + forward_host: "192.168.1.103", + forward_port: "8280", + forward_scheme: "http", + enabled: true, + allow_websocket_upgrade: true, + http2_support: true, + block_exploits: true, + certificate_id: (if $cert != "" and $cert != "null" then ($cert | tonumber) else null end), + ssl_forced: ($cert != "" and $cert != "null"), + access_list_id: (if $alid != "" and $alid != "null" then ($alid | tonumber) else 0 end) + }') + +RESP=$(curl -s -w "\n%{http_code}" -X POST "$API/nginx/proxy-hosts" \ + -H "Authorization: Bearer $TOKEN" \ + -H "Content-Type: application/json" \ + -d "$PROXY_PAYLOAD") +HTTP_CODE=$(echo "$RESP" | tail -1) +BODY=$(echo "$RESP" | sed '$d') + +if [ "$HTTP_CODE" = "201" ]; then + echo "Proxy host created: https://vault.katykhin.ru -> 192.168.1.103:8280 (Access List: LAN + VPN)" + echo "$BODY" | jq . +else + echo "Failed (HTTP $HTTP_CODE):" + echo "$BODY" | jq . 2>/dev/null || echo "$BODY" + exit 1 +fi diff --git a/scripts/npm-fix-proxy-domain-names.sh b/scripts/npm-fix-proxy-domain-names.sh new file mode 100644 index 0000000..c9bce06 --- /dev/null +++ b/scripts/npm-fix-proxy-domain-names.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Fix proxy_host rows where domain_names is stored as string instead of JSON array (causes "e.map is not a function" in NPM UI). +# Run on CT 100 where NPM data lives: ssh root@PROXMOX "pct exec 100 -- bash -s" < scripts/npm-fix-proxy-domain-names.sh + +set -e +DB="${NPM_DB:-/opt/docker/nginx-proxy/data/database.sqlite}" + +if [ ! -f "$DB" ]; then + echo "Database not found: $DB" + exit 1 +fi + +# Fix id=10: domain_names was "[mini-lm.katykhin.ru]" (string), must be ["mini-lm.katykhin.ru"] (JSON array) +sqlite3 "$DB" "UPDATE proxy_host SET domain_names = '[\"mini-lm.katykhin.ru\"]' WHERE id = 10;" +echo "Updated proxy_host id=10 domain_names to array." +sqlite3 "$DB" "SELECT id, domain_names FROM proxy_host WHERE id = 10;"