feat: add deployment hardening from production experience
- Add IP forwarding setup (sysctl) to install.sh — container can't write /proc/sys, must be done on host - Add host-level WireGuard detection and auto-stop in install.sh - Update key exchange instructions: 2-step process (server first, then client, then restart server with client key) - Add deployment nuances section to README (ip_forward, wg0 cleanup, compose version warning, key exchange, network_mode, iptables order) - Add production deployment notes to .env.example - Remove obsolete compose version warnings noted during deployment
This commit is contained in:
14
.env.example
14
.env.example
@@ -44,3 +44,17 @@ CLIENT_WG_IP=10.0.0.2
|
||||
|
||||
# Интервал Keepalive в секундах (оптимизировано для Starlink, по умолчанию 21)
|
||||
PERSISTENT_KEEPALIVE=21
|
||||
|
||||
# ── Важные замечания по развёртыванию ──────────────────────────────────────
|
||||
# 1. На VPS: включите IP-форвардинг на хосте (контейнер не может /proc/sys):
|
||||
# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf && sysctl -p
|
||||
# 2. Ключи генерируются автоматически при первом запуске.
|
||||
# Сервер: /etc/wireguard/server_private.key, server_public.key
|
||||
# Клиент: /etc/wireguard/client_private.key, client_public.key
|
||||
# 3. После первого запуска сервера скопируйте SERVER_PUBLIC_KEY в .env клиента.
|
||||
# 4. После первого запуска клиента скопируйте CLIENT_PUBLIC_KEY в .env сервера.
|
||||
# 5. Перезапустите контейнеры после обновления ключей:
|
||||
# docker compose -f docker-compose.server.yml restart (на VPS)
|
||||
# docker compose -f docker-compose.client.yml restart (на RPi)
|
||||
# 6. Контейнер использует network_mode: host — порты пробрасываются
|
||||
# через iptables DNAT, а не через Docker port mapping.
|
||||
70
README.md
70
README.md
@@ -414,6 +414,76 @@ wireguard-vps-tunnel/
|
||||
└── README.md # Документация
|
||||
```
|
||||
|
||||
## Нюансы развёртывания (выявлены на практике)
|
||||
|
||||
### 1. IP-форвардинг на хосте (обязательно)
|
||||
|
||||
Контейнер не может записать в `/proc/sys/net/ipv4/ip_forward` (read-only в Docker). Включите на хосте:
|
||||
|
||||
```bash
|
||||
# Временно
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding
|
||||
|
||||
# Постоянно
|
||||
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
|
||||
echo 'net.ipv6.conf.all.forwarding = 1' >> /etc/sysctl.conf
|
||||
sysctl -p
|
||||
```
|
||||
|
||||
Без этого DNAT-трафик не будет перенаправляться.
|
||||
|
||||
### 2. Обмен ключами: двухэтапный запуск
|
||||
|
||||
Ключи генерируются **внутри контейнера** при первом запуске. Поэтому:
|
||||
|
||||
1. Запустите сервер → он сгенерирует ключи и выведет `SERVER_PUBLIC_KEY=...`
|
||||
2. Впишите `SERVER_PUBLIC_KEY` в `.env` на клиенте
|
||||
3. Запустите клиент → он выведет `CLIENT_PUBLIC_KEY=...`
|
||||
4. Впишите `CLIENT_PUBLIC_KEY` в `.env` на сервере
|
||||
5. Перезапустите сервер: `docker compose -f docker-compose.server.yml restart`
|
||||
|
||||
Конфигурация `wg0.conf` пересоздаётся при каждом перезапуске, поэтому обновление ключей не требует ручного редактирования.
|
||||
|
||||
### 3. Удаление старого интерфейса wg0
|
||||
|
||||
При перезапуске контейнера интерфейс `wg0` может остаться от предыдущего запуска. Entrypoint автоматически удаляет его перед запуском `wg-quick up`. Если на хосте остался host-level WireGuard — остановите его:
|
||||
|
||||
```bash
|
||||
systemctl stop wg-quick@wg0
|
||||
systemctl disable wg-quick@wg0
|
||||
ip link del wg0 2>/dev/null
|
||||
rm -f /etc/wireguard/wg0.conf
|
||||
```
|
||||
|
||||
### 4. Docker Compose `version` устарел
|
||||
|
||||
Поле `version: "3.8"` в docker-compose вызывает предупреждение:
|
||||
`the attribute 'version' is obsolete`. Оно удалено из файлов проекта.
|
||||
Если вы видите это предупреждение — просто удалите строку `version:` из compose-файла.
|
||||
|
||||
### 5. Multi-arch сборка требует Buildx
|
||||
|
||||
Стандартный `docker build` не поддерживает `platforms: linux/amd64,linux/arm64`.
|
||||
Для multi-arch сборки через CI/CD используется Docker Buildx с QEMU.
|
||||
Для локальной сборки на текущей архитектуре достаточно убрать `platforms:` из compose-файла.
|
||||
|
||||
### 6. network_mode: host и порты
|
||||
|
||||
Контейнеры используют `network_mode: host`. Секция `ports:` в compose-файле игнорируется (Docker выведет предупреждение). Все порты доступны напрямую через iptables DNAT.
|
||||
|
||||
### 7. Конфликт с Docker iptables
|
||||
|
||||
Правила DNAT вставляются через `iptables -I FORWARD 1` — **перед** цепочкой DOCKER-USER.
|
||||
Это гарантирует, что WireGuard-трафик не блокируется Docker. Не меняйте приоритет
|
||||
без необходимости.
|
||||
|
||||
### 8. Парольная аутентификация SSH
|
||||
|
||||
Скрипт **НЕ отключает** `PasswordAuthentication` в sshd. Если вы хотите отключить,
|
||||
сделайте это вручную и обязательно добавьте SSH-ключ в `authorized_keys` **до**
|
||||
отключения пароля, иначе потеряете доступ.
|
||||
|
||||
## Поддерживаемые ОС
|
||||
|
||||
- Любой Linux с Docker 20.10+
|
||||
|
||||
65
install.sh
65
install.sh
@@ -91,6 +91,50 @@ install_docker() {
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Включение IP-форвардинга (обязательно для VPS) ──────────────────────────
|
||||
enable_ip_forwarding() {
|
||||
header "Настройка IP-форвардинга"
|
||||
|
||||
# Включить временно
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward 2>/dev/null || true
|
||||
echo 1 > /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || true
|
||||
|
||||
# Включить постоянно
|
||||
if ! grep -q "net.ipv4.ip_forward" /etc/sysctl.conf 2>/dev/null; then
|
||||
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
|
||||
else
|
||||
sed -i 's/.*net.ipv4.ip_forward.*/net.ipv4.ip_forward = 1/' /etc/sysctl.conf
|
||||
fi
|
||||
|
||||
if ! grep -q "net.ipv6.conf.all.forwarding" /etc/sysctl.conf 2>/dev/null; then
|
||||
echo "net.ipv6.conf.all.forwarding = 1" >> /etc/sysctl.conf
|
||||
else
|
||||
sed -i 's/.*net.ipv6.conf.all.forwarding.*/net.ipv6.conf.all.forwarding = 1/' /etc/sysctl.conf
|
||||
fi
|
||||
|
||||
sysctl -p 2>/dev/null || true
|
||||
|
||||
success "IP-форвардинг включён"
|
||||
}
|
||||
|
||||
# ── Остановка host-level WireGuard ────────────────────────────────────────
|
||||
stop_host_wireguard() {
|
||||
if systemctl is-active --quiet wg-quick@wg0 2>/dev/null; then
|
||||
warn "Обнаружен host-level WireGuard (wg-quick@wg0). Останавливаем..."
|
||||
systemctl stop wg-quick@wg0 2>/dev/null || true
|
||||
systemctl disable wg-quick@wg0 2>/dev/null || true
|
||||
ip link del wg0 2>/dev/null || true
|
||||
success "Host-level WireGuard остановлен и отключён"
|
||||
fi
|
||||
|
||||
# Остановить watchdog если есть
|
||||
if systemctl is-active --quiet wg-watchdog 2>/dev/null; then
|
||||
systemctl stop wg-watchdog 2>/dev/null || true
|
||||
systemctl disable wg-watchdog 2>/dev/null || true
|
||||
success "wg-watchdog остановлен"
|
||||
fi
|
||||
}
|
||||
|
||||
# ── Генерация ключей WireGuard ─────────────────────────────────────────────
|
||||
generate_keys() {
|
||||
header "Генерация ключей WireGuard"
|
||||
@@ -335,6 +379,8 @@ print_summary() {
|
||||
|
||||
if [[ "$MODE" == "vps" ]]; then
|
||||
echo -e "${BOLD}Проброс портов:${NC} ${PORTS} → ${CLIENT_WG_IP}"
|
||||
echo ""
|
||||
echo -e "${GREEN}${BOLD}✅ IP-форвардинг включён (net.ipv4.ip_forward=1)${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -355,11 +401,14 @@ print_summary() {
|
||||
|
||||
if [[ "$MODE" == "vps" ]]; then
|
||||
echo ""
|
||||
echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Скопируйте публичный ключ сервера на клиент:${NC}"
|
||||
echo -e " ${BOLD}cat ${CONFIG_DIR}/server_public.key${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Затем на клиенте (RPi):${NC}"
|
||||
echo -e " ${BOLD}sudo ./install.sh --client --vps-ip ${VPS_PUBLIC_IP}${NC}"
|
||||
echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Двухэтапный обмен ключами:${NC}"
|
||||
echo -e " 1. Запишите публичный ключ сервера:"
|
||||
echo -e " ${BOLD}cat ${CONFIG_DIR}/server_public.key${NC}"
|
||||
echo -e " 2. Передайте его на клиент (в .env как SERVER_PUBLIC_KEY)"
|
||||
echo -e " 3. После запуска клиента, получите CLIENT_PUBLIC_KEY:"
|
||||
echo -e " ${BOLD}cat ${CONFIG_DIR}/client_public.key${NC} (на клиенте)"
|
||||
echo -e " 4. Впишите CLIENT_PUBLIC_KEY в .env на VPS и перезапустите:"
|
||||
echo -e " ${BOLD}docker compose -f docker-compose.server.yml restart${NC}"
|
||||
else
|
||||
echo ""
|
||||
echo -e "${YELLOW}${BOLD}⚠️ ВАЖНО:${NC} ${YELLOW}Скопируйте публичный ключ клиента на VPS:${NC}"
|
||||
@@ -367,6 +416,8 @@ print_summary() {
|
||||
echo ""
|
||||
echo -e "${YELLOW}И добавьте в .env на VPS:${NC}"
|
||||
echo -e " ${BOLD}CLIENT_PUBLIC_KEY=<ключ>${NC}"
|
||||
echo -e "${YELLOW}Затем перезапустите сервер:${NC}"
|
||||
echo -e " ${BOLD}docker compose -f docker-compose.server.yml restart${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
@@ -403,8 +454,12 @@ main() {
|
||||
fi
|
||||
|
||||
install_docker
|
||||
stop_host_wireguard
|
||||
generate_keys
|
||||
create_env_file
|
||||
if [[ "$MODE" == "vps" ]]; then
|
||||
enable_ip_forwarding
|
||||
fi
|
||||
start_docker
|
||||
print_summary
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user