Files
hysteria2/README.md
T
Sergey Antropoff 401f03014a fix: generate VPN passwords without pwgen, set EDITOR=nano
Use Ansible password lookup on the control node so install works before packages are installed on VPS and without pwgen on macOS. Export EDITOR=nano in Makefile for vault-edit.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-01 11:43:34 +03:00

367 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.
# Hysteria2 Ansible — ветка **Salamander**
> **Ветка:** `salamander`
> **Режим:** **Salamander obfs** — запутывание пакетов для обхода DPI
> **Основная ветка:** [`main`](https://git.antropoff.ru/DevOpsTools/hysteria2/src/branch/main) — masquerade под HTTPS-сайт nginx
Ansible-роль для установки [Hysteria 2](https://v2.hysteria.network/) на Debian/Ubuntu VPS с **Salamander obfs** — когда masquerade под «обычный сайт» недостаточен.
---
## Выбор ветки: `main` или `salamander`
| | **`main`** | **`salamander` (эта ветка)** |
|---|---|---|
| Маскировка | HTTPS-сайт nginx + Let's Encrypt | **Salamander obfs** — пакеты выглядят как шум |
| Порт 80/tcp | **Нужен** (ACME HTTP + masquerade) | **Не нужен** |
| ACME | `type: http` | `type: tls` (TLS-ALPN на 443) |
| Сайт-заглушка | `/var/www/masq` (nginx welcome) | **Нет** |
| Obfs-пароль | — | **Обязателен** (один на сервер) |
| URI клиента | `hysteria2://user:pass@domain:443` | + `obfs=salamander&obfs-password=...` |
| Лучше когда | Нужен «легитимный» сайт в браузере | Агрессивный DPI, блокировка QUIC fingerprint |
### Когда выбирать `salamander`
- masquerade из `main` **блокируют** или распознают по fingerprint;
- не нужен фейковый сайт в браузере;
- готовы хранить **дополнительный** obfs-пароль.
### Когда выбирать `main`
- нужен **нормальный HTTPS-сайт** при открытии домена;
- достаточно маскировки под nginx;
- хотите **минимум параметров** в URI клиента.
---
## Быстрый старт
```bash
git clone https://git.antropoff.ru/DevOpsTools/hysteria2.git
cd hysteria2
git checkout salamander
make init
# отредактировать inventory/hosts.yml, group_vars/all.yml, vault
make vault-encrypt
make ping
make install # → output/index.html откроется в браузере
```
---
## Makefile
| Команда | Описание |
|---|---|
| `make help` | Справка |
| `make init` | Создать конфиги из `.example` |
| `make ping` | Проверить SSH к VPS |
| `make status` | `systemctl status hysteria-server` |
| `make install` | Установка Salamander + экспорт URL/QR/HTML |
| `make update` | Обновить бинарник, конфиг, перевыпустить экспорт |
| `make export` | Только экспорт (URL, QR, HTML) |
| `make uninstall` | Удалить Hysteria2 с VPS |
| `make vault-encrypt` | Зашифровать vault |
| `make vault-edit` | Редактировать vault |
```bash
make install LIMIT=vps-de
make update LIMIT=vps-nl
make export
make uninstall LIMIT=vps-de EXTRA_VARS='hysteria2_uninstall_remove_local_output=true'
make install EXTRA_VARS='hysteria2_open_browser=false'
make update EXTRA_VARS='hysteria2_wait_for_acme=false'
```
---
## Inventory
```yaml
all:
children:
hysteria2_servers:
hosts:
vps-de:
ansible_host: 203.0.113.10
ansible_port: 2222 # SSH-порт (если не 22)
ansible_user: root
ansible_password: "{{ vault_ssh_passwords['vps-de'] }}"
hysteria2_domain: vpn-de.example.com # для TLS/SNI и ACME
hysteria2_users:
- my
- friend
vps-nl:
ansible_host: 203.0.113.20
ansible_user: root
ansible_password: "{{ vault_ssh_passwords['vps-nl'] }}"
hysteria2_domain: vpn-nl.dynu.net
hysteria2_users:
- alice
- bob
```
### SSH (VPS)
| Параметр | Где | Описание |
|---|---|---|
| `ansible_host` | inventory | IP VPS |
| `ansible_port` | inventory | SSH-порт (по умолчанию `22`) |
| `ansible_user` | inventory | Пользователь SSH (обычно `root`) |
| `ansible_password` | inventory + vault | Пароль из `vault_ssh_passwords` |
| `ansible_ssh_private_key_file` | inventory | Альтернатива — SSH-ключ |
```yaml
# group_vars/hysteria2_servers/vault.yml
vault_ssh_passwords:
vps-de: "root-password-1"
vps-nl: "root-password-2"
```
Ключи в `vault_ssh_passwords` совпадают с **именами хостов** в inventory.
---
## Как работает Salamander в этом проекте
### Сервер (`/etc/hysteria/config.yaml`)
```yaml
listen: 0.0.0.0:443
acme:
type: tls # сертификат без порта 80
domains:
- vpn-de.example.com
email: admin@example.com
auth:
type: userpass
userpass:
my: "..."
friend: "..."
obfs:
type: salamander
salamander:
password: "общий_obfs_пароль_сервера"
```
### Клиент (генерируется автоматически)
```yaml
server: vpn-de.example.com:443
auth: my:password
obfs:
type: salamander
salamander:
password: общий_obfs_пароль_сервера
```
### URI (пример)
```
hysteria2://my:password@vpn-de.example.com:443?obfs=salamander&obfs-password=OBFS_PASS#my
```
Роль вызывает `hysteria share` — URI и QR уже содержат параметры Salamander.
---
## Пароли
### VPN-пользователи (`userpass`)
1. **Vault (рекомендуется):**
```yaml
vault_hysteria2_user_passwords:
vps-de:
friend: "Aingae0Okit1eek4eeZahFohVei4akee"
```
Подключается через `group_vars/hysteria2_servers/vars.yml`:
```yaml
```
2. **Per-host в inventory:**
```yaml
hysteria2_user_passwords:
friend: "custom-password"
```
3. **Автогенерация** — Ansible `password` lookup (длина `hysteria2_password_length`), если пароль не задан.
При `make update` пароли подтягиваются из `output/<server>/server-info.yml`, если не указаны в vault/inventory.
### Salamander obfs (один на сервер)
1. **Vault (рекомендуется):**
```yaml
vault_hysteria2_obfs_passwords:
vps-de: "cry_me_a_r1ver_salamander_obfs"
```
Подключается через `group_vars/hysteria2_servers/vars.yml`:
```yaml
```
2. **Авто:** Ansible `password` lookup (`hysteria2_obfs_password_length`) при первой установке
3. **При update:** загружается из `output/<server>/server-info.yml`
> **Важно:** obfs-пароль на сервере и клиенте должен **совпадать**. При `make update` без vault пароль сохраняется из предыдущего экспорта.
---
## Let's Encrypt — обновление сертификата
**Да, Hysteria2 обновляет сертификат автоматически.**
При блоке `acme:` в конфиге встроенный ACME-клиент Hysteria2 сам получает и **продлевает** сертификат Let's Encrypt (срок ~90 дней). Повторный `make install` или certbot для продления **не нужны** — процесс `hysteria-server` делает это сам.
**Условия для авто-продления (ветка `salamander`):**
- сервер **запущен** и доступен из интернета;
- домен указывает на IP VPS;
- порт **443/tcp** открыт (ACME TLS-ALPN challenge);
- конфиг `acme` не удалён.
Проверка логов: `journalctl -u hysteria-server -f`
---
## Firewall
По умолчанию открываются только порты Hysteria2:
- **443/tcp**
- **443/udp**
**Порт 80 не используется** — в отличие от ветки `main`.
---
## Результат: папка `output/`
```
output/
├── index.html ← все серверы (открывается в браузере)
├── vps-de/
│ ├── index.html ← страница сервера + obfs-пароль
│ ├── my.url ← URI с obfs=salamander
│ ├── my.png ← QR PNG
│ ├── my.qr.txt ← QR ASCII
│ ├── my.txt
│ └── server-info.yml ← mode, obfs_password, users
└── vps-nl/
└── ...
```
HTML-страницы показывают:
- режим **Salamander** и **obfs-password** с кнопкой копирования;
- пароль и URL каждого пользователя;
- QR-коды;
- ссылки на файлы и страницы серверов.
После `make install`, `make update` и `make export` **`output/index.html` автоматически открывается в браузере** (macOS: `open`, Linux: `xdg-open`).
Отключить: `hysteria2_open_browser: false` в `group_vars/all.yml` или `EXTRA_VARS`.
---
## QR-коды
PNG генерируются средствами Ansible (без Python):
1. `apt install qrencode` на VPS (остаётся установленным)
2. `qrencode -o user.png "hysteria2://..."`
3. `fetch` — скачивание PNG на control node
ASCII QR — `hysteria share --qr``user.qr.txt`.
---
## Переменные
| Переменная | Где | Описание |
|---|---|---|
| `hysteria2_mode` | defaults | `salamander` (информативно) |
| `hysteria2_domain` | host | Домен для TLS/SNI/ACME |
| `hysteria2_users` | host | VPN-пользователи |
| `hysteria2_acme_email` | group | Email Let's Encrypt |
| `hysteria2_user_passwords` | host/vault | Свои пароли VPN |
| `hysteria2_obfs_password` | host/vault | Пароль Salamander (или авто) |
| `hysteria2_obfs_password_length` | group | Длина автопароля obfs (32) |
| `hysteria2_output_dir` | group | Папка экспорта (по умолчанию `./output`) |
| `hysteria2_listen_port` | group | Порт (443) |
| `hysteria2_generate_qr_png` | group | PNG QR через `qrencode` |
| `hysteria2_open_browser` | group | Открыть `output/index.html` после экспорта |
| `hysteria2_uninstall_remove_local_output` | extra-vars | Удалить `output/<server>/` при uninstall |
| `vault_hysteria2_obfs_passwords` | vault | obfs-пароли по серверам |
---
## Безопасность
- `output/` содержит пароли, obfs-ключи и URL — **не коммитить**`.gitignore`)
- `inventory/hosts.yml`, `vault.yml`, `.vault_pass` — не коммитить
- После `make init` выполните `make vault-encrypt`
- Salamander **не делает** вас невидимым: IP VPS и UDP-поток всё ещё можно анализировать
---
## Требования
- Ansible 2.14+
- Debian/Ubuntu VPS с sudo
- Домен с A-записью на IP (для ACME TLS)
- Клиент Hysteria2 с поддержкой Salamander (Shadowrocket, NekoBox, Hiddify и др.)
- Для авто-открытия браузера: macOS или Linux с `xdg-open`
---
## Структура роли
```
roles/hysteria2/
├── tasks/
│ ├── obfs.yml ← генерация/загрузка obfs-пароля
│ ├── configure.yml ← Salamander, без masquerade
│ ├── export.yml ← URL, QR, HTML сервера
│ └── export_global.yml ← общий output/index.html
└── templates/
├── config.yaml.j2 ← acme tls + obfs salamander
├── client.yaml.j2 ← клиент с obfs
└── export/ ← HTML-каталоги
```
---
## Переключение между ветками
```bash
git fetch origin
git checkout main # masquerade + nginx
git checkout salamander # Salamander obfs (эта ветка)
```
Конфиги на **уже установленном** сервере **не меняются** при переключении ветки в git.
Чтобы применить другой режим на VPS:
```bash
git checkout main # или salamander
make install # перекатит конфиг сервера
# или
make update
```
> Переключение режима **меняет** `/etc/hysteria/config.yaml` на сервере. Клиентские URI/QR нужно **перевыпустить** (`make export` или `make update`).