GUI: migrate storage from PostgreSQL to SQLite and expose conf download

This commit is contained in:
Ruslan
2026-04-14 12:08:10 +03:00
parent 39d17534e0
commit cd5ba53802
5 changed files with 31 additions and 79 deletions

View File

@@ -8,7 +8,7 @@
- Быстро развернуть WireGuard-сервер (`wg-quick@wg0`) с автозапуском через `systemd`.
- Включить IP forwarding и NAT для выхода клиентов в интернет через сервер.
- Установить встроенный GUI для управления peer'ами и QR (`wg-admin-gui`) с хранением данных в PostgreSQL.
- Установить встроенный GUI для управления peer'ами и QR (`wg-admin-gui`) с хранением данных в SQLite.
- Автоматизировать добавление клиента с клиентской машины через SSH на сервер.
- Поддержать 2 режима маршрутизации клиента:
- полный туннель (весь трафик через VPN)
@@ -36,7 +36,7 @@
- Сервер разворачивается нативно на `wg-quick` + `systemd` (стабильность после reboot).
- GUI (`wg-admin-gui`) работает поверх того же `/etc/wireguard`, где лежит серверный конфиг.
- Метаданные GUI хранятся в PostgreSQL.
- Метаданные GUI хранятся в SQLite.
- На сервере ставится `wg-syncconf@wg0.path`: при изменении `/etc/wireguard/wg0.conf` конфиг автоматически применяется в живой интерфейс `wg0`.
- Клиентский скрипт:
1. генерирует ключи локально,
@@ -60,7 +60,6 @@
- `wireguard`, `wireguard-tools`
- `iproute2`, `iptables`
- `curl`, `ca-certificates`, `openssl`, `qrencode`
- `docker.io` и один из пакетов: `docker-compose-plugin` или `docker-compose` (для PostgreSQL контейнера GUI)
- `python3`, `python3-venv`, `python3-pip` (для `wg-admin-gui`)
### Клиент
@@ -79,7 +78,7 @@
sudo bash server/install_server.sh
```
Важно: серверный установщик теперь всегда выполняет полный reset прошлого состояния (`/etc/wireguard` + данные GUI/PostgreSQL) и поднимает всё заново.
Важно: серверный установщик теперь всегда выполняет полный reset прошлого состояния (`/etc/wireguard` + данные GUI/SQLite) и поднимает всё заново.
### Запуск сервера одной командой (без `git clone`)
@@ -234,7 +233,7 @@ http://203.0.113.10:5000
1. Откройте GUI по ссылке из итоговой сводки установки.
2. Перейдите в раздел добавления peer.
3. Создайте клиента.
4. Используйте показанный QR.
4. Используйте показанный QR или скачайте готовый `.conf`.
5. На iPhone: WireGuard → `Add Tunnel``Create from QR code` и отсканируйте код.
## Взаимодействие клиента с сервером
@@ -309,7 +308,6 @@ ls -l /usr/local/sbin/wg-peerctl
4. GUI недоступен:
```bash
sudo systemctl status wg-admin-gui --no-pager
sudo docker ps | grep wg-admin-postgres
sudo ss -tulpn | grep 5000
```

View File

@@ -2,18 +2,17 @@
import base64
import io
import os
import sqlite3
import subprocess
from datetime import datetime
import qrcode
from flask import Flask, redirect, render_template, request, url_for, flash, Response
from psycopg import connect
from psycopg.rows import dict_row
app = Flask(__name__)
app.secret_key = os.environ.get("APP_SECRET", "dev-secret")
DB_DSN = os.environ.get("DB_DSN", "postgresql://wgadmin:wgadmin@127.0.0.1:5432/wgadmin")
DB_PATH = os.environ.get("DB_PATH", "/opt/wg-admin-gui/data/wgadmin.db")
WG_INTERFACE = os.environ.get("WG_INTERFACE", "wg0")
WG_META_FILE = os.environ.get("WG_META_FILE", "/etc/wireguard/wg-meta.env")
ADMIN_USER = os.environ.get("ADMIN_USER", "admin")
@@ -21,23 +20,25 @@ ADMIN_PASSWORD = os.environ.get("ADMIN_PASSWORD", "")
def db_conn():
return connect(DB_DSN, row_factory=dict_row)
os.makedirs(os.path.dirname(DB_PATH), exist_ok=True)
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def ensure_schema():
with db_conn() as conn, conn.cursor() as cur:
cur.execute(
"""
with db_conn() as conn:
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS peers (
id BIGSERIAL PRIMARY KEY,
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
public_key TEXT UNIQUE NOT NULL,
client_address TEXT,
advertised_routes TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT now()
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
"""
)
""")
conn.commit()
@@ -150,9 +151,10 @@ def _schema():
def index():
meta = load_meta()
runtime = {p["public_key"]: p for p in wg_dump()}
with db_conn() as conn, conn.cursor() as cur:
with db_conn() as conn:
cur = conn.cursor()
cur.execute("SELECT * FROM peers ORDER BY id DESC")
db_peers = cur.fetchall()
db_peers = [dict(r) for r in cur.fetchall()]
items = []
seen = set()
@@ -260,16 +262,14 @@ def new_peer():
client_conf = "\n".join(conf_lines)
qr_b64 = to_png_b64(client_conf)
with db_conn() as conn, conn.cursor() as cur:
cur.execute(
"""
with db_conn() as conn:
cur = conn.cursor()
cur.execute("""
INSERT INTO peers(name, public_key, client_address, advertised_routes)
VALUES (%s,%s,%s,%s)
VALUES (?,?,?,?)
ON CONFLICT(public_key)
DO UPDATE SET name=excluded.name, client_address=excluded.client_address, advertised_routes=excluded.advertised_routes
""",
(name, client_pub, client_addr, routes),
)
""", (name, client_pub, client_addr, routes))
conn.commit()
return render_template(

View File

@@ -1,4 +1,3 @@
Flask==3.0.3
psycopg[binary]==3.2.1
qrcode==7.4.2
gunicorn==23.0.0

View File

@@ -2,6 +2,7 @@
{% block content %}
<h2>Peer создан: {{ name }}</h2>
<p>PublicKey: <span class="mono">{{ public_key }}</span></p>
<p><a href="data:text/plain;charset=utf-8,{{ client_conf | urlencode }}" download="{{ name }}.conf">Скачать {{ name }}.conf</a></p>
<div class="grid2">
<div>
<h3>QR</h3>

View File

@@ -24,7 +24,6 @@ GUI_USER="admin"
GUI_PASSWORD=""
GUI_PASSWORD_GENERATED=0
GUI_RESET_DB="no"
GUI_DB_PASSWORD=""
usage() {
cat <<'USAGE'
@@ -116,16 +115,6 @@ 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"
@@ -149,14 +138,9 @@ reset_existing_install() {
rm -f /etc/systemd/system/wg-admin-gui.service
if command -v docker >/dev/null 2>&1; then
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
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
(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
fi
docker rm -f wireguard-ui wg-admin-postgres >/dev/null 2>&1 || true
@@ -213,8 +197,6 @@ collect_inputs() {
fi
fi
fi
GUI_DB_PASSWORD="$(random_alnum 24)"
[[ "$GUI_RESET_DB" == "yes" || "$GUI_RESET_DB" == "no" ]] || die "--gui-reset-db должен быть yes или no"
fi
@@ -224,15 +206,7 @@ collect_inputs() {
install_packages() {
apt_install_if_missing \
wireguard wireguard-tools iproute2 iptables curl ca-certificates openssl \
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
elif apt-cache show docker-compose >/dev/null 2>&1; then
apt_install_if_missing docker-compose
else
log_warn "Не найден пакет docker-compose-plugin/docker-compose. Проверьте репозитории APT."
fi
python3 python3-venv python3-pip
}
setup_sysctl() {
@@ -371,37 +345,17 @@ EOF_SYNC_PATH
setup_gui() {
[[ "$GUI_ENABLE" == "yes" ]] || { log_warn "GUI отключен (GUI_ENABLE=no)"; return; }
mkdir -p /opt/wg-admin-gui/{app,pgdata}
mkdir -p /opt/wg-admin-gui/{app,data}
safe_chmod_700 /opt/wg-admin-gui
cp -a "${PROJECT_ROOT}/gui/." /opt/wg-admin-gui/app/
cat > /opt/wg-admin-gui/docker-compose.yml <<EOF_COMPOSE
services:
postgres:
image: postgres:16-alpine
container_name: wg-admin-postgres
restart: unless-stopped
environment:
- POSTGRES_DB=wgadmin
- POSTGRES_USER=wgadmin
- POSTGRES_PASSWORD=${GUI_DB_PASSWORD}
ports:
- "127.0.0.1:5432:5432"
volumes:
- /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)
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
cat > /opt/wg-admin-gui/wg-admin-gui.env <<EOF_ENV
DB_DSN=postgresql://wgadmin:${GUI_DB_PASSWORD}@127.0.0.1:5432/wgadmin
DB_PATH=/opt/wg-admin-gui/data/wgadmin.db
WG_INTERFACE=${WG_INTERFACE}
WG_META_FILE=/etc/wireguard/wg-meta.env
ADMIN_USER=${GUI_USER}
@@ -414,7 +368,7 @@ EOF_ENV
cat > /etc/systemd/system/wg-admin-gui.service <<EOF_SERVICE
[Unit]
Description=WG Admin GUI
After=network-online.target docker.service
After=network-online.target
Wants=network-online.target
[Service]