Перейти к содержанию

AmneziaWG: VPN-тоннели через VPS

Обфусцированный WireGuard-сервер на VPS vm-mini для обхода блокировок (Россия) и приватной сети.

Дата снимка: 24.08.2026 Сервер: VPS vm-mini (Hostkey, 46.17.99.183) — единственный VPS в инфраструктуре, совмещает роли web-front (nginx) и VPN-шлюза Порт: 8443/udp Подсеть VPN: 10.8.1.0/24 Клиентов: 11 (см. таблицу ниже)


Почему AmneziaWG, а не WireGuard

  • Классический WireGuard в РФ блокируется по сигнатуре трафика (DPI распознаёт handshake)
  • AmneziaWG добавляет обфускацию поверх WireGuard: junk-байты, скремблинг заголовков, маскировку под другие протоколы
  • Совместимость: клиент Amnezia (Windows/Linux/Android/iOS/Mac) и awg-quick для Linux CLI

Развёртывание сервера

Тип: Docker-контейнер (не systemd wg-quick — то было раньше, снесено 05.08.2026).

sudo docker ps -a | grep -i amnezia

Ожидаемый вывод:

amnezia-awg2   0.0.0.0:8443->8443/udp   Up N weeks

Живёт: контейнер amnezia-awg2, image amnezia-awg2, uptime > 2 недель.

Расположение конфига (внутри контейнера)

/opt/amnezia/awg/
├── awg0.conf                             # основной конфиг сервера + всех peers
├── clientsTable                          # JSON-таблица с именами и трафиком (chmod 700)
├── wireguard_psk.key                     # pre-shared key (45 байт, base64)
├── wireguard_server_private_key.key      # приватный ключ сервера ⚠
└── wireguard_server_public_key.key       # публичный ключ сервера

Прочитать конфиг с маскированием ключей:

sudo docker exec amnezia-awg2 sed -E 's/(PrivateKey|PublicKey|PresharedKey)\s*=\s*.*/\1 = <REDACTED>/g' /opt/amnezia/awg/awg0.conf

Server config (структура)

awg0.conf — секция [Interface] + N секций [Peer].

[Interface] — сервер

[Interface]
PrivateKey = <REDACTED>
Address    = 10.8.1.0/24
ListenPort = 8443

# Amnezia obfuscation parameters (уникальны для каждой инсталляции)
Jc = 5                                    # junk packet count
Jmin = 10                                 # min junk size
Jmax = 50                                 # max junk size
S1 = 131                                  # scrambler parameter 1
S2 = 76
S3 = 24
S4 = 4
H1 = 1641349487-1779097007                # header rotation seed 1
H2 = 2066003011-2130195867
H3 = 2146414465-2147337260
H4 = 2147459586-2147482239

# I1: sample "cover traffic" — DNS-запрос под iCloud.com для маскировки первого handshake
# I1 = <r 2><b 0x8580...>

Важно: S1-S4, H1-H4, Jc/Jmin/Jmax, I1обязаны совпадать между сервером и клиентами, иначе handshake не пройдёт.

[Peer] — клиенты

Каждый клиент — блок:

[Peer]
PublicKey    = <клиентский pub>
PresharedKey = <REDACTED>
AllowedIPs   = 10.8.1.N/32

AllowedIPs с точки зрения сервера — какие IP клиент имеет право использовать (обычно один /32).


Клиенты (6 штук, аудит 24.08.2026)

IP Имя в GUI Создан Трафик RX / TX Последний handshake Статус
10.8.1.1 Admin [Windows 10 22H2] 18.07.2026 27.34 / 3.43 GiB 24.08, около часа назад 🟢 активен
10.8.1.3 Admin [Android 14.0] 18.07.2026 46.28 / 3.62 GiB 24.08, менее 2 минут 🟢 активен
10.8.1.4 unknown-active-10.8.1.4 18.07.2026 38.60 / 1.22 GiB 24.08, около 4 часов 🟡 активен, устройство ещё определить
10.8.1.5 марина лисичка 23.07.2026 28.30 / 1.45 GiB 24.08, менее 2 минут 🟢 активен
10.8.1.7 marina komp 23.07.2026 31.80 / 2.02 GiB 24.08, около 13 часов 🟢 активен
10.8.1.12 ragserver 24.08.2026 24.08, менее 10 секунд 🟢 активен, управляется GUI

По результатам аудита выяснено, что .2, .6, .9 и .10 уже отсутствуют после перезаписи конфигурации через GUI. Удалены неактивный .8 и устаревшая запись .11. Активный .4 сохранён и получил временное диагностическое имя до определения конкретного устройства.


NAT и маршрутизация

Внутри контейнера amnezia-awg2:

MASQUERADE  -s 172.29.172.1/32 -d 10.8.1.12/32 -o awg0
MASQUERADE  -s 10.8.1.0/24 -o eth0
MASQUERADE  -s 10.8.1.0/24 -o eth1

