vault backup: 2026-10-15 20:03:12
This commit is contained in:
@@ -0,0 +1,406 @@
|
||||
# AmneziaVPN в Docker: полный гайд
|
||||
|
||||
**Цель:** поднять в Docker контейнере клиент AmneziaVPN (AmneziaWG 3.1), подключить его по пользовательскому `.conf` от Amnezia Premium и сделать его VPN-шлюзом для домашней сети.
|
||||
|
||||
**Автор:** Hermes Agent • Среда: LXC-контейнер (Docker 29.4.1, ядро Proxmox 6.17.13-2-pve)
|
||||
|
||||
---
|
||||
|
||||
## 1. Что потребуется
|
||||
|
||||
| Компонент | Значение |
|
||||
|-----------|----------|
|
||||
| Хост | Linux с Docker 20.10+ (тестировалось: LXC 29.4.1) |
|
||||
| `/dev/net/tun` | Должен существовать и быть открыт |
|
||||
| `ip_forward` | `1` |
|
||||
| `.conf` файл | Amnezia Premium / AmneziaWG 3.1 конфиг |
|
||||
| Версии | `amneziawg-go` v3.1.20260828, `amneziawg-tools` v3.1.20260812 |
|
||||
|
||||
Пример `.conf` (Amnezia Premium, конфиг 3.1):
|
||||
```ini
|
||||
[Interface]
|
||||
Address = 100.85.175.118/32
|
||||
DNS = 100.64.0.1, 8.8.4.4
|
||||
PrivateKey = fSdjHMi8tAzL2wbNxsylQW1FAIXdn2/ODPGWr569J/w=
|
||||
Jc = 5
|
||||
Jmin = 10
|
||||
Jmax = 80
|
||||
H1 = 1
|
||||
H2 = 2
|
||||
H3 = 3
|
||||
H4 = 4
|
||||
HeaderProtectionKey = 8H1SggRhZ8iT8ZYZlS/RPf6SItoxb8OeXX2rNwMgc3M=
|
||||
RekeyAfterTime = 100-120
|
||||
RekeyTimeout = 3-8
|
||||
RejectAfterTime = 150-180
|
||||
KeepaliveTimeout = 7-13
|
||||
MaxHandshakeAttempts = 15-20
|
||||
ContentPaddingAddition = 10-100
|
||||
[Peer]
|
||||
PublicKey = FfgUO6z0plGUntTW3T8fsFsZ250GcQZEKlCgj1fkRFc=
|
||||
PresharedKey = +Is1eWUUQ5UXYD8E7zigG32KaThcGC/YolOVS7LeDGU=
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
Endpoint = 78.17.149.78:8344
|
||||
PersistentKeepalive = 25-35
|
||||
```
|
||||
|
||||
> ⚠️ **НЕ** выкладывай `.conf` ни в чат, ни на сторонние сайты. Его приватный ключ — твой доступ. Файл копируется только на сервер.
|
||||
|
||||
---
|
||||
|
||||
## 2. Подготовка хоста
|
||||
|
||||
```bash
|
||||
# Проверить Tun-устройство и форвардинг
|
||||
ls -la /dev/net/tun
|
||||
cat /proc/sys/net/ipv4/ip_forward # должно быть 1
|
||||
|
||||
# Включить форвардинг (если 0)
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
# Проверить Docker
|
||||
docker --version
|
||||
```
|
||||
|
||||
**На LXC (виртуальном контейнере Proxmox)** убедись, что:
|
||||
- `/dev/net/tun` существует (создаётся через настройки LXC)
|
||||
- `net.ipv4.ip_forward=1` установлен (в Proxmox: LXC → Options → Features)
|
||||
|
||||
---
|
||||
|
||||
## 3. Скачивание репозиториев
|
||||
> ⚠️ Сборку ведём из **локальных** копий репозиториев (COPY в Dockerfile), так как DNS внутри build-контейнера нестабилен.
|
||||
|
||||
```bash
|
||||
mkdir -p /root/awg-src
|
||||
cd /root/awg-src
|
||||
|
||||
# Правильный DNS на хосте LXC
|
||||
echo "nameserver 8.8.8.8" > /etc/resolv.conf
|
||||
|
||||
git clone --depth 1 --branch v3.1.20260828 https://github.com/amnezia-vpn/amneziawg-go.git
|
||||
git clone --depth 1 --branch v3.1.20260812 https://github.com/amnezia-vpn/amneziawg-tools.git
|
||||
```
|
||||
|
||||
**Проверка тегов** (актуальные на момент сборки):
|
||||
```bash
|
||||
git ls-remote --tags https://github.com/amnezia-vpn/amneziawg-go.git | tail
|
||||
# v3.1.20260813, v3.1.20260814, v3.1.20260828
|
||||
git ls-remote --tags https://github.com/amnezia-vpn/amneziawg-tools.git | tail
|
||||
# v3.0.20260805, v3.1.20260812
|
||||
```
|
||||
|
||||
> Найдите **последний** тег v3.1.* — они выходят часто и содержат исправления DPI-обхода.
|
||||
|
||||
---
|
||||
|
||||
## 4. Директория сборки
|
||||
```bash
|
||||
mkdir -p /root/awg-builder
|
||||
cp -r /root/awg-src/amneziawg-go /root/awg-builder/
|
||||
cp -r /root/awg-src/amneziawg-tools /root/awg-builder/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Dockerfile
|
||||
**`/root/awg-builder/Dockerfile`**
|
||||
```dockerfile
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM golang:alpine AS go-build
|
||||
|
||||
RUN apk add --no-cache make gcc musl-dev linux-headers
|
||||
|
||||
COPY amneziawg-go /src/amneziawg-go
|
||||
RUN cd /src/amneziawg-go && make && cp amneziawg-go /go/bin/
|
||||
|
||||
COPY amneziawg-tools /src/amneziawg-tools
|
||||
RUN cd /src/amneziawg-tools/src && make && cp wg /go/bin/awg
|
||||
|
||||
FROM alpine:3.21
|
||||
|
||||
RUN apk add --no-cache iptables ip6tables iproute2 bash openresolv
|
||||
|
||||
COPY --from=go-build /go/bin/amneziawg-go /usr/bin/
|
||||
COPY --from=go-build /go/bin/awg /usr/bin/
|
||||
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
```
|
||||
|
||||
> **Почему `cp wg /go/bin/awg`**: в `amneziawg-tools` бинарь надёжнее назвать `awg`. Это клиентская утилита управления интерфейсом.
|
||||
|
||||
**Healthcheck** (необязателен): добавить в Dockerfile ```HEALTHCHECK``` — можно пропустить, статус смотрим через `awg show`.
|
||||
|
||||
---
|
||||
|
||||
## 6. entrypoint.sh
|
||||
Скрипт: поднимает интерфейс, загружает конфиг (с фолбэком на минимальный), настраивает policy routing и NAT.
|
||||
|
||||
**`/root/awg-builder/entrypoint.sh`**
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
CONFIG_DIR=/config
|
||||
|
||||
for f in "${CONFIG_DIR}"/*.conf; do
|
||||
[ -f "$f" ] || continue
|
||||
IFACE=$(basename "$f" .conf)
|
||||
echo "Starting AmneziaWG interface: ${IFACE}"
|
||||
|
||||
modprobe amneziawg 2>/dev/null || true
|
||||
if ! ip link show "${IFACE}" 2>/dev/null | grep -q UP; then
|
||||
ip link add "${IFACE}" type amneziawg 2>/dev/null || {
|
||||
echo "[*] Using userspace amneziawg-go"
|
||||
amneziawg-go "${IFACE}" 2>/dev/null || true
|
||||
sleep 1
|
||||
}
|
||||
fi
|
||||
|
||||
TMPF=$(mktemp)
|
||||
grep -v -E '^(Address|DNS)' "$f" > "$TMPF"
|
||||
|
||||
if ! awg setconf "${IFACE}" "$TMPF" 2>/dev/null; then
|
||||
echo "[!] Trying minimal config"
|
||||
{
|
||||
echo "[Interface]"
|
||||
grep -E '^PrivateKey' "$f"
|
||||
echo "ListenPort = 51820"
|
||||
echo ""
|
||||
echo "[Peer]"
|
||||
grep -E '^(PublicKey|PresharedKey|AllowedIPs|Endpoint|PersistentKeepalive)' "$f"
|
||||
} | awg setconf "${IFACE}" /dev/stdin 2>/dev/null || {
|
||||
echo "[!] FATAL: cannot parse config"
|
||||
rm -f "$TMPF"
|
||||
continue
|
||||
}
|
||||
fi
|
||||
rm -f "$TMPF"
|
||||
|
||||
IP=$(grep ^Address "$f" | head -1 | cut -d= -f2 | tr -d ' ' | cut -d, -f1)
|
||||
[ -n "$IP" ] && ip addr add "$IP" dev "${IFACE}" 2>/dev/null || true
|
||||
ip link set "${IFACE}" up
|
||||
echo "[*] ${IFACE} UP: ${IP}"
|
||||
done
|
||||
|
||||
# --- Policy routing: только forwarded LAN-трафик через VPN ---
|
||||
mkdir -p /etc/iproute2
|
||||
if ! grep -q "awg-vpn" /etc/iproute2/rt_tables 2>/dev/null; then
|
||||
echo "100 awg-vpn" >> /etc/iproute2/rt_tables 2>/dev/null || true
|
||||
fi
|
||||
|
||||
ip route add 0.0.0.0/0 dev awg0 table 100 2>/dev/null || true
|
||||
|
||||
# Пометить forwarded LAN-трафик (не на LAN) меткой 100
|
||||
iptables -t mangle -C PREROUTING -s 192.168.1.0/24 ! -d 192.168.1.0/24 -j MARK --set-mark 100 2>/dev/null || \
|
||||
iptables -t mangle -A PREROUTING -s 192.168.1.0/24 ! -d 192.168.1.0/24 -j MARK --set-mark 100 2>/dev/null || true
|
||||
|
||||
# Пакеты с меткой 100 → таблица awg-vpn (через awg0)
|
||||
ip rule add fwmark 100 lookup 100 priority 5000 2>/dev/null || true
|
||||
|
||||
# NAT для LAN через туннель
|
||||
iptables -t nat -C POSTROUTING -s 192.168.1.0/24 -o awg0 -j MASQUERADE 2>/dev/null || \
|
||||
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o awg0 -j MASQUERADE 2>/dev/null || true
|
||||
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward 2>/dev/null || true
|
||||
|
||||
echo "[*] AmneziaWG client running"
|
||||
awg show 2>/dev/null || true
|
||||
|
||||
sleep infinity
|
||||
```
|
||||
|
||||
> **Как работает policy routing**:
|
||||
> - Локальный (исходящий) трафик **самого LXC** (SSH и т.д.) → идёт напрямую через `eth0`
|
||||
> - Только **forwarded** трафик из LAN → помечается меткой → направляется в таблицу `awg-vpn` → уходит через `awg0`
|
||||
> - Это сохраняет доступ к управлению LXC, не ломая VPN-шлюз
|
||||
|
||||
---
|
||||
|
||||
## 7. Редактирование сети под свою подсеть
|
||||
|
||||
В скрипте выше я использовал `192.168.1.0/24` — это **основной LAN сегмент**, который пойдёт через VPN.
|
||||
|
||||
**Если нужна отдельная VPN-подсеть** (например `192.168.2.0/24`), замени в двух местах:
|
||||
- `iptables -t mangle ... -s 192.168.1.0/24` → `-s 192.168.2.0/24`
|
||||
- `iptables -t nat ... -s 192.168.1.0/24 ... -o awg0` → `-s 192.168.2.0/24`
|
||||
|
||||
Подробнее про отдельную подсеть см. раздел «Расширенный сценарий» ниже.
|
||||
|
||||
---
|
||||
|
||||
## 8. Запуск
|
||||
|
||||
1. **Создай директорию конфига** и положи туда `.conf`:
|
||||
```bash
|
||||
mkdir -p /root/awg-config
|
||||
cp /путь/к/de.conf /root/awg-config/awg0.conf
|
||||
# ↑ имя файла = имя интерфейса (awg0)
|
||||
```
|
||||
|
||||
2. **Собери образ:**
|
||||
```bash
|
||||
cd /root/awg-builder
|
||||
docker build -t amneziawg-client:latest .
|
||||
```
|
||||
|
||||
3. **Запусти контейнер:**
|
||||
```bash
|
||||
docker run -dit \
|
||||
--name=amneziawg-client \
|
||||
-v /root/awg-config:/config \
|
||||
--network=host \
|
||||
--device=/dev/net/tun:/dev/net/tun \
|
||||
--cap-add=NET_ADMIN \
|
||||
--cap-add=SYS_MODULE \
|
||||
--restart always \
|
||||
amneziawg-client:latest
|
||||
```
|
||||
|
||||
4. **Проверь:**
|
||||
```bash
|
||||
docker ps --filter name=amneziawg-client # Up, restart always
|
||||
docker logs amneziawg-client # интерфейс UP, handshake
|
||||
docker exec amneziawg-client awg show # самый наглядный статус
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Проверка работоспособности
|
||||
|
||||
```bash
|
||||
# Статус интерфейса и handshake (главное)
|
||||
docker exec amneziawg-client awg show
|
||||
# Должно быть: "latest handshake: N seconds ago" и ненулевые transfer
|
||||
|
||||
# Внешний IP с самого LXC (через awg0):
|
||||
curl -s ifconfig.me
|
||||
# Это будет IP VPN-провайдера
|
||||
|
||||
# Статус NAT/маршрутизации
|
||||
docker exec amneziawg-client iptables -t mangle -L PREROUTING -n -v
|
||||
docker exec amneziawg-client iptables -t nat -L POSTROUTING -n -v
|
||||
|
||||
# Проверка forwarded трафика из LAN:
|
||||
# с устройства в 192.168.1.0/24, у которого шлюз = 192.168.1.147
|
||||
curl -s ifconfig.me
|
||||
# Тоже IP VPN-провайдера
|
||||
```
|
||||
|
||||
**Полезный признак нормальной работы:**
|
||||
```
|
||||
peer: FfgUO6z0plGUntTW3T8fsFsZ250GcQZEKlCgj1fkRFc=
|
||||
latest handshake: 42 seconds ago ← периодически обновляется
|
||||
transfer: 1.24 MiB received, 3.2 MiB sent ← данные идут
|
||||
```
|
||||
|
||||
Если `latest handshake` отсутствует и `received = 0` — пакеты не доходят до сервера. Причины: файрвол роутера блокирует UDP, неверный Endpoint в `.conf`, фильтрация DPI.
|
||||
|
||||
---
|
||||
|
||||
## 10. Включение шлюза для LAN
|
||||
|
||||
Когда туннель поднят, чтобы устройства LAN пошли через VPN, на **роутере** меняют шлюз по умолчанию или статический маршрут:
|
||||
|
||||
**Keenetic (веб-интерфейс):**
|
||||
1. `Интернет-центр → Маршрутизация → Статические маршруты`
|
||||
2. Добавить:
|
||||
- Сеть назначения: `0.0.0.0`
|
||||
- Маска: `0.0.0.0`
|
||||
- Шлюз: `192.168.1.147`
|
||||
- (или конкретная VPN-подсеть, если не вся LAN)
|
||||
|
||||
**На телефоне (временная проверка):**
|
||||
- Wi-Fi → IP-настройки → Статический → Маршрутизатор = `192.168.1.147`
|
||||
|
||||
---
|
||||
|
||||
## 11. Питфоллы и их решение
|
||||
|
||||
| Проблема | Причина | Решение |
|
||||
|----------|---------|---------|
|
||||
| `Unknown device type. Falling back to userspace` | Нет модуля ядра amneziawg | Нормально; userspace (amneziawg-go) работает |
|
||||
| `Line unrecognized: S3=145` | Старая версия `awg`, не знает v3.1 параметры | Собрать свежую amneziawg-tools v3.1.x (п.3) |
|
||||
| `Address=/DNS=` line error | `awg setconf` не понимает `wg-quick` директивы | Убрать `Address`/`DNS` из `setconf` (см. entrypoint) |
|
||||
| `/proc/sys/...ip_forward: Read-only` | Ограничение LXC / контейнера | Включить заранее на хосте (п.2) |
|
||||
| Диск забит (`no space left on device`) | Сборки и образы жрут место | `docker system prune`, расширить диск |
|
||||
| `gcc not found` при сборке tools | Нет компилятора | `apk add gcc musl-dev` в Dockerfile |
|
||||
| `linux/types.h` нет | Нужны linux-headers | `apk add linux-headers` |
|
||||
| `cockpit`/быстрые списки GitHub таймаут | DNS внутри build-контейнера | Клонировать на хосте, `COPY` в Dockerfile |
|
||||
|
||||
---
|
||||
|
||||
## 12. Расширенный сценарий: отдельная VPN-подсеть (вариант B)
|
||||
|
||||
Нужно, чтобы не вся LAN уходила в VPN, а только отдельные устройства в своей подсети (`192.168.2.0/24`).
|
||||
|
||||
**На LXC добавить alias-IP шлюза:**
|
||||
```bash
|
||||
ip addr add 192.168.2.1/32 dev eth0
|
||||
# persistence: netplan / LXC interface
|
||||
```
|
||||
|
||||
**entrypoint.sh — расширить маршрутизацию:**
|
||||
```bash
|
||||
# Вторая подсеть → тоже через VPN
|
||||
iptables -t mangle -A PREROUTING -s 192.168.2.0/24 ! -d 192.168.2.0/24 -j MARK --set-mark 100
|
||||
iptables -t nat -A POSTROUTING -s 192.168.2.0/24 -o awg0 -j MASQUERADE
|
||||
```
|
||||
|
||||
**DHCP сервер для 192.168.2.0/24** (dnsmasq на LXC или Docker):
|
||||
```
|
||||
interface=eth0
|
||||
dhcp-range=192.168.2.100,192.168.2.200,255.255.255.0,24h
|
||||
dhcp-option=3,192.168.2.1
|
||||
dhcp-option=6,100.64.0.1,8.8.8.8
|
||||
```
|
||||
|
||||
**Keenetic — статический маршрут:**
|
||||
- Сеть: `192.168.2.0`, маска `255.255.255.0`, шлюз `192.168.1.147`
|
||||
|
||||
**Keenetic — гостевая сеть с другой подсетью:**
|
||||
- Создать вторую SSID, IP `192.168.2.1/24`, DHCP `192.168.2.x`
|
||||
|
||||
---
|
||||
|
||||
## 13. Обновление версий AWG
|
||||
|
||||
Поскольку AmneziaWG 3.x развивается быстро (новые теги), при проблемах с DPI-блокировками:
|
||||
|
||||
```bash
|
||||
# Узнать свежие теги
|
||||
git ls-remote --tags https://github.com/amnezia-vpn/amneziawg-go.git | tail
|
||||
git ls-remote --tags https://github.com/amnezia-vpn/amneziawg-tools.git | tail
|
||||
|
||||
# Пересобрать из свежих копий
|
||||
cd /root/awg-src/amneziawg-go && git fetch --tags && git checkout v3.1.XXXXXXX
|
||||
cd /root/awg-src/amneziawg-tools && git fetch --tags && git checkout v3.1.XXXXXXX
|
||||
cp -r /root/awg-src/amneziawg-*/* /root/awg-builder/
|
||||
docker build -t amneziawg-client:latest /root/awg-builder/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. Безопасность и данные
|
||||
|
||||
- **Приватный ключ** в `.conf` не попадает в логи/память ассистента — только в файл на сервере.
|
||||
- Не выкладывай `.conf` в чат, репозитории, скриншоты.
|
||||
- `.conf` читается из `/root/awg-config/awg0.conf` только контейнером.
|
||||
- Права: `chmod 600 /root/awg-config/awg0.conf`.
|
||||
|
||||
---
|
||||
|
||||
## Итоговая структура файлов
|
||||
|
||||
```
|
||||
/root/awg-config/awg0.conf ← твой .conf (private)
|
||||
/root/awg-builder/Dockerfile
|
||||
/root/awg-builder/entrypoint.sh
|
||||
/root/awg-builder/amneziawg-go/ ← исходники (3.1.20260828)
|
||||
/root/awg-builder/amneziawg-tools/ ← исходники (3.1.20260812)
|
||||
/root/awg-src/ ← свежие клоны (для апдейтов)
|
||||
```
|
||||
|
||||
**Контейнер:** `amneziawg-client` = полностью автономный AWG-шлюз, ставится как `--restart always`, не зависит от остальных Docker-сервисов.
|
||||
Reference in New Issue
Block a user