Server: replace wireguard-ui with built-in wg-admin-gui + PostgreSQL
This commit is contained in:
@@ -23,12 +23,12 @@ GUI_PORT="5000"
|
||||
GUI_USER="admin"
|
||||
GUI_PASSWORD=""
|
||||
GUI_PASSWORD_GENERATED=0
|
||||
GUI_SESSION_SECRET=""
|
||||
GUI_RESET_DB="no"
|
||||
GUI_DB_PASSWORD=""
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Установка WireGuard-сервера и GUI (Debian/Ubuntu).
|
||||
Установка WireGuard-сервера и встроенного WG Admin GUI (Debian/Ubuntu).
|
||||
Каждый запуск выполняет полный reset прошлой инсталляции и поднимает все с нуля.
|
||||
|
||||
Использование:
|
||||
@@ -44,12 +44,12 @@ usage() {
|
||||
--server-dns <ip> DNS для клиентов (по умолчанию: 1.1.1.1)
|
||||
--default-iface <iface> Внешний интерфейс для NAT
|
||||
|
||||
--gui-enable <yes|no> Включить GUI wireguard-ui (по умолчанию: yes)
|
||||
--gui-enable <yes|no> Включить WG Admin GUI (по умолчанию: yes)
|
||||
--gui-host <host> Домен/IP для открытия GUI
|
||||
--gui-port <port> Порт GUI (по умолчанию: 5000)
|
||||
--gui-user <user> Логин GUI (по умолчанию: admin)
|
||||
--gui-password <pass> Пароль GUI (если не указан, будет запрос)
|
||||
--gui-reset-db <yes|no> Устарело: теперь reset GUI выполняется автоматически
|
||||
--gui-password <pass> Пароль GUI (если не указан, будет сгенерирован)
|
||||
--gui-reset-db <yes|no> Устарело: reset БД теперь выполняется автоматически
|
||||
|
||||
-h, --help Показать помощь
|
||||
USAGE
|
||||
@@ -116,6 +116,16 @@ validate_inputs() {
|
||||
fi
|
||||
}
|
||||
|
||||
detect_compose_cmd() {
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(docker compose)
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
COMPOSE_CMD=(docker-compose)
|
||||
else
|
||||
die "Не найден docker compose. Установите docker-compose-plugin или docker-compose."
|
||||
fi
|
||||
}
|
||||
|
||||
reset_existing_install() {
|
||||
log_warn "Выполняю полный reset предыдущей инсталляции WireGuard/GUI"
|
||||
|
||||
@@ -135,16 +145,25 @@ reset_existing_install() {
|
||||
log_info "Очищены конфиги/ключи WireGuard в /etc/wireguard"
|
||||
fi
|
||||
|
||||
systemctl disable --now wg-admin-gui.service >/dev/null 2>&1 || true
|
||||
rm -f /etc/systemd/system/wg-admin-gui.service
|
||||
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
if [[ -f /opt/wireguard-ui/docker-compose.yml ]]; then
|
||||
(cd /opt/wireguard-ui && docker compose down --remove-orphans >/dev/null 2>&1) || true
|
||||
(cd /opt/wireguard-ui && docker-compose down --remove-orphans >/dev/null 2>&1) || true
|
||||
if [[ -f /opt/wg-admin-gui/docker-compose.yml ]]; then
|
||||
detect_compose_cmd
|
||||
(cd /opt/wg-admin-gui && "${COMPOSE_CMD[@]}" down --remove-orphans >/dev/null 2>&1) || true
|
||||
fi
|
||||
docker rm -f wireguard-ui >/dev/null 2>&1 || true
|
||||
|
||||
if [[ -f /opt/wireguard-ui/docker-compose.yml ]]; then
|
||||
detect_compose_cmd
|
||||
(cd /opt/wireguard-ui && "${COMPOSE_CMD[@]}" down --remove-orphans >/dev/null 2>&1) || true
|
||||
fi
|
||||
|
||||
docker rm -f wireguard-ui wg-admin-postgres >/dev/null 2>&1 || true
|
||||
fi
|
||||
|
||||
rm -rf /opt/wireguard-ui/db/* /opt/wireguard-ui/data/* /opt/wireguard-ui/docker-compose.yml
|
||||
log_info "Очищено состояние GUI в /opt/wireguard-ui"
|
||||
rm -rf /opt/wireguard-ui /opt/wg-admin-gui
|
||||
log_info "Очищено состояние GUI"
|
||||
}
|
||||
|
||||
collect_inputs() {
|
||||
@@ -174,9 +193,9 @@ collect_inputs() {
|
||||
|
||||
if [[ "$GUI_ENABLE" == "yes" ]]; then
|
||||
if [[ -z "$GUI_PASSWORD" ]]; then
|
||||
GUI_PASSWORD="$(random_alnum 8)"
|
||||
GUI_PASSWORD="$(random_alnum 10)"
|
||||
GUI_PASSWORD_GENERATED=1
|
||||
log_warn "Пароль GUI не задан. Сгенерирован пароль (8 символов): ${GUI_PASSWORD}"
|
||||
log_warn "Пароль GUI не задан. Сгенерирован пароль: ${GUI_PASSWORD}"
|
||||
|
||||
if (( ! NON_INTERACTIVE )); then
|
||||
local replace_or_password=""
|
||||
@@ -187,8 +206,6 @@ collect_inputs() {
|
||||
if [[ -n "$custom_gui_password" ]]; then
|
||||
GUI_PASSWORD="$custom_gui_password"
|
||||
GUI_PASSWORD_GENERATED=0
|
||||
else
|
||||
log_warn "Пустой пароль не принят. Остается сгенерированный пароль."
|
||||
fi
|
||||
elif [[ -n "$replace_or_password" && ! "$replace_or_password" =~ ^([nN][oO]?|[nN])$ ]]; then
|
||||
GUI_PASSWORD="$replace_or_password"
|
||||
@@ -196,11 +213,9 @@ collect_inputs() {
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
GUI_SESSION_SECRET="$(random_alnum 32)"
|
||||
|
||||
GUI_DB_PASSWORD="$(random_alnum 24)"
|
||||
[[ "$GUI_RESET_DB" == "yes" || "$GUI_RESET_DB" == "no" ]] || die "--gui-reset-db должен быть yes или no"
|
||||
if [[ "$GUI_RESET_DB" == "yes" ]]; then
|
||||
log_warn "--gui-reset-db устарел: очистка GUI теперь выполняется автоматически на каждом запуске."
|
||||
fi
|
||||
fi
|
||||
|
||||
validate_inputs
|
||||
@@ -209,7 +224,7 @@ collect_inputs() {
|
||||
install_packages() {
|
||||
apt_install_if_missing \
|
||||
wireguard wireguard-tools iproute2 iptables curl ca-certificates openssl \
|
||||
qrencode docker.io
|
||||
docker.io python3 python3-venv python3-pip
|
||||
|
||||
if apt-cache show docker-compose-plugin >/dev/null 2>&1; then
|
||||
apt_install_if_missing docker-compose-plugin
|
||||
@@ -237,19 +252,12 @@ setup_keys() {
|
||||
local priv="/etc/wireguard/server_private.key"
|
||||
local pub="/etc/wireguard/server_public.key"
|
||||
|
||||
if [[ ! -f "$priv" ]]; then
|
||||
umask 077
|
||||
wg genkey | tee "$priv" | wg pubkey > "$pub"
|
||||
log_success "Сгенерированы ключи сервера"
|
||||
else
|
||||
if [[ ! -f "$pub" ]]; then
|
||||
wg pubkey < "$priv" > "$pub"
|
||||
fi
|
||||
log_info "Ключи сервера уже существуют, переиспользую"
|
||||
fi
|
||||
umask 077
|
||||
wg genkey | tee "$priv" | wg pubkey > "$pub"
|
||||
|
||||
safe_chmod_600 "$priv"
|
||||
safe_chmod_600 "$pub"
|
||||
log_success "Сгенерированы ключи сервера"
|
||||
}
|
||||
|
||||
setup_wg_config() {
|
||||
@@ -363,75 +371,69 @@ EOF_SYNC_PATH
|
||||
setup_gui() {
|
||||
[[ "$GUI_ENABLE" == "yes" ]] || { log_warn "GUI отключен (GUI_ENABLE=no)"; return; }
|
||||
|
||||
mkdir -p /opt/wireguard-ui/{db,data}
|
||||
safe_chmod_700 /opt/wireguard-ui
|
||||
mkdir -p /opt/wg-admin-gui/{app,pgdata}
|
||||
safe_chmod_700 /opt/wg-admin-gui
|
||||
|
||||
cat > /opt/wireguard-ui/docker-compose.yml <<EOF_COMPOSE
|
||||
cp -a "${PROJECT_ROOT}/gui/." /opt/wg-admin-gui/app/
|
||||
|
||||
cat > /opt/wg-admin-gui/docker-compose.yml <<EOF_COMPOSE
|
||||
services:
|
||||
wireguard-ui:
|
||||
image: ngoduykhanh/wireguard-ui:latest
|
||||
container_name: wireguard-ui
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
container_name: wg-admin-postgres
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${GUI_PORT}:5000"
|
||||
environment:
|
||||
- WGUI_USERNAME=${GUI_USER}
|
||||
- WGUI_PASSWORD=${GUI_PASSWORD}
|
||||
- SESSION_SECRET=${GUI_SESSION_SECRET}
|
||||
- WGUI_ENDPOINT_ADDRESS=${SERVER_PUBLIC_IP}:${WG_PORT}
|
||||
- WGUI_DNS=${SERVER_DNS}
|
||||
- WGUI_CONFIG_FILE_PATH=/etc/wireguard/${WG_INTERFACE}.conf
|
||||
- WGUI_SERVER_INTERFACE_ADDRESSES=${WG_ADDRESS}
|
||||
- WGUI_SERVER_LISTEN_PORT=${WG_PORT}
|
||||
- WGUI_DEFAULT_CLIENT_ALLOWED_IPS=0.0.0.0/0
|
||||
- WGUI_MANAGE_START=true
|
||||
- WGUI_MANAGE_RESTART=true
|
||||
- POSTGRES_DB=wgadmin
|
||||
- POSTGRES_USER=wgadmin
|
||||
- POSTGRES_PASSWORD=${GUI_DB_PASSWORD}
|
||||
ports:
|
||||
- "127.0.0.1:5432:5432"
|
||||
volumes:
|
||||
- /etc/wireguard:/etc/wireguard
|
||||
- /opt/wireguard-ui/db:/app/db
|
||||
- /opt/wireguard-ui/data:/app/data
|
||||
cap_add:
|
||||
- NET_ADMIN
|
||||
- /opt/wg-admin-gui/pgdata:/var/lib/postgresql/data
|
||||
EOF_COMPOSE
|
||||
|
||||
systemd_enable_now docker.service
|
||||
detect_compose_cmd
|
||||
(cd /opt/wg-admin-gui && "${COMPOSE_CMD[@]}" up -d --remove-orphans)
|
||||
|
||||
local compose_cmd=()
|
||||
local compose_mode=""
|
||||
if docker compose version >/dev/null 2>&1; then
|
||||
compose_cmd=(docker compose)
|
||||
compose_mode="plugin"
|
||||
elif command -v docker-compose >/dev/null 2>&1; then
|
||||
compose_cmd=(docker-compose)
|
||||
compose_mode="legacy"
|
||||
else
|
||||
die "Не найден docker compose. Установите docker-compose-plugin или docker-compose."
|
||||
fi
|
||||
python3 -m venv /opt/wg-admin-gui/venv
|
||||
/opt/wg-admin-gui/venv/bin/pip install --upgrade pip >/dev/null
|
||||
/opt/wg-admin-gui/venv/bin/pip install -r /opt/wg-admin-gui/app/requirements.txt >/dev/null
|
||||
|
||||
# На некоторых системах с legacy docker-compose (v1) при recreate может возникать
|
||||
# KeyError: 'ContainerConfig'. Предварительно удаляем старый контейнер по имени.
|
||||
if [[ "$compose_mode" == "legacy" ]]; then
|
||||
docker rm -f wireguard-ui >/dev/null 2>&1 || true
|
||||
cat > /opt/wg-admin-gui/wg-admin-gui.env <<EOF_ENV
|
||||
DB_DSN=postgresql://wgadmin:${GUI_DB_PASSWORD}@127.0.0.1:5432/wgadmin
|
||||
WG_INTERFACE=${WG_INTERFACE}
|
||||
WG_META_FILE=/etc/wireguard/wg-meta.env
|
||||
ADMIN_USER=${GUI_USER}
|
||||
ADMIN_PASSWORD=${GUI_PASSWORD}
|
||||
APP_SECRET=$(random_alnum 32)
|
||||
APP_PORT=${GUI_PORT}
|
||||
EOF_ENV
|
||||
chmod 600 /opt/wg-admin-gui/wg-admin-gui.env
|
||||
|
||||
# Удаляем возможные старые контейнеры вида <project>_wireguard-ui
|
||||
# и контейнеры сервиса wireguard-ui по compose-label.
|
||||
local legacy_ids legacy_names
|
||||
legacy_ids="$(docker ps -aq --filter 'label=com.docker.compose.service=wireguard-ui' || true)"
|
||||
if [[ -n "$legacy_ids" ]]; then
|
||||
docker rm -f $legacy_ids >/dev/null 2>&1 || true
|
||||
fi
|
||||
cat > /etc/systemd/system/wg-admin-gui.service <<EOF_SERVICE
|
||||
[Unit]
|
||||
Description=WG Admin GUI
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
|
||||
legacy_names="$(docker ps -a --format '{{.Names}}' | grep -E '(^|[_-])wireguard-ui($|[_-])' || true)"
|
||||
if [[ -n "$legacy_names" ]]; then
|
||||
while IFS= read -r cname; do
|
||||
[[ -n "$cname" ]] || continue
|
||||
docker rm -f "$cname" >/dev/null 2>&1 || true
|
||||
done <<< "$legacy_names"
|
||||
fi
|
||||
fi
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/opt/wg-admin-gui/app
|
||||
EnvironmentFile=/opt/wg-admin-gui/wg-admin-gui.env
|
||||
ExecStart=/opt/wg-admin-gui/venv/bin/gunicorn -w 2 -b 0.0.0.0:${GUI_PORT} app:app
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
User=root
|
||||
|
||||
(cd /opt/wireguard-ui && "${compose_cmd[@]}" up -d --remove-orphans)
|
||||
log_success "GUI wireguard-ui запущен"
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF_SERVICE
|
||||
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now wg-admin-gui.service
|
||||
|
||||
log_success "WG Admin GUI запущен"
|
||||
}
|
||||
|
||||
print_summary() {
|
||||
@@ -440,8 +442,7 @@ print_summary() {
|
||||
gui_status="disabled"
|
||||
|
||||
if [[ "$GUI_ENABLE" == "yes" ]]; then
|
||||
gui_status="$(docker ps --filter name=wireguard-ui --format '{{.Status}}' || true)"
|
||||
[[ -n "$gui_status" ]] || gui_status="not running"
|
||||
gui_status="$(systemctl is-active wg-admin-gui.service 2>/dev/null || true)"
|
||||
fi
|
||||
|
||||
cat <<EOF_SUMMARY
|
||||
@@ -466,10 +467,6 @@ Auto-apply GUI->WG: enabled (wg-syncconf@${WG_INTERFACE}.path)
|
||||
Лог установки: ${LOG_FILE}
|
||||
=================================================
|
||||
EOF_SUMMARY
|
||||
|
||||
if [[ "$GUI_ENABLE" == "yes" ]]; then
|
||||
echo "Ссылка для входа в GUI: http://${GUI_HOST}:${GUI_PORT}"
|
||||
fi
|
||||
}
|
||||
|
||||
main() {
|
||||
@@ -480,6 +477,7 @@ main() {
|
||||
require_cmd ip
|
||||
require_cmd awk
|
||||
require_cmd sed
|
||||
require_cmd python3
|
||||
|
||||
collect_inputs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user