Что это значит:

  • eth0 (172.29.172.2/24) — основной выход контейнера через bridge amn0
  • eth1 (172.17.0.2/16) — отдельная Docker-сеть
  • awg0 — туннель к клиентам; узкий SNAT нужен для VPS → ragserver
  • Правила -o eth0 и -o eth1 не являются дубликатами
  • Клиент сам определяет направляемый в VPN трафик через AllowedIPs и локальную policy routing

Split-tunnel на клиенте: примеры

Full-tunnel (весь трафик через VPN):

[Peer]
AllowedIPs = 0.0.0.0/0, ::/0

Простой split-tunnel — только определённые сети/сервисы через VPN:

[Peer]
AllowedIPs = 10.8.1.0/24, <specific_subnets_or_IPs>

На ragserver применяется более гибкая схема: AllowedIPs = 0.0.0.0/0, ::/0 вместе с Table = off и отдельным policy routing по fwmark 0x1234.

Split-tunnel — обход по домену (Amnezia GUI позволяет):

  • Настройка в приложении Amnezia на клиенте (Windows/Android): "Только сайты из списка" или "Все кроме указанных"
  • Приложение динамически обновляет AllowedIPs по DNS-запросам

Что ЧЕРЕЗ VPN НЕ идёт (важно для архитектуры)

