some fix
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -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
|
||||
@@ -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 |
|
||||
|
||||
BIN
docs/.DS_Store
vendored
Normal file
BIN
docs/.DS_Store
vendored
Normal file
Binary file not shown.
@@ -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).
|
||||
|
||||
@@ -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). |
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) |
|
||||
|
||||
---
|
||||
|
||||
|
||||
203
docs/containers/container-109.md
Normal file
203
docs/containers/container-109.md
Normal file
@@ -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 = <server-private-key>
|
||||
|
||||
# Включение форвардинга 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 = <ios-public-key>
|
||||
AllowedIPs = 10.10.99.2/32
|
||||
|
||||
[Peer]
|
||||
# macOS
|
||||
PublicKey = <macos-public-key>
|
||||
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 = <ios-private-key>
|
||||
DNS = 192.168.1.100
|
||||
|
||||
[Peer]
|
||||
PublicKey = <server-public-key>
|
||||
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 = <macos-private-key>
|
||||
DNS = 192.168.1.100
|
||||
|
||||
[Peer]
|
||||
PublicKey = <server-public-key>
|
||||
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 и общие правила фаервола/маршрутизации.
|
||||
@@ -11,37 +11,38 @@
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph External["Внешний мир"]
|
||||
DNS["DNS (Beget)\n*.katykhin.ru → IP"]
|
||||
DNS["DNS (Beget)<br>*.katykhin.ru → IP"]
|
||||
end
|
||||
|
||||
subgraph Edge["Граница сети"]
|
||||
Router["Роутер\n192.168.1.1\nпроброс 80/443 → .100"]
|
||||
Router["Роутер<br>192.168.1.1<br>проброс 80/443 → .100"]
|
||||
end
|
||||
|
||||
subgraph Gateway["Единая точка входа"]
|
||||
NPM["NPM\nCT 100\nтерминация SSL, маршрут по Host"]
|
||||
NPM["NPM<br>CT 100<br>терминация 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<br>CT 101"]
|
||||
S103["Gitea / CouchDB / Vaultwarden<br>CT 103"]
|
||||
S104["Paperless<br>CT 104"]
|
||||
S105["RAG API<br>CT 105"]
|
||||
S107["Invidious<br>CT 107"]
|
||||
S108["Galene<br>CT 108"]
|
||||
S109["WireGuard VPN<br>CT 109<br>10.10.99.0/24"]
|
||||
S200["Immich<br>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<br>Redis<br>CT 101"]
|
||||
D103["PostgreSQL<br>CT 103"]
|
||||
D104["PostgreSQL<br>Redis<br>CT 104"]
|
||||
D107["PostgreSQL<br>CT 107"]
|
||||
D200["PostgreSQL<br>Redis<br>VM 200"]
|
||||
end
|
||||
|
||||
subgraph External2["Внешние зависимости"]
|
||||
coTURN["coTURN\nVPS Миран 185.147.80.190"]
|
||||
coTURN["coTURN<br>VPS Миран 185.147.80.190"]
|
||||
end
|
||||
|
||||
DNS --> Router
|
||||
@@ -53,6 +54,8 @@ flowchart TB
|
||||
NPM --> S107
|
||||
NPM --> S108
|
||||
NPM --> S200
|
||||
Router --> S109
|
||||
S109 -.->|"клиенты VPN<br>доступ к 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.
|
||||
|
||||
258
docs/network/vpn-mobileconfig-wireguard.md
Normal file
258
docs/network/vpn-mobileconfig-wireguard.md
Normal file
@@ -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
|
||||
<key>OnDemandRules</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Action</key>
|
||||
<string>Disconnect</string>
|
||||
<key>InterfaceTypeMatch</key>
|
||||
<string>WiFi</string>
|
||||
<key>SSIDMatch</key>
|
||||
<array>
|
||||
<string>HomeWiFi</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Action</key>
|
||||
<string>Connect</string>
|
||||
</dict>
|
||||
</array>
|
||||
```
|
||||
|
||||
Перед установкой профиля **замени** `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
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PayloadContent</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>VPN</string>
|
||||
<key>PayloadType</key>
|
||||
<string>com.apple.vpn.managed</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>ru.katykhin.wireguard.local-vpn.tunnel</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>A1B2C3D4-E5F6-4A5B-8C9D-0E1F2A3B4C5D</string>
|
||||
<key>UserDefinedName</key>
|
||||
<string>Local VPN (WireGuard)</string>
|
||||
<key>VPNType</key>
|
||||
<string>VPN</string>
|
||||
<key>VPNSubType</key>
|
||||
<string>com.wireguard.macos</string>
|
||||
<key>VendorConfig</key>
|
||||
<dict>
|
||||
<key>WgQuickConfig</key>
|
||||
<string>[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
|
||||
</string>
|
||||
</dict>
|
||||
<key>VPN</key>
|
||||
<dict>
|
||||
<key>RemoteAddress</key>
|
||||
<string>185.35.193.144:43123</string>
|
||||
<key>AuthenticationMethod</key>
|
||||
<string>Password</string>
|
||||
</dict>
|
||||
<key>OnDemandEnabled</key>
|
||||
<integer>1</integer>
|
||||
<key>OnDemandRules</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>Action</key>
|
||||
<string>Disconnect</string>
|
||||
<key>InterfaceTypeMatch</key>
|
||||
<string>WiFi</string>
|
||||
<key>SSIDMatch</key>
|
||||
<array>
|
||||
<string>HomeWiFi</string>
|
||||
</array>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>Action</key>
|
||||
<string>Connect</string>
|
||||
</dict>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>PayloadDisplayName</key>
|
||||
<string>WireGuard Local VPN (On-Demand)</string>
|
||||
<key>PayloadIdentifier</key>
|
||||
<string>ru.katykhin.wireguard.local-vpn</string>
|
||||
<key>PayloadType</key>
|
||||
<string>Configuration</string>
|
||||
<key>PayloadUUID</key>
|
||||
<string>B2C3D4E5-F6A7-5B6C-9D0E-1F2A3B4C5D6E</string>
|
||||
<key>PayloadVersion</key>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</plist>
|
||||
```
|
||||
|
||||
Для **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.
|
||||
110
scripts/npm-add-proxy-vault.sh
Normal file
110
scripts/npm-add-proxy-vault.sh
Normal file
@@ -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
|
||||
16
scripts/npm-fix-proxy-domain-names.sh
Normal file
16
scripts/npm-fix-proxy-domain-names.sh
Normal file
@@ -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;"
|
||||
Reference in New Issue
Block a user