Compare commits

...

30 Commits

Author SHA1 Message Date
Donald Zou
1faabd37af Merge pull request #936 from WGDashboard/fix-752
Internal merge for Fix 752
2025-10-02 07:18:09 +08:00
jinndi
c18ec5c83c Docker: Use relative paths instead of absolute ones to ensure proper namespace handling when working behind a reverse proxy. (#934)
* Docker: Use relative paths instead of absolute ones to ensure proper namespace handling when working behind a reverse proxy.

* Fix: Progress Swap Memory percent
2025-09-29 12:14:52 +02:00
Daan Selen
d8c89056cb refac: rework the variable times, mostly in ConnectionString 2025-09-23 09:08:21 +02:00
DaanSelen
8b541229d8 refac: make WGDashboard logging level configurable (#915)
* feat: init configurable logging level

* refac: correct some logging functions to debug from info. They were not that informational

* fix: logging somehow was broken due to disablement of external loggers

* refac: set default to info

---------

Co-authored-by: Daan Selen <dselen@systemec.nl>
2025-09-22 18:20:22 +02:00
Daan Selen
b7e65f7caf fix: initial run import massacre 2025-09-22 14:04:11 +02:00
Daan Selen
2eda18f18d refac: correct log output for the conditions checked 2025-09-22 13:35:53 +02:00
Daan Selen
d06709aeab Merge branch 'main' into v4.3.1-dev 2025-09-22 13:29:06 +02:00
Donald Zou
3de22ed2d6 Merge pull request #921 from WGDashboard/minor-patch-save-config 2025-09-22 17:54:40 +08:00
Donald Zou
10a8d22efd Merge pull request #922 from WGDashboard/docker-duplicate-hotfix
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
2025-09-22 17:53:34 +08:00
Donald Zou
fc3ec61373 Merge pull request #923 from WGDashboard/remove-docker-funcs
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-09-22 05:46:38 +08:00
Daan Selen
094d1c0718 refac: remove docker functions 2025-09-21 22:04:59 +02:00
Daan Selen
0d814ec03c refac: new logic to detecting a Wireguard interface 2025-09-21 21:57:28 +02:00
Daan Selen
a9036590a9 refac: save config before accessing it 2025-09-21 21:51:59 +02:00
dependabot[bot]
8f8843d449 Bump is-cidr from 5.1.1 to 6.0.0 in /src/static/app (#903)
Bumps [is-cidr](https://github.com/silverwind/is-cidr) from 5.1.1 to 6.0.0.
- [Release notes](https://github.com/silverwind/is-cidr/releases)
- [Commits](https://github.com/silverwind/is-cidr/compare/5.1.1...6.0.0)

---
updated-dependencies:
- dependency-name: is-cidr
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 19:52:39 +02:00
dependabot[bot]
6a21702768 Bump uuid from 11.1.0 to 13.0.0 in /src/static/app (#904)
Bumps [uuid](https://github.com/uuidjs/uuid) from 11.1.0 to 13.0.0.
- [Release notes](https://github.com/uuidjs/uuid/releases)
- [Changelog](https://github.com/uuidjs/uuid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/uuidjs/uuid/compare/v11.1.0...v13.0.0)

---
updated-dependencies:
- dependency-name: uuid
  dependency-version: 13.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 19:52:10 +02:00
dependabot[bot]
5ccfe07e12 Bump npm from 10.9.3 to 11.6.0 in /src/static/app (#901)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Bumps [npm](https://github.com/npm/cli) from 10.9.3 to 11.6.0.
- [Release notes](https://github.com/npm/cli/releases)
- [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md)
- [Commits](https://github.com/npm/cli/compare/v10.9.3...v11.6.0)

---
updated-dependencies:
- dependency-name: npm
  dependency-version: 11.6.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-21 17:30:31 +02:00
Donald Zou
56552d0a83 Merge pull request #917 from WGDashboard/db_prefix_add
feat: add configurable database prefix
2025-09-21 02:44:48 +08:00
dependabot[bot]
101ac5e985 Bump vite from 7.1.5 to 7.1.6 in /src/static/app (#912)
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) from 7.1.5 to 7.1.6.
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.1.6/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.1.6
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-19 21:00:15 +02:00
dependabot[bot]
113a780eec Bump @vue/language-server from 3.0.5 to 3.0.7 in /src/static/app (#902)
Bumps [@vue/language-server](https://github.com/vuejs/language-tools/tree/HEAD/packages/language-server) from 3.0.5 to 3.0.7.
- [Release notes](https://github.com/vuejs/language-tools/releases)
- [Changelog](https://github.com/vuejs/language-tools/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vuejs/language-tools/commits/v3.0.7/packages/language-server)

---
updated-dependencies:
- dependency-name: "@vue/language-server"
  dependency-version: 3.0.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-09-19 20:59:48 +02:00
Daan Selen
bd17b9080a fix: issue where I accidentally did the same name twice 2025-09-19 20:56:00 +02:00
Daan Selen
bf28983229 feat: make the prefix configurable 2025-09-19 20:55:47 +02:00
Donald Zou
cf77610a56 Merge pull request #914 from WGDashboard/add-template
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
2025-09-19 18:24:45 +08:00
Daan Selen
84675fe521 feat: add default wg-dashboard.ini config 2025-09-19 10:32:25 +02:00
Donald Zou
5db5b35311 Update README.md
Some checks failed
CodeQL / Analyze (javascript) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Docker Build and Push / docker_build (push) Has been cancelled
Docker Build and Push / docker_scan (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-09-17 23:31:20 +08:00
DaanSelen
ff345c9609 style: readme update 2025-09-17 16:03:35 +02:00
Daan Selen
6cccfec923 fix: fix the docker building issue
I accidentally removed a character
  we are all human.
2025-09-17 15:58:16 +02:00
Donald Zou
8231dd1463 Merge pull request #906 from WGDashboard/docker-doc-refac
refac(docs): rewrite and check the docker documents
2025-09-17 21:49:25 +08:00
Daan Selen
d8ff020d8c refac(docs): rewrite and check the docker documents 2025-09-17 15:34:39 +02:00
Daan Selen
238fb91360 chore: further expand and change the compose file
For people that want to get started quickly
2025-09-17 15:20:01 +02:00
DaanSelen
9ecc16fcc1 chore: update dependabot config 2025-09-17 11:05:31 +02:00
27 changed files with 662 additions and 692 deletions

View File

@@ -11,7 +11,7 @@ updates:
interval: "daily"
- package-ecosystem: "npm"
directory: "/"
directory: "/src/static/app"
schedule:
interval: "daily"

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@ __pycache__
src/test.py
*.db
src/wg-dashboard.ini
src/ssl-tls.ini
src/static/pic.xd
*.conf
private_key.txt

View File

@@ -26,6 +26,8 @@
<a href="https://wakatime.com/badge/github/donaldzou/WGDashboard"><img src="https://wakatime.com/badge/github/donaldzou/WGDashboard.svg?style=for-the-badge" alt="wakatime"></a>
<a href="https://hitscounter.dev"><img src="https://hitscounter.dev/api/hit?url=https%3A%2F%2Fgithub.com%2Fdonaldzou%2FWGDashboard&label=Visitor&icon=github&color=%230a58ca&style=for-the-badge"></a>
<img src="https://img.shields.io/docker/pulls/donaldzou/wgdashboard?logo=docker&label=Docker%20Image%20Pulls&labelColor=ffffff&style=for-the-badge">
<img src="https://github.com/WGDashboard/WGDashboard/actions/workflows/docker.yml/badge.svg?style=for-the-badge">
<img src="https://github.com/WGDashboard/WGDashboard/actions/workflows/codeql-analyze.yaml/badge.svg">
</p>
<p align="center"><b>This project is supported by</b></p>
<p align="center">

View File

@@ -3,8 +3,10 @@
# Base: Alpine
#
# Pull the current golang-alpine image.
FROM golang:1.25-alpine AS awg-go
# Install build-dependencies.
RUN apk add --no-cache \
git \
gcc \
@@ -14,9 +16,12 @@ RUN apk add --no-cache \
RUN mkdir -p /workspace && \
git clone https://github.com/WGDashboard/amneziawg-go /workspace/awg
# Enable CGO compilation for AmneziaWG
ENV CGO_ENABLED=1
# Change directory
WORKDIR /workspace/awg
# Compile the binaries
RUN go mod download && \
go mod verify && \
go build -ldflags '-linkmode external -extldflags "-fno-PIC -static"' -v -o /usr/bin
@@ -26,6 +31,7 @@ RUN go mod download && \
#
FROM alpine:latest AS awg-tools
# Install needed dependencies.
RUN apk add --no-cache \
make \
git \
@@ -33,19 +39,24 @@ RUN apk add --no-cache \
linux-headers \
ca-certificates
# Get the workspace ready
RUN mkdir -p /workspace && \
git clone https://github.com/WGDashboard/amneziawg-tools /workspace/awg-tools
# Change directory
WORKDIR /workspace/awg-tools/src
# Compile and change permissions
RUN make && chmod +x wg*
#
# PIP DEPENDENCY BUILDING
# Base: Alpine
#
# Use the python-alpine image for building pip dependencies
FROM python:3.13-alpine AS pip-builder
# Add the build dependencies and create a Python virtual environment.
RUN apk add --no-cache \
build-base \
pkgconfig \
@@ -57,7 +68,9 @@ RUN apk add --no-cache \
&& mkdir -p /opt/wgdashboard/src \
&& python3 -m venv /opt/wgdashboard/src/venv
# Copy the requirements file into the build layer.
COPY ./src/requirements.txt /opt/wgdashboard/src
# Install the pip packages
RUN . /opt/wgdashboard/src/venv/bin/activate && \
pip3 install --upgrade pip && \
pip3 install -r /opt/wgdashboard/src/requirements.txt
@@ -66,6 +79,8 @@ RUN . /opt/wgdashboard/src/venv/bin/activate && \
# WGDashboard RUNNING STAGE
# Base: Alpine
#
# Running with the python-alpine image.
FROM python:3.13-alpine AS final
LABEL maintainer="dselen@nerthus.nl"
@@ -78,7 +93,7 @@ RUN apk add --no-cache \
tzdata wireguard-tools \
openresolv openrc
# Copy only the final binaries from the builders
# Copy only the final binaries from the AWG builder stages
COPY --from=awg-go /usr/bin/amneziawg-go /usr/bin/amneziawg-go
COPY --from=awg-tools /workspace/awg-tools/src/wg /usr/bin/awg
COPY --from=awg-tools /workspace/awg-tools/src/wg-quick/linux.bash /usr/bin/awg-quick
@@ -89,17 +104,18 @@ ARG wg_port="51820"
ENV TZ="Europe/Amsterdam" \
global_dns="9.9.9.9" \
wgd_port="10086" \
log_level="INFO" \
public_ip="" \
WGDASH=/opt/wgdashboard
# Create directories
# Create directories needed for operation
RUN mkdir /data /configs -p ${WGDASH}/src /etc/amnezia/amneziawg
# Copy app source and prebuilt venv only (no pip cache)
# Copy the python virtual environment from the pip-builder stage
COPY ./src ${WGDASH}/src
COPY --from=pip-builder /opt/wgdashboard/src/venv /opt/wgdashboard/src/venv
# WireGuard interface template
# First WireGuard interface template
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN out_adapt=$(ip -o -4 route show to default | awk '{print $NF}') \
&& echo -e "[Interface]\n\
@@ -114,11 +130,23 @@ SaveConfig = true\n\
DNS = ${global_dns}" > /configs/wg0.conf.template \
&& chmod 600 /configs/wg0.conf.template
# Replacement of paths with relative ones for namespace handling when using a reverse proxy
RUN set -ex && \
find ${WGDASH}/src/static/dist -type f \( -name "*.html" -o -name "*.js" \) \
-exec sed -i 's|/static/dist|./static/dist|g' {} + && \
find ${WGDASH}/src/static/dist -type f -name "*.css" \
-exec sed -i 's|/static/dist/WGDashboardClient/assets/|./|g' {} + && \
find ${WGDASH}/src/static/dist -type f -name "*.css" \
-exec sed -i 's|/static/dist/WGDashboardAdmin/assets/|./|g' {} +
# Set a healthcheck to determine the container its health
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
CMD sh -c 'pgrep gunicorn > /dev/null && pgrep tail > /dev/null' || exit 1
# Copy in the runtime script, essential.
COPY ./docker/entrypoint.sh /entrypoint.sh
#
EXPOSE 10086
WORKDIR $WGDASH/src

View File

@@ -3,8 +3,8 @@ Author: @DaanSelen<br>
This document delves into how the WGDashboard Docker container has been built.<br>
Of course there are two stages (simply said), one before run-time and one at/after run-time.<br>
The `Dockerfile` describes how the container image is made, and the `entrypoint.sh` is executed after running the container. <br>
In this example, WireGuard is integrated into the container itself, so it should be a run-and-go(/out-of-the-box).<br>
The `Dockerfile` describes how the container image is made, and the `entrypoint.sh` is executed after the container is started. <br>
In this example, [WireGuard](https://www.wireguard.com/) is integrated into the container itself, so it should be a run-and-go(/out-of-the-box) experience.<br>
For more details on the source-code specific to this Docker image, refer to the source files, they have lots of comments.
<br>
@@ -18,20 +18,24 @@ For more details on the source-code specific to this Docker image, refer to the
/>
<br>
To get the container running you either pull the image from the repository, (docker.io)`donaldzou/wgdashboard:latest`.<br>
From there either use the environment variables describe below as parameters or use the Docker Compose file: `compose.yaml`.<br>
Be careful, the default generated WireGuard configuration file uses port 51820/udp. So use this port if you want to use it out of the box.<br>
Otherwise edit the configuration file in `/etc/wireguard/wg0.conf`.
To get the container running you either pull the pre-made image from a remote repository, there are 2 official options.<br>
- ghcr.io/wgdashboard/wgdashboard:<tag>
- docker.io/donaldzou/wgdashboard:<tag>
> tags should be either: latest, main, <version> or <commit-sha>.
From there either use the environment variables described below as parameters or use the Docker Compose file: `compose.yaml`.<br>
Be careful, the default generated WireGuard configuration file uses port 51820/udp. So make sure to use this port if you want to use it out of the box.<br>
Otherwise edit the configuration file in WGDashboard under `Configuration Settings` -> `Edit Raw Configuration File`.
> Otherwise you need to enter the container and edit: `/etc/wireguard/wg0.conf`.
# WGDashboard: 🐳 Docker Deployment Guide
To run the container, you can either pull the image from Docker Hub or build it yourself. The image is available at:
To run the container, you can either pull the image from the Github Container Registry (ghcr.io), Docker Hub (docker.io) or build it yourself. The image is available at:
```
docker.io/donaldzou/wgdashboard:latest
```
> `docker.io` is in most cases automatically resolved by the Docker application.
> `docker.io` is in most cases automatically resolved by the Docker application. Therefor you can ofter specify: `donaldzou/wgdashboard:latest`
### 🔧 Quick Docker Run Command
@@ -44,7 +48,7 @@ docker run -d \
-p 10086:10086/tcp \
-p 51820:51820/udp \
--cap-add NET_ADMIN \
donaldzou/wgdashboard:latest
ghcr.io/wgdashboard/wgdashboard:latest
```
> ⚠️ The default WireGuard port is `51820/udp`. If you change this, update the `/etc/wireguard/wg0.conf` accordingly.
@@ -58,23 +62,24 @@ You can also use Docker Compose for easier configuration:
```yaml
services:
wgdashboard:
image: donaldzou/wgdashboard:latest
image: ghcr.io/wgdashboard/wgdashboard:latest
restart: unless-stopped
container_name: wgdashboard
environment:
# - tz=Europe/Amsterdam
# - global_dns=1.1.1.1
# - public_ip=YOUR_PUBLIC_IP
ports:
- 10086:10086/tcp
- 51820:51820/udp
volumes:
- aconf:/etc/amnezia/amneziawg
- conf:/etc/wireguard
- data:/data
cap_add:
- NET_ADMIN
volumes:
aconf:
conf:
data:
```
@@ -85,7 +90,7 @@ volumes:
## 🔄 Updating the Container
Updating WGDashboard is currently in **alpha** stage. While the update process may work, it's still under testing.
Updating the WGDashboard container should be through 'The Docker Way' - by pulling the newest/newer image and replacing this old one.
---
@@ -97,6 +102,7 @@ Updating WGDashboard is currently in **alpha** stage. While the update process m
| `global_dns` | IPv4 and IPv6 addresses | `9.9.9.9` | `8.8.8.8`, `1.1.1.1` | Default DNS for WireGuard clients. |
| `public_ip` | Public IP address | Retrieved automatically | `253.162.134.73` | Used to generate accurate client configs. Needed if container is NATd. |
| `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. |
| `log_level` | `DEBUG`, `INFO`, `WARNING`, `ERROR` and `CRITICAL` | `INFO` | `WARNING` | Sets the severity of the logs being displayed. |
| `username` | Any nonempty string | `-` | `admin` | Username for the WGDashboard web interface account. |
| `password` | Any nonempty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). |
| `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTPbased twofactor authentication for the account. |
@@ -205,4 +211,4 @@ ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
## Closing remarks:
For feedback please submit an issue to the repository. Or message dselen@nerthus.nl.
For feedback please submit an issue to the repository. Or message dselen@nerthus.nl.

View File

@@ -1,22 +1,42 @@
services:
wireguard-dashboard:
image: donaldzou/wgdashboard:latest
wgdashboard:
# Since the github organisation we recommend the ghcr.io.
# Alternatively we also still push to docker.io under donaldzou/wgdashboard.
# Both share the exact same tags. So they should be interchangable.
image: ghcr.io/wgdashboard/wgdashboard:latest
# Make sure to set the restart policy. Because for a VPN its important to come back IF it crashes.
restart: unless-stopped
container_name: wgdashboard
#environment:
# Environment variables can be used to configure certain values at startup. Without having to configure it from the dashboard.
# By default its all disabled, but uncomment the following lines to apply these. (uncommenting is removing the # character)
# Refer to the documentation on https://wgdashboard.dev/ for more info on what everything means.
environment:
- log_level=WARNING
#- tz= # <--- Set container timezone, default: Europe/Amsterdam.
#- public_ip= # <--- Set public IP to ensure the correct one is chosen, defaulting to the IP give by ifconfig.me.
#- wgd_port= # <--- Set the port WGDashboard will use for its web-server.
# The following section, ports is very important for exposing more than one Wireguard/AmneziaWireguard interfaces.
# Once you create a new configuration and assign a port in the dashboard, don't forget to add it to the ports as well.
# Quick-tip: most Wireguard VPN tunnels use UDP. WGDashboard uses HTTP, so tcp.
ports:
- 10086:10086/tcp
- 51820:51820/udp
# Volumes can be configured however you'd like. The default is using docker volumes.
# If you want to use local paths, replace the path before the : with your path.
volumes:
- aconf:/etc/amnezia/amneziawg
- conf:/etc/wireguard
- data:/data
# Needed for network administration.
cap_add:
- NET_ADMIN
# The following configuration is linked to the above default volumes.
volumes:
aconf:
conf:

View File

@@ -13,15 +13,15 @@ hash_password() {
set_ini() {
local section="$1" key="$2" value="$3"
local current_value
# Add section if it doesn't exist
grep -q "^\[${section}\]" "$config_file" \
|| printf "\n[%s]\n" "${section}" >> "$config_file"
# Check current value if key exists
if grep -q "^[[:space:]]*${key}[[:space:]]*=" "$config_file"; then
current_value=$(grep "^[[:space:]]*${key}[[:space:]]*=" "$config_file" | cut -d= -f2- | xargs)
# Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then
if [ "$current_value" = "$value" ]; then
@@ -40,7 +40,7 @@ set_ini() {
fi
else
sed -i "/^\[${section}\]/a ${key} = ${value}" "$config_file"
# Don't display actual value if it's a password field
if [[ "$key" == *"password"* ]]; then
echo "- Added new setting $key (value hidden)"
@@ -61,111 +61,112 @@ echo "Starting the WGDashboard Docker container."
ensure_installation() {
echo "Quick-installing..."
# Make the wgd.sh script executable.
chmod +x "${WGDASH}"/src/wgd.sh
cd "${WGDASH}"/src || exit
# Github issue: https://github.com/donaldzou/WGDashboard/issues/723
echo "Checking for stale pids..."
if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then
echo "Found stale pid, removing..."
rm ${WGDASH}/src/gunicorn.pid
fi
# Removing clear shell command from the wgd.sh script to enhance docker logging.
echo "Removing clear command from wgd.sh for better Docker logging."
sed -i '/clear/d' ./wgd.sh
# Create required directories and links
if [ ! -d "/data/db" ]; then
echo "Creating database dir"
mkdir -p /data/db
fi
if [ ! -d "${WGDASH}/src/db" ]; then
ln -s /data/db "${WGDASH}/src/db"
fi
if [ ! -f "${config_file}" ]; then
echo "Creating wg-dashboard.ini file"
touch "${config_file}"
fi
if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then
ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
fi
# Create the Python virtual environment.
. "${WGDASH}/src/venv/bin/activate"
# Use the bash interpreter to install WGDashboard according to the wgd.sh script.
/bin/bash ./wgd.sh install
echo "Looks like the installation succeeded. Moving on."
# Setup WireGuard if needed
if [ ! -f "/etc/wireguard/wg0.conf" ]; then
if [ -z "$(ls -A /etc/wireguard)" ]; then
cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf"
echo "Setting a secure private key."
local privateKey
privateKey=$(wg genkey)
sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf
echo "Done setting template."
else
echo "Existing wg0 configuration file found, using that."
echo "Existing Wireguard configuration file found in /etc/wireguard."
fi
}
set_envvars() {
printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n"
# Check if config file is empty
if [ ! -s "${config_file}" ]; then
echo "Config file is empty. Creating initial structure."
fi
echo "Checking basic configuration:"
set_ini Peers peer_global_dns "${global_dns}"
if [ -z "${public_ip}" ]; then
public_ip=$(curl -s ifconfig.me)
echo "Automatically detected public IP: ${public_ip}"
fi
set_ini Peers remote_endpoint "${public_ip}"
set_ini Server app_port "${wgd_port}"
set_ini Server log_level "${log_level}"
# Account settings - process all parameters
[[ -n "$username" ]] && echo "Configuring user account:"
# Basic account variables
[[ -n "$username" ]] && set_ini Account username "${username}"
if [[ -n "$password" ]]; then
echo "- Setting password"
set_ini Account password "$(hash_password "${password}")"
fi
# Additional account variables
[[ -n "$enable_totp" ]] && set_ini Account enable_totp "${enable_totp}"
[[ -n "$totp_verified" ]] && set_ini Account totp_verified "${totp_verified}"
[[ -n "$totp_key" ]] && set_ini Account totp_key "${totp_key}"
# Welcome session
[[ -n "$welcome_session" ]] && set_ini Other welcome_session "${welcome_session}"
# If username and password are set but welcome_session isn't, disable it
if [[ -n "$username" && -n "$password" && -z "$welcome_session" ]]; then
set_ini Other welcome_session "false"
fi
# Autostart WireGuard
if [[ -n "$wg_autostart" ]]; then
echo "Configuring WireGuard autostart:"
set_ini WireGuardConfiguration autostart "${wg_autostart}"
fi
# Email (check if any settings need to be configured)
email_vars=("email_server" "email_port" "email_encryption" "email_username" "email_password" "email_from" "email_template")
for var in "${email_vars[@]}"; do
@@ -174,12 +175,12 @@ set_envvars() {
break
fi
done
# Email (iterate through all possible fields)
email_fields=("server:email_server" "port:email_port" "encryption:email_encryption"
"username:email_username" "email_password:email_password"
"send_from:email_from" "email_template:email_template")
for field_pair in "${email_fields[@]}"; do
IFS=: read -r field var <<< "$field_pair"
[[ -n "${!var}" ]] && set_ini Email "$field" "${!var}"
@@ -189,7 +190,7 @@ set_envvars() {
# Start service and monitor logs
start_and_monitor() {
printf "\n---------------------- STARTING CORE -----------------------\n"
# Due to some instances complaining about this, making sure its there every time.
mkdir -p /dev/net
mknod /dev/net/tun c 10 200
@@ -198,15 +199,15 @@ start_and_monitor() {
# Actually starting WGDashboard
echo "Activating Python venv and executing the WireGuard Dashboard service."
bash ./wgd.sh start
# Wait a second before continuing, to give the python program some time to get ready.
sleep 1
echo -e "\nEnsuring container continuation."
# Find and monitor log file
local logdir="${WGDASH}/src/log"
latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1)
# Only tail the logs if they are found
if [ -n "$latestErrLog" ]; then
tail -f "$latestErrLog" &
@@ -221,4 +222,4 @@ start_and_monitor() {
# Main execution flow
ensure_installation
set_envvars
start_and_monitor
start_and_monitor

View File

@@ -72,7 +72,6 @@ def ResponseObject(status=True, message=None, data=None, status_code = 200) -> F
'''
Flask App
'''
app = Flask("WGDashboard", template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"))
def peerInformationBackgroundThread():
global WireguardConfigurations
@@ -120,7 +119,8 @@ def peerJobScheduleBackgroundThread():
def gunicornConfig():
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port")
return app_ip, app_port
return app_ip, app_port, log_level
def ProtocolsEnabled() -> list[str]:
from shutil import which
@@ -172,16 +172,7 @@ def startThreads():
scheduleJobThread = threading.Thread(target=peerJobScheduleBackgroundThread, daemon=True)
scheduleJobThread.start()
dictConfig({
'version': 1,
'formatters': {'default': {
'format': '[%(asctime)s] [%(levelname)s] in [%(module)s] %(message)s',
}},
'root': {
'level': 'INFO'
}
})
app = Flask("WGDashboard", template_folder=os.path.abspath("./static/dist/WGDashboardAdmin"))
WireguardConfigurations: dict[str, WireguardConfiguration] = {}
CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
@@ -189,6 +180,7 @@ CONFIGURATION_PATH = os.getenv('CONFIGURATION_PATH', '.')
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 5206928
app.secret_key = secrets.token_urlsafe(32)
app.json = CustomJsonEncoder(app)
with app.app_context():
SystemStatus = SystemStatus()
DashboardConfig = DashboardConfig()
@@ -199,19 +191,44 @@ with app.app_context():
DashboardPlugins: DashboardPlugins = DashboardPlugins(app, WireguardConfigurations)
DashboardWebHooks: DashboardWebHooks = DashboardWebHooks(DashboardConfig)
NewConfigurationTemplates: NewConfigurationTemplates = NewConfigurationTemplates()
InitWireguardConfigurationsList(startup=True)
DashboardClients: DashboardClients = DashboardClients(WireguardConfigurations)
app.register_blueprint(createClientBlueprint(WireguardConfigurations, DashboardConfig, DashboardClients))
app.register_blueprint(
createClientBlueprint(WireguardConfigurations, DashboardConfig, DashboardClients)
)
_, APP_PREFIX = DashboardConfig.GetConfig("Server", "app_prefix")
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port")
_, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
_, log_level = DashboardConfig.GetConfig("Server", "log_level")
cors = CORS(app, resources={rf"{APP_PREFIX}/api/*": {
"origins": "*",
"methods": "DELETE, POST, GET, OPTIONS",
"allow_headers": ["Content-Type", "wg-dashboard-apikey"]
}})
_, app_ip = DashboardConfig.GetConfig("Server", "app_ip")
_, app_port = DashboardConfig.GetConfig("Server", "app_port")
_, WG_CONF_PATH = DashboardConfig.GetConfig("Server", "wg_conf_path")
app.logger.setLevel(getattr(logging, log_level.upper(), logging.INFO))
dictConfig({
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'default': {
'format': '[%(asctime)s] [%(levelname)s] in [%(module)s] %(message)s',
},
},
'handlers': {
'wsgi': {
'class': 'logging.StreamHandler',
'stream': 'ext://flask.logging.wsgi_errors_stream',
'formatter': 'default',
},
}
})
'''
API Routes

View File

@@ -1,7 +1,7 @@
import dashboard
from datetime import datetime
global sqldb, cursor, DashboardConfig, WireguardConfigurations, AllPeerJobs, JobLogger, Dash
app_host, app_port = dashboard.gunicornConfig()
app_host, app_port, log_level = dashboard.gunicornConfig()
date = datetime.today().strftime('%Y_%m_%d_%H_%M_%S')
def post_worker_init(worker):
@@ -16,7 +16,7 @@ daemon = True
pidfile = './gunicorn.pid'
wsgi_app = "dashboard:app"
accesslog = f"./log/access_{date}.log"
loglevel = "info"
loglevel = f"{log_level}"
capture_output = True
errorlog = f"./log/error_{date}.log"
pythonpath = "., ./modules"

View File

@@ -174,7 +174,7 @@ class AmneziaWireguardConfiguration(WireguardConfiguration):
def getPeers(self):
self.Peers.clear()
current_app.logger.info(f"Refreshing {self.Name} peer list")
current_app.logger.debug(f"Refreshing {self.Name} peer list")
if self.configurationFileChanged():
with open(self.configPath, 'r') as configFile:
@@ -183,7 +183,7 @@ class AmneziaWireguardConfiguration(WireguardConfiguration):
content = configFile.read().split('\n')
try:
if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section")
current_app.logger.debug(f"{self.Name} config has no [Peer] section")
return
peerStarts = content.index("[Peer]")

View File

@@ -1,25 +1,47 @@
# ConnectionString.py
import configparser
import os
from sqlalchemy_utils import database_exists, create_database
from flask import current_app
def ConnectionString(database) -> str:
default_db = "wgdashboard"
default_log_db = "wgdashboard_log"
default_job_db = "wgdashboard_job"
sqlite_path = "db"
if os.path.exists(sqlite_path):
os.makedirs(sqlite_path, exist_ok=True)
def ConnectionString(database_name: str) -> str:
"""
Returns a SQLAlchemy-compatible connection string for the chosen database.
Creates the database if it doesn't exist.
"""
# Read and parse the INI file once at startup
parser = configparser.ConfigParser(strict=False)
parser.read_file(open('wg-dashboard.ini', "r+"))
sqlitePath = os.path.join("db")
if not os.path.isdir(sqlitePath):
os.mkdir(sqlitePath)
if parser.get("Database", "type") == "postgresql":
cn = f'postgresql+psycopg://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}'
elif parser.get("Database", "type") == "mysql":
cn = f'mysql+pymysql://{parser.get("Database", "username")}:{parser.get("Database", "password")}@{parser.get("Database", "host")}/{database}'
parser.read("wg-dashboard.ini")
db_type = parser.get("Database", "type")
db_prefix = parser.get("Database", "prefix")
database_name = f"{db_prefix}{database_name}"
if db_type == "postgresql":
username = parser.get("Database", "username")
password = parser.get("Database", "password")
host = parser.get("Database", "host")
cn = f"postgresql+psycopg://{username}:{password}@{host}/{database_name}"
elif db_type == "mysql":
username = parser.get("Database", "username")
password = parser.get("Database", "password")
host = parser.get("Database", "host")
cn = f"mysql+pymysql://{username}:{password}@{host}/{database_name}"
else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}'
cn = f'sqlite:///{os.path.join(sqlite_path, f"{database_name}.db")}'
try:
if not database_exists(cn):
create_database(cn)
except Exception as e:
current_app.logger.error("Database error. Terminating...", e)
current_app.logger.critical("Database error. Terminating...", e)
exit(1)
return cn

View File

@@ -8,7 +8,7 @@ import pyotp
import sqlalchemy as db
import requests
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from .DashboardClientsPeerAssignment import DashboardClientsPeerAssignment
from .DashboardClientsTOTP import DashboardClientsTOTP
from .DashboardOIDC import DashboardOIDC
@@ -20,7 +20,7 @@ from flask import session
class DashboardClients:
def __init__(self, wireguardConfigurations):
self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.OIDC = DashboardOIDC("Client")
@@ -32,10 +32,10 @@ class DashboardClients:
db.Column('TotpKey', db.String(500)),
db.Column('TotpKeyVerified', db.Integer),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True,
)
@@ -46,10 +46,10 @@ class DashboardClients:
db.Column('ProviderIssuer', db.String(500), nullable=False, index=True),
db.Column('ProviderSubject', db.String(500), nullable=False, index=True),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('DeletedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True,
)
@@ -65,10 +65,10 @@ class DashboardClients:
db.Column('ResetToken', db.String(255), nullable=False, primary_key=True),
db.Column('ClientID', db.String(255), nullable=False),
db.Column('CreatedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('ExpiryDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True
)

View File

@@ -1,7 +1,7 @@
import datetime
import uuid
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from .DashboardLogger import DashboardLogger
import sqlalchemy as db
from .WireguardConfiguration import WireguardConfiguration
@@ -31,7 +31,7 @@ class Assignment:
class DashboardClientsPeerAssignment:
def __init__(self, wireguardConfigurations: dict[str, WireguardConfiguration]):
self.logger = DashboardLogger()
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.wireguardConfigurations = wireguardConfigurations
self.dashboardClientsPeerAssignmentTable = db.Table(
@@ -41,10 +41,10 @@ class DashboardClientsPeerAssignment:
db.Column('ConfigurationName', db.String(255)),
db.Column('PeerID', db.String(500)),
db.Column('AssignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('UnassignedDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)),
extend_existing=True
)
self.metadata.create_all(self.engine)

View File

@@ -3,19 +3,19 @@ import hashlib
import uuid
import sqlalchemy as db
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
class DashboardClientsTOTP:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.dashboardClientsTOTPTable = db.Table(
'DashboardClientsTOTPTokens', self.metadata,
db.Column("Token", db.String(500), primary_key=True, index=True),
db.Column("ClientID", db.String(500), index=True),
db.Column(
"ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP)
"ExpireTime", (db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP)
)
)
self.metadata.create_all(self.engine)

View File

@@ -7,7 +7,7 @@ import sqlalchemy as db
from datetime import datetime
from typing import Any
from flask import current_app
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from .Utilities import (
GetRemoteEndpoint, ValidateDNSAddress
)
@@ -47,7 +47,8 @@ class DashboardConfig:
"dashboard_sort": "status",
"dashboard_theme": "dark",
"dashboard_api_key": "false",
"dashboard_language": "en-US"
"dashboard_language": "en-US",
"log_level": "INFO"
},
"Peers": {
"peer_global_DNS": "1.1.1.1",
@@ -65,7 +66,8 @@ class DashboardConfig:
"host": "",
"port": "",
"username": "",
"password": ""
"password": "",
"prefix": ""
},
"Email":{
"server": "",
@@ -95,28 +97,14 @@ class DashboardConfig:
if not exist:
self.SetConfig(section, key, value, True)
self.engine = db.create_engine(ConnectionString('wgdashboard'))
self.SetConfig("Server", "version", DashboardConfig.DashboardVersion)
self.SaveConfig()
self.engine = db.create_engine(ConnectionString(default_db))
self.dbMetadata = db.MetaData()
self.__createAPIKeyTable()
self.DashboardAPIKeys = self.__getAPIKeys()
self.APIAccessed = False
self.SetConfig("Server", "version", DashboardConfig.DashboardVersion)
def getConnectionString(self, database) -> str or None:
sqlitePath = os.path.join(DashboardConfig.ConfigurationPath, "db")
if not os.path.isdir(sqlitePath):
os.mkdir(sqlitePath)
if self.GetConfig("Database", "type")[1] == "postgresql":
cn = f'postgresql+psycopg2://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
elif self.GetConfig("Database", "type")[1] == "mysql":
cn = f'mysql+mysqldb://{self.GetConfig("Database", "username")[1]}:{self.GetConfig("Database", "password")[1]}@{self.GetConfig("Database", "host")[1]}/{database}'
else:
cn = f'sqlite:///{os.path.join(sqlitePath, f"{database}.db")}'
if not database_exists(cn):
create_database(cn)
return cn
def __createAPIKeyTable(self):
self.apiKeyTable = db.Table('DashboardAPIKeys', self.dbMetadata,

View File

@@ -4,18 +4,18 @@ Dashboard Logger Class
import uuid
import sqlalchemy as db
from flask import current_app
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db, default_log_db
class DashboardLogger:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard_log"))
self.engine = db.create_engine(ConnectionString(default_log_db))
self.metadata = db.MetaData()
self.dashboardLoggerTable = db.Table('DashboardLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True),
db.Column('LogDate',
(db.DATETIME if 'sqlite:///' in ConnectionString("wgdashboard") else db.TIMESTAMP),
(db.DATETIME if 'sqlite:///' in ConnectionString(default_db) else db.TIMESTAMP),
server_default=db.func.now()),
db.Column('URL', db.String(255)),
db.Column('IP', db.String(255)),

View File

@@ -8,7 +8,7 @@ from datetime import datetime, timedelta
import requests
from pydantic import BaseModel, field_serializer
import sqlalchemy as db
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from flask import current_app
WebHookActions = ['peer_created', 'peer_deleted', 'peer_updated']
@@ -40,7 +40,7 @@ class WebHookSessionLogs(BaseModel):
class DashboardWebHooks:
def __init__(self, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.webHooksTable = db.Table(
'DashboardWebHooks', self.metadata,
@@ -201,7 +201,7 @@ class DashboardWebHooks:
class WebHookSession:
def __init__(self, webHook: WebHook, data: dict[str, str]):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.webHookSessionsTable = db.Table('DashboardWebHookSessions', self.metadata, autoload_with=self.engine)
self.webHook = webHook

View File

@@ -2,7 +2,7 @@ import uuid
from pydantic import BaseModel, field_serializer
import sqlalchemy as db
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
class NewConfigurationTemplate(BaseModel):
@@ -14,7 +14,7 @@ class NewConfigurationTemplate(BaseModel):
class NewConfigurationTemplates:
def __init__(self):
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.templatesTable = db.Table(
'NewConfigurationTemplates', self.metadata,

View File

@@ -4,12 +4,12 @@ Peer Job Logger
import uuid
import sqlalchemy as db
from flask import current_app
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_log_db
from .Log import Log
class PeerJobLogger:
def __init__(self, AllPeerJobs, DashboardConfig):
self.engine = db.create_engine(ConnectionString("wgdashboard_log"))
self.engine = db.create_engine(ConnectionString(default_log_db))
self.metadata = db.MetaData()
self.jobLogTable = db.Table('JobLog', self.metadata,
db.Column('LogID', db.String(255), nullable=False, primary_key=True),

View File

@@ -1,7 +1,7 @@
"""
Peer Jobs
"""
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_job_db
from .PeerJob import PeerJob
from .PeerJobLogger import PeerJobLogger
import sqlalchemy as db
@@ -11,7 +11,7 @@ from flask import current_app
class PeerJobs:
def __init__(self, DashboardConfig, WireguardConfigurations):
self.Jobs: list[PeerJob] = []
self.engine = db.create_engine(ConnectionString('wgdashboard_job'))
self.engine = db.create_engine(ConnectionString(default_job_db))
self.metadata = db.MetaData()
self.peerJobTable = db.Table('PeerJobs', self.metadata,
db.Column('JobID', db.String(255), nullable=False, primary_key=True),
@@ -141,7 +141,7 @@ class PeerJobs:
def runJob(self):
current_app.logger.info("Running scheduled jobs")
current_app.logger.debug("Running scheduled jobs")
needToDelete = []
self.__getJobs()
for job in self.Jobs:

View File

@@ -1,4 +1,4 @@
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from .PeerShareLink import PeerShareLink
import sqlalchemy as db
from datetime import datetime
@@ -10,7 +10,7 @@ Peer Share Links
class PeerShareLinks:
def __init__(self, DashboardConfig, WireguardConfigurations):
self.Links: list[PeerShareLink] = []
self.engine = db.create_engine(ConnectionString("wgdashboard"))
self.engine = db.create_engine(ConnectionString(default_db))
self.metadata = db.MetaData()
self.peerShareLinksTable = db.Table(
'PeerShareLinks', self.metadata,

View File

@@ -10,7 +10,7 @@ from datetime import datetime, timedelta
from itertools import islice
from flask import current_app
from .ConnectionString import ConnectionString
from .ConnectionString import ConnectionString, default_db
from .DashboardConfig import DashboardConfig
from .Peer import Peer
from .PeerJobs import PeerJobs
@@ -64,7 +64,7 @@ class WireguardConfiguration:
self.AllPeerShareLinks = AllPeerShareLinks
self.DashboardWebHooks = DashboardWebHooks
self.configPath = os.path.join(self.__getProtocolPath(), f'{self.Name}.conf')
self.engine: sqlalchemy.Engine = sqlalchemy.create_engine(ConnectionString("wgdashboard"))
self.engine: sqlalchemy.Engine = sqlalchemy.create_engine(ConnectionString(default_db))
self.metadata: sqlalchemy.MetaData = sqlalchemy.MetaData()
self.dbType = self.DashboardConfig.GetConfig("Database", "type")[1]
@@ -396,7 +396,7 @@ class WireguardConfiguration:
def getPeers(self):
tmpList = []
current_app.logger.info(f"Refreshing {self.Name} peer list")
current_app.logger.debug(f"Refreshing {self.Name} peer list")
if self.configurationFileChanged():
with open(self.configPath, 'r') as configFile:
@@ -405,7 +405,7 @@ class WireguardConfiguration:
content = configFile.read().split('\n')
try:
if "[Peer]" not in content:
current_app.logger.info(f"{self.Name} config has no [Peer] section")
current_app.logger.debug(f"{self.Name} config has no [Peer] section")
return
peerStarts = content.index("[Peer]")

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
},
"dependencies": {
"@volar/language-server": "2.4.23",
"@vue/language-server": "3.0.5",
"@vue/language-server": "3.0.7",
"@vuepic/vue-datepicker": "^11.0.2",
"@vueuse/core": "^13.5.0",
"@vueuse/shared": "^13.5.0",
@@ -26,21 +26,21 @@
"electron-builder": "^26.0.12",
"fuse.js": "^7.0.0",
"i": "^0.3.7",
"is-cidr": "^5.0.3",
"npm": "^10.5.0",
"is-cidr": "^6.0.0",
"npm": "^11.6.0",
"ol": "^10.2.1",
"pinia": "^3.0.3",
"pinia-plugin-persistedstate": "^4.5.0",
"qrcode": "^1.5.3",
"qrcodejs": "^1.0.0",
"simple-code-editor": "^2.0.9",
"uuid": "^11.1.0",
"uuid": "^13.0.0",
"vue": "^3.5.17",
"vue-chartjs": "^5.3.0",
"vue-router": "^4.2.5"
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.0",
"vite": "^7.0.5"
"vite": "^7.1.6"
}
}

View File

@@ -114,7 +114,7 @@ const data = computed(() => {
</h6>
</div>
<div class="progress" role="progressbar" style="height: 6px">
<div class="progress-bar bg-warning" :style="{width: `$ data?.Memory.SwapMemory.percent}%` }"></div>
<div class="progress-bar bg-warning" :style="{width: `${data?.Memory.SwapMemory.percent}%` }"></div>
</div>
</div>
</div>

View File

@@ -464,47 +464,6 @@ stop_wgd() {
fi
}
# ============= Docker Functions =============
startwgd_docker() {
_checkWireguard
printf "[WGDashboard][Docker] WireGuard configuration started\n"
{ date; start_core ; printf "\n\n"; } >> ./log/install.txt
gunicorn_start
}
start_core() {
# Re-assign config_files to ensure it includes any newly created configurations
local config_files=$(find /etc/wireguard -type f -name "*.conf")
# Set file permissions
find /etc/wireguard -type f -name "*.conf" -exec chmod 600 {} \;
find "$iptable_dir" -type f -name "*.sh" -exec chmod +x {} \;
# Start WireGuard for each config file
for file in $config_files; do
config_name=$(basename "$file" ".conf")
wg-quick up "$config_name"
done
}
newconf_wgd() {
local wg_port_listen=$wg_port
local wg_addr_range=$wg_net
private_key=$(wg genkey)
public_key=$(echo "$private_key" | wg pubkey)
cat <<EOF >"/etc/wireguard/wg0.conf"
[Interface]
PrivateKey = $private_key
Address = $wg_addr_range
ListenPort = $wg_port_listen
SaveConfig = true
PostUp = /opt/wireguarddashboard/src/iptable-rules/postup.sh
PreDown = /opt/wireguarddashboard/src/iptable-rules/postdown.sh
EOF
}
# ============= Docker Functions =============
start_wgd_debug() {
_checkWireguard
printf "[WGDashboard] Starting WGDashboard in the foreground.\n"
@@ -600,4 +559,4 @@ else
help
fi
fi
printf "%s\n" "$dashes"
printf "%s\n" "$dashes"

View File

@@ -0,0 +1,59 @@
[Peers]
remote_endpoint = <your-public-ip>
peer_global_dns = <your-chosen-dns>
peer_endpoint_allowed_ip = 0.0.0.0/0
peer_display_mode = grid
peer_mtu = 1420
peer_keep_alive = 21
[Server]
app_port = 10086
wg_conf_path = /etc/wireguard
awg_conf_path = /etc/amnezia/amneziawg
app_prefix =
app_ip = 0.0.0.0
auth_req = true
version = v4.3.0.1
dashboard_refresh_interval = 60000
dashboard_peer_list_display = grid
dashboard_sort = status
dashboard_theme = dark
dashboard_api_key = false
dashboard_language = en-US
[Account]
username = admin
password = $2b$12$nWgPW.4adylN2oMhTyS5AeoiAvDj9SZxnXS.lCMkJYCV6jytmHKzu
enable_totp = false
totp_verified = false
totp_key = UOXAUPDDUNFTTHXZNQI4J4BWCEJZ63HF
[Other]
welcome_session = true
[Database]
type = sqlite
host =
port =
username =
password =
[Email]
server =
port =
encryption =
username =
email_password =
authentication_required = true
send_from =
email_template =
[OIDC]
admin_enable = false
client_enable = false
[Clients]
enable = true
[WireGuardConfiguration]
autostart =