240 lines
8.8 KiB
Markdown
240 lines
8.8 KiB
Markdown
|
|
# Operator guide — Montana VPN
|
|||
|
|
|
|||
|
|
Как поднять свой Reality-эндпоинт на чистом VPS с нуля, выдать клиенту, обслуживать.
|
|||
|
|
|
|||
|
|
## Шаг 0 — выбор VPS
|
|||
|
|
|
|||
|
|
Требования:
|
|||
|
|
- Linux Ubuntu 24.04 / Debian 12 / Fedora 40+ / RHEL-family / Alpine
|
|||
|
|
- Минимум 512 MiB RAM (xray ~60 MiB, nginx ~10 MiB; рекомендуется 1 GiB+ если хостить узел Montana рядом)
|
|||
|
|
- 5 GiB disk (под систему + логи; узел Montana добавит ~50 MiB/год)
|
|||
|
|
- 1 vCPU достаточно
|
|||
|
|
- Public IPv4 со свободным :443 и :80
|
|||
|
|
- Рут-доступ либо sudo
|
|||
|
|
|
|||
|
|
**Хорошие провайдеры (нейтральные юрисдикции):**
|
|||
|
|
|
|||
|
|
- THE.Hosting (Финляндия) — текущий montana-finland
|
|||
|
|
- Hetzner (Финляндия / Германия) — стабильный, недорогой, хорошая network policy
|
|||
|
|
- Mythic Beasts (UK) — privacy-friendly
|
|||
|
|
- 1984 Hosting (Исландия) — nation-level legal protection
|
|||
|
|
- Njalla (no-KYC, разные локации)
|
|||
|
|
|
|||
|
|
**Юрисдикции которые избегать для VPN:** US, UK (5 Eyes core), Russia, China, Iran, любая страна где VPN-операция требует регистрации.
|
|||
|
|
|
|||
|
|
## Шаг 1 — установка одной командой
|
|||
|
|
|
|||
|
|
После git clone и `sudo`:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo bash montana-vpn/install.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Что произойдёт:
|
|||
|
|
1. apt/dnf/apk install nginx + ufw + curl + jq
|
|||
|
|
2. Скачивание xray через официальный installer XTLS/Xray-install
|
|||
|
|
3. Генерация Reality keypair (X25519), UUID клиента, shortId — всё локально на VPS
|
|||
|
|
4. Сборка `/usr/local/etc/xray/config.json` из шаблона
|
|||
|
|
5. Поднятие nginx :80 с decoy `It works!`
|
|||
|
|
6. Установка systemd unit с hardening
|
|||
|
|
7. Открытие 22/80/443 в ufw, остальное закрытие
|
|||
|
|
8. Включение BBR + fq_codel
|
|||
|
|
9. Запуск xray, печать VLESS URL для клиента
|
|||
|
|
|
|||
|
|
В конце выведется одна строка `vless://...` — это всё что нужно клиенту.
|
|||
|
|
|
|||
|
|
## Шаг 2 — первичная защита SSH
|
|||
|
|
|
|||
|
|
В `install.sh` это **не** делается (опционально, чтобы не сломать доступ оператору). Делается вручную после установки:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# Включить ключ-only auth
|
|||
|
|
sudo sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
|
|||
|
|
sudo systemctl restart ssh
|
|||
|
|
|
|||
|
|
# Поставить fail2ban
|
|||
|
|
sudo apt install -y fail2ban
|
|||
|
|
sudo tee /etc/fail2ban/jail.local >/dev/null <<'JAIL'
|
|||
|
|
[DEFAULT]
|
|||
|
|
bantime = 1h
|
|||
|
|
findtime = 10m
|
|||
|
|
maxretry = 3
|
|||
|
|
backend = auto
|
|||
|
|
bantime.increment = true
|
|||
|
|
bantime.factor = 2
|
|||
|
|
bantime.maxtime = 1w
|
|||
|
|
|
|||
|
|
[sshd]
|
|||
|
|
enabled = true
|
|||
|
|
JAIL
|
|||
|
|
sudo systemctl enable --now fail2ban
|
|||
|
|
|
|||
|
|
# (опционально) crowdsec для IP-reputation feed
|
|||
|
|
curl -s https://install.crowdsec.net | sudo sh
|
|||
|
|
sudo apt install -y crowdsec-firewall-bouncer-iptables
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Шаг 3 — выдача клиенту
|
|||
|
|
|
|||
|
|
В выводе `install.sh` строка вида:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
vless://e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d@91.132.142.42:443?encryption=none&flow=xtls-rprx-vision&security=reality&sni=www.googletagmanager.com&fp=chrome&pbk=AbCd...&sid=302805bc0c25e504&type=tcp#montana-vpn
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Передать клиенту через **зашифрованный канал** (Signal, ProtonMail с PGP, Threema, не Telegram-чат-историю и не email plaintext).
|
|||
|
|
|
|||
|
|
Клиент импортирует в:
|
|||
|
|
- iOS / macOS: **Streisand** (App Store), **FoXray**, **Hiddify**
|
|||
|
|
- Android: **v2rayNG**, **Hiddify**, **NekoBox**
|
|||
|
|
- Windows: **v2rayN**, **Hiddify**
|
|||
|
|
- Linux: **Hiddify-Next** или CLI `xray run -config /path/to/config.json`
|
|||
|
|
- Router (OpenWrt): **xray-core** + sing-box
|
|||
|
|
|
|||
|
|
## Шаг 4 — мониторинг
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# статус сервиса
|
|||
|
|
systemctl status xray
|
|||
|
|
|
|||
|
|
# логи (live)
|
|||
|
|
journalctl -u xray -f
|
|||
|
|
|
|||
|
|
# access log (кто подключался когда)
|
|||
|
|
sudo tail -f /var/log/xray/access.log
|
|||
|
|
|
|||
|
|
# error log
|
|||
|
|
sudo tail -f /var/log/xray/error.log
|
|||
|
|
|
|||
|
|
# текущие соединения
|
|||
|
|
sudo ss -tlnp | grep :443
|
|||
|
|
|
|||
|
|
# CPU/RAM xray
|
|||
|
|
ps aux | grep -v grep | grep xray
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Шаг 5 — обновление xray
|
|||
|
|
|
|||
|
|
xray релизит security patches. Минимум раз в квартал:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) @ install
|
|||
|
|
sudo systemctl restart xray
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Конфиг в `/usr/local/etc/xray/config.json` сохраняется, ключи в `/etc/montana-vpn/state.env` тоже.
|
|||
|
|
|
|||
|
|
## Шаг 6 — ротация ключей (если подозрение на компрометацию)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo rm /etc/montana-vpn/state.env
|
|||
|
|
sudo bash montana-vpn/install.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Сгенерируются новые UUID + Reality keypair + shortId. Старые клиенты перестанут работать — нужно раздать новый VLESS URL.
|
|||
|
|
|
|||
|
|
## Шаг 7 — несколько клиентов
|
|||
|
|
|
|||
|
|
`install.sh` создаёт **одного** клиента в массиве `inbounds[0].settings.clients`. Чтобы добавить второго:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo nano /usr/local/etc/xray/config.json
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
В блоке `clients`:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
"clients": [
|
|||
|
|
{
|
|||
|
|
"id": "e6d355e2-2d79-4c96-a373-3b0e6b6f4b0d",
|
|||
|
|
"email": "alice",
|
|||
|
|
"flow": "xtls-rprx-vision"
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"id": "ВТОРОЙ-UUID-СГЕНЕРИРОВАТЬ-ЧЕРЕЗ-xray-uuid",
|
|||
|
|
"email": "bob",
|
|||
|
|
"flow": "xtls-rprx-vision"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo xray uuid # сгенерить UUID для bob
|
|||
|
|
sudo systemctl restart xray
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Reality keypair (`pbk`/`sid`) **общий** для всех клиентов одного эндпоинта. Различается только UUID. Это нормально и архитектурно правильно.
|
|||
|
|
|
|||
|
|
## Шаг 8 — отключение VPN (но узел Montana остаётся)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl stop xray
|
|||
|
|
sudo systemctl disable xray
|
|||
|
|
sudo ufw delete allow 443/tcp
|
|||
|
|
sudo ufw delete allow 80/tcp
|
|||
|
|
sudo systemctl stop nginx
|
|||
|
|
sudo systemctl disable nginx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Шаг 9 — полное удаление
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl stop xray
|
|||
|
|
sudo systemctl disable xray
|
|||
|
|
sudo bash <(curl -L https://github.com/XTLS/Xray-install/raw/main/install-release.sh) @ remove
|
|||
|
|
sudo rm -rf /etc/montana-vpn /usr/local/etc/xray /var/log/xray /var/www/decoy
|
|||
|
|
sudo apt remove -y nginx
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Узел Montana (если установлен) — отдельная команда:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo systemctl stop montana-node
|
|||
|
|
sudo systemctl disable montana-node
|
|||
|
|
sudo rm /etc/systemd/system/montana-node.service
|
|||
|
|
sudo systemctl daemon-reload
|
|||
|
|
sudo rm -rf /var/lib/montana /usr/local/bin/montana-node /opt/montana
|
|||
|
|
sudo userdel montana
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Troubleshooting
|
|||
|
|
|
|||
|
|
**Клиент не подключается, no error.**
|
|||
|
|
Проверь `pbk` (public key) — это **публичный** ключ из `state.env`. Если случайно вставил `private_key` — будет тихий fail.
|
|||
|
|
|
|||
|
|
**Клиент подключается, ping есть, но websites не открываются.**
|
|||
|
|
DNS leak. В клиенте принудительно через VPN: `1.1.1.1`. Либо проверь что в `xray-config.json` outbound `freedom` действительно direct, не proxy.
|
|||
|
|
|
|||
|
|
**xray падает с `failed to listen on 0.0.0.0:443: bind: permission denied`.**
|
|||
|
|
`AmbientCapabilities=CAP_NET_BIND_SERVICE` не сработал. Проверь systemd-version (≥232) и что drop-in присутствует. На старых Linux: `setcap 'cap_net_bind_service=+ep' /usr/local/bin/xray`.
|
|||
|
|
|
|||
|
|
**Reality handshake fail.**
|
|||
|
|
`dest` сайт перестал поддерживать TLS 1.3 + X25519 либо стал недоступен. Смени `DECOY_HOST=www.cloudflare.com` и переустанови.
|
|||
|
|
|
|||
|
|
**ufw блокирует :443.**
|
|||
|
|
`sudo ufw status verbose`. Если правил нет — `sudo ufw allow 443/tcp && sudo ufw reload`.
|
|||
|
|
|
|||
|
|
**RAM кончается.**
|
|||
|
|
Helsinki 961 MiB достаточно для xray-only. Если вместе с узлом Montana и swap нет — добавить swapfile:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo fallocate -l 1G /swapfile
|
|||
|
|
sudo chmod 600 /swapfile
|
|||
|
|
sudo mkswap /swapfile
|
|||
|
|
sudo swapon /swapfile
|
|||
|
|
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Backup
|
|||
|
|
|
|||
|
|
Что бэкапить (для пере-деплоя без потери ключей):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# одной командой — на локальную машину
|
|||
|
|
ssh montana-finland 'sudo tar czf - /etc/montana-vpn /usr/local/etc/xray /var/lib/montana 2>/dev/null' \
|
|||
|
|
> montana-finland-backup-$(date +%Y%m%d).tar.gz
|
|||
|
|
gpg -c montana-finland-backup-*.tar.gz # зашифровать паролем
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Хранить **отдельно** от мнемоники узла Montana. Backup VPN ≠ backup узла.
|