VPS 46.17.99.183VPN-сервер, а не клиент. Сам он в VPN не заворачивается — весь его трафик (nginx → клиенты в интернете, Let's Encrypt renew, GitHub синхроны) идёт напрямую через Hostkey uplink.

Ragserver (192.168.1.200) тоже не заворачивает весь трафик в VPN. В peer задано AllowedIPs = 0.0.0.0/0, ::/0, но Table = off запрещает awg-quick менять main routing table. Отдельные fwmark 0x1234, таблица vpnroute и awg-rag-split-tunnel.service направляют через VPN только внешний трафик контейнера rag-openwebui; LAN и Docker-сети исключены.

Сервис на ragserver Как ходит наружу Причина
Ollama (host, :11434) Локально, не выходит в интернет Модели уже скачаны, эмбеддинги строятся на CPU локально
OpenWebUI: исходящие запросы к OpenRouter Через AmneziaWG Трафик контейнера 172.19.0.10 маркируется 0x1234
OpenWebUI: локальный и входящий трафик Напрямую/локально LAN и Docker-сети исключены из маркировки
PostgreSQL, Qdrant Локально Слушают только 127.0.0.1
git pull в /opt/rag-kb/ Напрямую в GitHub через роутер GitHub не заблокирован в РФ
rag-sync → OpenWebUI API Локально (127.0.0.1:3000) Оба сервиса на ragserver

Через VPN идут: маркированный внешний трафик rag-openwebui к OpenRouter, доступ VPS nginx к 10.8.1.12:3000, а также обращения к VPN-подсети.


Как добавить нового клиента

Через GUI Amnezia (простой путь)

  1. На админской машине откройте Amnezia (Windows/Mac)
  2. Servers → vm-mini → Clients → Add new client
  3. Название клиента → Amnezia сгенерирует пару ключей + конфиг
  4. Скопировать конфиг QR-коде или как файл .conf
  5. Отправить пользователю → он импортирует в свой Amnezia-клиент

Amnezia сама обновит awg0.conf и clientsTable, перезапустит контейнер.

Через CLI (если нужен awg-quick клиент — Linux/ragserver)

Пример как настроен awg-rag на ragserver:

# /etc/amnezia/amneziawg/awg-rag.conf

[Interface]
PrivateKey = <клиентский приватный>
Address    = 10.8.1.12/32
# DNS      = 1.1.1.1, 1.0.0.1

# Обфускация — ДОЛЖНО совпадать с сервером
Jc = 5
Jmin = 10
Jmax = 50
S1 = 131
S2 = 76
S3 = 24
S4 = 4
H1 = 1641349487-1779097007
H2 = 2066003011-2130195867
H3 = 2146414465-2147337260
H4 = 2147459586-2147482239
I1 = <значение из GUI-конфига>

# Маршруты создаёт отдельный policy-routing unit
Table = off

[Peer]
PublicKey       = <публичный ключ сервера>
PresharedKey    = <REDACTED>
Endpoint        = 46.17.99.183:8443
AllowedIPs      = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

Фактический split-tunnel реализован не через узкий AllowedIPs, а через Table = off, fwmark 0x1234, таблицу vpnroute и unit awg-rag-split-tunnel.service. Через VPN идёт только внешний трафик контейнера rag-openwebui (172.19.0.10); LAN и Docker-сети исключены правилами mangle.

Запуск:

sudo awg-quick up awg-rag
sudo systemctl enable awg-quick@awg-rag

Как добавить нового awg-quick клиента вручную (без GUI):

Пока не описано — TODO расписать пошагово, когда потребуется.


Проверка что тоннель работает

На сервере (VPS)

# Контейнер живой
sudo docker ps | grep amnezia

# Логи
sudo docker logs amnezia-awg2 --tail 30

# Активные handshakes (кто сейчас в тоннеле)
sudo docker exec amnezia-awg2 awg show

# Или посмотреть в JSON
sudo docker exec amnezia-awg2 cat /opt/amnezia/awg/clientsTable | jq

На клиенте (ragserver, awg-rag)

sudo awg show awg-rag

# Проверка что VPN-IP видит сервер
ping -c 3 10.8.1.0

# Проверка что через VPN виден внешний интернет (если full-tunnel)
curl -s https://ifconfig.me
# Должен показать 46.17.99.183 (IP VPS)

С Windows-клиента

  • Amnezia GUI → Servers → vm-mini → зелёный кружок + "Connected"
  • Или в CMD: ping 10.8.1.0

Восстановление и бэкап AmneziaWG

Что бэкапить:

  1. /opt/amnezia/awg/awg0.conf — весь конфиг с peers
  2. /opt/amnezia/awg/wireguard_server_private_key.key — приватный ключ сервера
  3. /opt/amnezia/awg/wireguard_psk.key — pre-shared key
  4. /opt/amnezia/awg/clientsTable — обязательные метаданные GUI-клиентов

Автоматический бэкап на VPS:

sudo /opt/backups/amneziawg-backup.sh
sudo tail -20 /var/log/amneziawg-backup.log

Скрипт запускается ежедневно в 03:20 MSK, хранит GPG-архивы в /opt/backups/amneziawg/ и удаляет плановые архивы старше 30 дней. В архив входят весь каталог awg/, docker inspect, полный iptables-save, адреса и маршруты хоста. Незашифрованный tar существует только во временном каталоге с режимом 700 и удаляется через trap. Перед успешным завершением скрипт расшифровывает архив и проверяет наличие пяти обязательных файлов.

Off-site копия пока не настроена, см. задачу 17.

Восстановление после переустановки VPS

Худший сценарий: VPS упал, ставим новый, что делать:

  1. Установить Amnezia сервер через официальный setup.sh
  2. Остановить контейнер: sudo docker stop amnezia-awg2
  3. Восстановить /opt/amnezia/awg/ из бэкапа
  4. Запустить: sudo docker start amnezia-awg2
  5. Клиенты подключатся автоматически (у них конфиги не менялись)

Условие успеха: Endpoint IP 46.17.99.183 не должен меняться, иначе клиентам придётся обновить .conf файлы.

Если IP поменялся: - Ждать пока клиенты сами обновят через Amnezia GUI (для не-CLI клиентов) - Для CLI клиентов (ragserver) — редактировать awg-rag.conf и awg-quick down/up awg-rag


TODO (сводка)

🟢 Приоритет 3 — документация

  • Расписать пошагово "как добавить awg-quick клиента вручную (без GUI)"
  • Добавить sample split-tunnel конфиг для типичных сценариев (только соцсети, только rag.alatyr-service.ru, только конкретные IP)

Ссылки


История изменений

Дата Что
2026-08-25 Задача #19 закрыта: установлен /opt/backups/amneziawg-backup.sh, ежедневный запуск 03:20 MSK, локальный retention 30 дней. Первый плановый архив создан и независимо проверен расшифровкой и чтением содержимого; открытых .tar.gz нет. Off-site остаётся задачей #17.
2026-08-24 Задача #26 закрыта без удаления: правила MASQUERADE для 10.8.1.0/24 используют разные выходы eth0 и eth1 и не являются дубликатами. Отдельный узкий SNAT через awg0 нужен для rag-api. Опасная рекомендация удаления по номеру строки заменена безопасной диагностикой.
2026-08-24 Проведён аудит клиентов: .2, .6, .9, .10 уже отсутствовали после перезаписи через GUI; удалены неактивный .8 и устаревшая запись .11. Активный .4 сохранён и переименован в unknown-active-10.8.1.4. В clientsTable и runtime осталось 6 согласованных peers.
2026-08-24 awg-rag переоформлен через Amnezia GUI: старый ручной peer 10.8.1.11 удалён, новый GUI-managed клиент ragserver получил 10.8.1.12. Обновлены конфиг ragserver, Docker bindings, nginx, VPS host-route/SNAT; проверены handshake, OpenRouter, storage-api и Open WebUI через VPN.
2026-08-05 Первая версия. Задокументированы сервер (Docker amnezia-awg2), 11 клиентов, NAT, split-tunnel клиента ragserver, восстановление. Найдены проблемы: awg-rag вне clientsTable, 4 неактивных клиента, AmneziaWG не в бэкапах.
2026-08-05 Добавлен раздел "Что через VPN НЕ идёт" — уточнено, что RAG-стек (Ollama, OpenWebUI, Postgres, Qdrant, rag-sync, git pull) работает вне VPN. VPS 46.17.99.183 — единственный, сам в VPN не заворачивается.