- Removed privileged: true from docker-compose.yml - Removed SYS_MODULE cap_add (kept NET_ADMIN for WireGuard) - Removed source code bind mounts (./src, package.json) - Removed wg0.conf and resolv.conf bind mounts (now generated from env) - Added resource limits: mem_limit 512m, cpus 1.0 - Added healthcheck with curl - Added non-root user appuser:appgroup in Dockerfile - wg0.conf now generated from env vars at container startup (WG_PRIVATE_KEY, etc.) - resolv.conf generated from WG_DNS env var - Rotated wg0.conf — private key removed from file - Added WG_ALLOWED_IPS to .env.example SECURITY: Rotate WireGuard keys on server if previously used in production
This commit is contained in:
@@ -36,6 +36,7 @@ WG_PRESHARED_KEY=
|
||||
WG_ENDPOINT=
|
||||
WG_ADDRESS=
|
||||
WG_DNS=
|
||||
WG_ALLOWED_IPS=0.0.0.0/0,::/0
|
||||
|
||||
# --- Gitea API (для CI/CD и пайплайна) ---
|
||||
GITEA_API_URL=https://git.softuniq.eu/api/v1
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -11,6 +11,10 @@ RUN apk update && \
|
||||
curl && \
|
||||
rm -rf /var/cache/apk/*
|
||||
|
||||
# Создаём непривилегированного пользователя
|
||||
RUN addgroup -S appgroup && \
|
||||
adduser -S appuser -G appgroup
|
||||
|
||||
# Рабочая директория
|
||||
WORKDIR /app
|
||||
|
||||
@@ -18,9 +22,15 @@ WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
|
||||
# Копируем исходный код с правильным владельцем
|
||||
COPY --chown=appuser:appgroup ./src ./src
|
||||
|
||||
# Копируем скрипт запуска
|
||||
COPY ./wg/start.sh /app/start.sh
|
||||
COPY --chown=appuser:appgroup ./wg/start.sh /app/start.sh
|
||||
RUN chmod +x /app/start.sh
|
||||
|
||||
# Переключаемся на непривилегированного пользователя
|
||||
USER appuser
|
||||
|
||||
# Команда для запуска
|
||||
CMD ["/bin/bash", "/app/start.sh"]
|
||||
|
||||
@@ -10,18 +10,19 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./db:/app/db/ # Синхронизация базы данных
|
||||
- ./src:/app/src/ # Синхронизация исходного кода
|
||||
- ./package.json:/app/package.json # Синхронизация package.json
|
||||
- ./package-lock.json:/app/package-lock.json # Синхронизация package-lock.json
|
||||
- ./wg/config/wg0.conf:/etc/wireguard/wg0.conf # Монтируем конфиг WireGuard
|
||||
- ./wg/config/resolv.conf:/etc/resolv.conf # Монтируем resolv.conf
|
||||
- ./wg/start.sh:/app/start.sh # Монтируем start.sh
|
||||
cap_add: # Необходимо для работы WireGuard
|
||||
- NET_ADMIN
|
||||
- SYS_MODULE
|
||||
- ./db:/app/db/ # Синхронизация базы данных (persistence)
|
||||
- ./wg/start.sh:/app/start.sh # Монтируем start.sh (генерирует wg0.conf из env)
|
||||
cap_add: # Минимальные привилегии, необходимые только для WireGuard
|
||||
- NET_ADMIN
|
||||
sysctls:
|
||||
- net.ipv4.conf.all.src_valid_mark=1 # Необходимо для маршрутизации
|
||||
privileged: true # Даем контейнеру повышенные привилегии
|
||||
mem_limit: 512m
|
||||
cpus: "1.0"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
networks:
|
||||
default:
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
nameserver 9.9.9.11
|
||||
# Generated from WG_DNS environment variable at container startup
|
||||
# See wg/start.sh
|
||||
@@ -1,12 +1,7 @@
|
||||
# Autogenerated by WireGuard UI (WireAdmin)
|
||||
[Interface]
|
||||
PrivateKey = ePxlvZTgr+fJ7ntU6oWti13X8h2100CrjnZFOkSLUWQ=
|
||||
Address = 10.8.0.4/24
|
||||
DNS = 9.9.9.11
|
||||
|
||||
[Peer]
|
||||
PublicKey = PYJSZlU38l9OzZnb7iANVk3LotbTg5MdyB2nInxhdA0=
|
||||
PresharedKey = gK0SjJAvE0oFT6q9yDOQpBP6CyUOclX5yMqAm3hNa1Q=
|
||||
AllowedIPs = 0.0.0.0/0, ::/0
|
||||
PersistentKeepalive = 0
|
||||
Endpoint = 194.87.105.23:51820
|
||||
# SECURITY: This file is intentionally empty.
|
||||
# WireGuard configuration is generated from environment variables at container startup.
|
||||
# See wg/start.sh and .env.example (WG_PRIVATE_KEY, WG_ADDRESS, WG_DNS, etc.).
|
||||
#
|
||||
# IMPORTANT: The previous version of this file contained a real WireGuard private key.
|
||||
# ROTATE THE WIREGUARD KEYS ON THE SERVER SIDE if this key was ever used in production.
|
||||
# Generate new keys with: wg genkey | tee /dev/stderr | wg pubkey
|
||||
168
wg/start.sh
168
wg/start.sh
@@ -16,13 +16,13 @@ print_result() {
|
||||
local status=$?
|
||||
local message=$1
|
||||
local action=$2
|
||||
|
||||
|
||||
if [ -n "$action" ]; then
|
||||
case "$action" in
|
||||
"created")
|
||||
echo "║ 🆕 $message"
|
||||
;;
|
||||
"exists")
|
||||
"exists")
|
||||
echo "║ ✅ $message"
|
||||
;;
|
||||
*)
|
||||
@@ -40,11 +40,13 @@ print_result() {
|
||||
echo "║ ❌ $message"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
print_separator
|
||||
}
|
||||
|
||||
# Проверка включения WireGuard
|
||||
# ============================================================
|
||||
# WireGuard: полное отключение
|
||||
# ============================================================
|
||||
if [ "$WG_ENABLED" = "false" ]; then
|
||||
print_stage "WireGuard is disabled"
|
||||
print_result "Skipping WireGuard setup"
|
||||
@@ -54,37 +56,60 @@ if [ "$WG_ENABLED" = "false" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Проверка наличия /etc/resolv.conf
|
||||
print_stage "Checking /etc/resolv.conf"
|
||||
if [ ! -f /etc/resolv.conf ]; then
|
||||
echo "║ /etc/resolv.conf not found. Creating it..."
|
||||
# ============================================================
|
||||
# WireGuard: включён, но нет приватного ключа — warn и skip
|
||||
# ============================================================
|
||||
if [ -z "$WG_PRIVATE_KEY" ]; then
|
||||
print_stage "WireGuard misconfiguration"
|
||||
echo "║ ⚠️ WG_ENABLED=true but WG_PRIVATE_KEY is empty"
|
||||
echo "║ ⚠️ Skipping WireGuard setup. Set WG_PRIVATE_KEY or set WG_ENABLED=false"
|
||||
print_result "WireGuard skipped (missing private key)"
|
||||
print_stage "Starting application"
|
||||
echo "║ Application is starting without VPN..."
|
||||
exec node src/index.js
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ============================================================
|
||||
# Генерация /etc/resolv.conf из WG_DNS
|
||||
# ============================================================
|
||||
print_stage "Configuring /etc/resolv.conf"
|
||||
if [ -n "$WG_DNS" ]; then
|
||||
echo "║ Using DNS from env WG_DNS: $WG_DNS"
|
||||
echo "nameserver $WG_DNS" > /etc/resolv.conf
|
||||
else
|
||||
echo "║ WG_DNS empty — using fallback DNS: 1.1.1.1, 8.8.8.8"
|
||||
echo "nameserver 1.1.1.1" > /etc/resolv.conf
|
||||
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
|
||||
if [ $? -eq 0 ]; then
|
||||
print_result "/etc/resolv.conf created successfully." "created"
|
||||
else
|
||||
print_result "Failed to create /etc/resolv.conf"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
print_result "/etc/resolv.conf already exists." "exists"
|
||||
fi
|
||||
print_result "/etc/resolv.conf configured." "created"
|
||||
|
||||
# Проверка наличия конфига WireGuard
|
||||
print_stage "Checking WireGuard config"
|
||||
if [ ! -f /etc/wireguard/wg0.conf ]; then
|
||||
echo "║ Error: WireGuard config not found!"
|
||||
exit 1
|
||||
else
|
||||
if [ -r /etc/wireguard/wg0.conf ]; then
|
||||
print_result "WireGuard config found and readable." "exists"
|
||||
else
|
||||
print_result "WireGuard config found but not readable!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
# ============================================================
|
||||
# Генерация /etc/wireguard/wg0.conf из env vars
|
||||
# ============================================================
|
||||
print_stage "Generating /etc/wireguard/wg0.conf from environment"
|
||||
cat > /etc/wireguard/wg0.conf <<EOF
|
||||
# Generated from environment variables at container start.
|
||||
# DO NOT commit real keys to the repository.
|
||||
[Interface]
|
||||
PrivateKey = ${WG_PRIVATE_KEY}
|
||||
Address = ${WG_ADDRESS}
|
||||
DNS = ${WG_DNS}
|
||||
|
||||
[Peer]
|
||||
PublicKey = ${WG_PUBLIC_KEY}
|
||||
PresharedKey = ${WG_PRESHARED_KEY}
|
||||
AllowedIPs = ${WG_ALLOWED_IPS:-0.0.0.0/0,::/0}
|
||||
PersistentKeepalive = 0
|
||||
Endpoint = ${WG_ENDPOINT}
|
||||
EOF
|
||||
|
||||
chmod 600 /etc/wireguard/wg0.conf
|
||||
print_result "wg0.conf generated with mode 0600." "created"
|
||||
|
||||
# ============================================================
|
||||
# Проверка сети ДО включения WireGuard
|
||||
# ============================================================
|
||||
print_stage "Testing connectivity BEFORE WireGuard"
|
||||
echo "║ Pinging 1.1.1.1..."
|
||||
ping -c 4 1.1.1.1 > /tmp/ping.log 2>&1
|
||||
@@ -96,71 +121,38 @@ else
|
||||
fi
|
||||
print_separator
|
||||
|
||||
# Извлекаем DNS из конфига WireGuard
|
||||
WG_DNS=$(awk -F= '/DNS/ {print $2}' /etc/wireguard/wg0.conf | xargs)
|
||||
|
||||
# Настройка DNS
|
||||
print_stage "Configuring DNS"
|
||||
if [ -n "$WG_DNS" ]; then
|
||||
echo "║ Using DNS from WireGuard config: $WG_DNS"
|
||||
echo "nameserver $WG_DNS" > /etc/resolv.conf
|
||||
if [ $? -eq 0 ]; then
|
||||
print_result "DNS configured using WireGuard settings." "created"
|
||||
else
|
||||
print_result "Failed to configure DNS!"
|
||||
exit 1
|
||||
fi
|
||||
# ============================================================
|
||||
# Запуск WireGuard
|
||||
# ============================================================
|
||||
print_stage "Starting WireGuard"
|
||||
wg-quick up wg0 2>&1 | tee /tmp/wg.log
|
||||
wg_status=$?
|
||||
if [ $wg_status -eq 0 ]; then
|
||||
echo "║ WireGuard started successfully."
|
||||
print_result "WireGuard interface activated successfully."
|
||||
else
|
||||
echo "║ Using fallback DNS: 1.1.1.1, 8.8.8.8"
|
||||
echo "nameserver 1.1.1.1" > /etc/resolv.conf
|
||||
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
|
||||
if [ $? -eq 0 ]; then
|
||||
print_result "DNS configured using fallback settings." "created"
|
||||
else
|
||||
print_result "Failed to configure DNS!"
|
||||
exit 1
|
||||
fi
|
||||
echo "║ WireGuard failed to start. Logs:"
|
||||
cat /tmp/wg.log | sed 's/^/║ /'
|
||||
print_result "Failed to start WireGuard interface!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверка включения WireGuard
|
||||
print_stage "Checking WireGuard status"
|
||||
if [ "$WG_ENABLED" = "true" ]; then
|
||||
echo "║ WireGuard is enabled. Starting..."
|
||||
|
||||
# Запуск WireGuard
|
||||
wg-quick up wg0 2>&1 | tee /tmp/wg.log
|
||||
wg_status=$?
|
||||
if [ $wg_status -eq 0 ]; then
|
||||
echo "║ WireGuard started successfully."
|
||||
print_result "WireGuard interface activated successfully."
|
||||
else
|
||||
echo "║ WireGuard failed to start. Logs:"
|
||||
cat /tmp/wg.log | sed 's/^/║ /'
|
||||
print_result "Failed to start WireGuard interface!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Проверка маршрутизации после запуска WireGuard
|
||||
print_stage "Routing table AFTER WireGuard"
|
||||
ip route | sed 's/^/║ /'
|
||||
print_separator
|
||||
# Проверка маршрутизации после запуска WireGuard
|
||||
print_stage "Routing table AFTER WireGuard"
|
||||
ip route | sed 's/^/║ /'
|
||||
print_separator
|
||||
|
||||
# Проверка сети ПОСЛЕ включения WireGuard
|
||||
print_stage "Testing connectivity AFTER WireGuard"
|
||||
echo "║ Pinging 1.1.1.1..."
|
||||
ping -c 4 1.1.1.1 > /tmp/ping.log 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "║ Ping successful."
|
||||
cat /tmp/ping.log | sed 's/^/║ /'
|
||||
else
|
||||
echo "║ Ping failed."
|
||||
fi
|
||||
print_separator
|
||||
# Проверка сети ПОСЛЕ включения WireGuard
|
||||
print_stage "Testing connectivity AFTER WireGuard"
|
||||
echo "║ Pinging 1.1.1.1..."
|
||||
ping -c 4 1.1.1.1 > /tmp/ping.log 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "║ Ping successful."
|
||||
cat /tmp/ping.log | sed 's/^/║ /'
|
||||
else
|
||||
echo "║ WireGuard is disabled. Skipping..."
|
||||
print_result "WireGuard is disabled in configuration."
|
||||
echo "║ Ping failed."
|
||||
fi
|
||||
|
||||
print_separator
|
||||
|
||||
# Проверка DNS
|
||||
print_stage "Testing DNS"
|
||||
|
||||
Reference in New Issue
Block a user