Files
homelab-docs/docs/network/vpn-mobileconfig-wireguard.md
2026-02-25 21:01:06 +03:00

259 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Генерация .mobileconfig для WireGuard VPN (On-Demand)
Как собрать Apple-профиль конфигурации (`.mobileconfig`) для WireGuard с правилами **On-Demand**: автоматическое подключение VPN вне домашней сети и отключение на домашнем WiFi.
---
## Зачем нужен .mobileconfig
- **Обычный конфиг WireGuard** — пользователь сам включает/выключает туннель.
- **Профиль .mobileconfig** — ставится в «Настройки» → «Профили» (macOS) или «Основные» → «VPN и управление устройством» (iOS). Туннель появляется в приложении WireGuard и может управляться **On-Demand**: система сама поднимает VPN, когда устройство не в доверенной сети (например не дома), и отключает на домашнем WiFi.
В итоге: за пределами дома — всегда 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 (например на домашнем WiFi) и когда подключать. |
---
## Конфиг 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 на домашнем WiFi** — правило с `Action = Disconnect` и условием по WiFi:
- `InterfaceTypeMatch` = `WiFi`;
- `SSIDMatch` = массив SSID (например `["HomeWiFi"]` или `["Netcraze-1882"]`).
- Итог: если устройство в WiFi с этим SSID → VPN отключается.
2. **Во всех остальных случаях — подключать** — правило без условий:
- `Action` = `Connect`.
- Итог: любой другой сеть (другой WiFi, сотовые данные) → 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.