mirror of
https://github.com/donaldzou/WGDashboard.git
synced 2025-10-03 07:46:18 +00:00
Merge pull request #880 from WGDashboard/v4.3-dev-docker
V4.3 dev docker
This commit is contained in:
@@ -1,3 +0,0 @@
|
|||||||
FROM ubuntu:24.04
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get full-upgrade -y
|
|
@@ -92,11 +92,22 @@ Updating WGDashboard is currently in **alpha** stage. While the update process m
|
|||||||
## ⚙️ Environment Variables
|
## ⚙️ Environment Variables
|
||||||
|
|
||||||
| Variable | Accepted Values | Default | Example | Description |
|
| Variable | Accepted Values | Default | Example | Description |
|
||||||
|---------------|------------------------------------------|-------------------------|------------------------|-----------------------------------------------------------------------------|
|
| ------------------ | ---------------------------------------- | ----------------------- | --------------------- | ----------------------------------------------------------------------- |
|
||||||
| `tz` | Timezone | `Europe/Amsterdam` | `America/New_York` | Sets the container's timezone. Useful for accurate logs and scheduling. |
|
| `tz` | Timezone | `Europe/Amsterdam` | `America/New_York` | Sets the container's timezone. Useful for accurate logs and scheduling. |
|
||||||
| `global_dns` | IPv4 and IPv6 addresses | `9.9.9.9` | `8.8.8.8`, `1.1.1.1` | Default DNS for WireGuard clients. |
|
| `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 NAT’d. |
|
| `public_ip` | Public IP address | Retrieved automatically | `253.162.134.73` | Used to generate accurate client configs. Needed if container is NAT’d. |
|
||||||
| `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. |
|
| `wgd_port` | Any port that is allowed for the process | `10086` | `443` | This port is used to set the WGDashboard web port. |
|
||||||
|
| `username` | Any non‐empty string | `-` | `admin` | Username for the WGDashboard web interface account. |
|
||||||
|
| `password` | Any non‐empty string | `-` | `s3cr3tP@ss` | Password for the WGDashboard web interface account (stored hashed). |
|
||||||
|
| `enable_totp` | `true`, `false` | `true` | `false` | Enable TOTP‐based two‐factor authentication for the account. |
|
||||||
|
| `wg_autostart` | Wireguard interface name | `false` | `true` | Auto‐start the WireGuard client when the container launches. |
|
||||||
|
| `email_server` | SMTP server address | `-` | `smtp.gmail.com` | SMTP server for sending email notifications. |
|
||||||
|
| `email_port` | SMTP port number | `-` | `587` | Port for connecting to the SMTP server. |
|
||||||
|
| `email_encryption` | `TLS`, `SSL`, etc. | `-` | `TLS` | Encryption method for email communication. |
|
||||||
|
| `email_username` | Any non-empty string | `-` | `user@example.com` | Username for SMTP authentication. |
|
||||||
|
| `email_password` | Any non-empty string | `-` | `app_password` | Password for SMTP authentication. |
|
||||||
|
| `email_from` | Valid email address | `-` | `noreply@example.com` | Email address used as the sender for notifications. |
|
||||||
|
| `email_template` | Path to template file | `-` | `your-template` | Custom template for email notifications. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -1,10 +1,55 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Path to the configuration file (exists because of previous function).
|
|
||||||
config_file="/data/wg-dashboard.ini"
|
config_file="/data/wg-dashboard.ini"
|
||||||
|
|
||||||
trap 'stop_service' SIGTERM
|
trap 'stop_service' SIGTERM
|
||||||
|
|
||||||
|
# Hash password with bcrypt
|
||||||
|
hash_password() {
|
||||||
|
python3 -c "import bcrypt; print(bcrypt.hashpw('$1'.encode(), bcrypt.gensalt(12)).decode())"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Function to set or update section/key/value in the INI file
|
||||||
|
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
|
||||||
|
echo "- $key is already set correctly (value hidden)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sed -i "/^\[${section}\]/,/^\[/{s|^[[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|}" "$config_file"
|
||||||
|
echo "- Updated $key (value hidden)"
|
||||||
|
else
|
||||||
|
if [ "$current_value" = "$value" ]; then
|
||||||
|
echo "- $key is already set correctly ($value)"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
sed -i "/^\[${section}\]/,/^\[/{s|^[[:space:]]*${key}[[:space:]]*=.*|${key} = ${value}|}" "$config_file"
|
||||||
|
echo "- Updated $key to: $value"
|
||||||
|
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)"
|
||||||
|
else
|
||||||
|
echo "- Added new setting $key: $value"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
stop_service() {
|
stop_service() {
|
||||||
echo "[WGDashboard] Stopping WGDashboard..."
|
echo "[WGDashboard] Stopping WGDashboard..."
|
||||||
/bin/bash ./wgd.sh stop
|
/bin/bash ./wgd.sh stop
|
||||||
@@ -12,10 +57,9 @@ stop_service() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
echo "------------------------- START ----------------------------"
|
echo "------------------------- START ----------------------------"
|
||||||
echo "Starting the WireGuard Dashboard Docker container."
|
echo "Starting the WGDashboard Docker container."
|
||||||
|
|
||||||
ensure_installation() {
|
ensure_installation() {
|
||||||
# When using a custom directory to store the files, this part moves over and makes sure the installation continues.
|
|
||||||
echo "Quick-installing..."
|
echo "Quick-installing..."
|
||||||
|
|
||||||
# Make the wgd.sh script executable.
|
# Make the wgd.sh script executable.
|
||||||
@@ -33,24 +77,21 @@ ensure_installation() {
|
|||||||
echo "Removing clear command from wgd.sh for better Docker logging."
|
echo "Removing clear command from wgd.sh for better Docker logging."
|
||||||
sed -i '/clear/d' ./wgd.sh
|
sed -i '/clear/d' ./wgd.sh
|
||||||
|
|
||||||
# Create the databases directory if it does not exist yet.
|
# Create required directories and links
|
||||||
if [ ! -d "/data/db" ]; then
|
if [ ! -d "/data/db" ]; then
|
||||||
echo "Creating database dir"
|
echo "Creating database dir"
|
||||||
mkdir /data/db
|
mkdir -p /data/db
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Linking the database on the persistent directory location to where WGDashboard expects.
|
|
||||||
if [ ! -d "${WGDASH}/src/db" ]; then
|
if [ ! -d "${WGDASH}/src/db" ]; then
|
||||||
ln -s /data/db "${WGDASH}/src/db"
|
ln -s /data/db "${WGDASH}/src/db"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Create the wg-dashboard.ini file if it does not exist yet.
|
|
||||||
if [ ! -f "${config_file}" ]; then
|
if [ ! -f "${config_file}" ]; then
|
||||||
echo "Creating wg-dashboard.ini file"
|
echo "Creating wg-dashboard.ini file"
|
||||||
touch "${config_file}"
|
touch "${config_file}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Link the wg-dashboard.ini file from the persistent directory to where WGDashboard expects it.
|
|
||||||
if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then
|
if [ ! -f "${WGDASH}/src/wg-dashboard.ini" ]; then
|
||||||
ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
|
ln -s "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
|
||||||
fi
|
fi
|
||||||
@@ -63,15 +104,11 @@ ensure_installation() {
|
|||||||
|
|
||||||
echo "Looks like the installation succeeded. Moving on."
|
echo "Looks like the installation succeeded. Moving on."
|
||||||
|
|
||||||
# This first step is to ensure the wg0.conf file exists, and if not, then its copied over from the ephemeral container storage.
|
# Setup WireGuard if needed
|
||||||
# This is done so WGDashboard it works out of the box, it also sets a randomly generated private key.
|
|
||||||
|
|
||||||
if [ ! -f "/etc/wireguard/wg0.conf" ]; then
|
if [ ! -f "/etc/wireguard/wg0.conf" ]; then
|
||||||
echo "Standard wg0 Configuration file not found, grabbing template."
|
|
||||||
cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf"
|
cp -a "/configs/wg0.conf.template" "/etc/wireguard/wg0.conf"
|
||||||
|
|
||||||
echo "Setting a secure private key."
|
echo "Setting a secure private key."
|
||||||
|
|
||||||
local privateKey
|
local privateKey
|
||||||
privateKey=$(wg genkey)
|
privateKey=$(wg genkey)
|
||||||
sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf
|
sed -i "s|^PrivateKey *=.*$|PrivateKey = ${privateKey}|g" /etc/wireguard/wg0.conf
|
||||||
@@ -85,60 +122,72 @@ ensure_installation() {
|
|||||||
set_envvars() {
|
set_envvars() {
|
||||||
printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n"
|
printf "\n------------- SETTING ENVIRONMENT VARIABLES ----------------\n"
|
||||||
|
|
||||||
# Check if the file is empty
|
# Check if config file is empty
|
||||||
if [ ! -s "${config_file}" ]; then
|
if [ ! -s "${config_file}" ]; then
|
||||||
echo "Config file is empty. Creating [Peers] section."
|
echo "Config file is empty. Creating initial structure."
|
||||||
|
|
||||||
# Create [Peers] section with initial values
|
|
||||||
{
|
|
||||||
echo "[Peers]"
|
|
||||||
echo "peer_global_dns = ${global_dns}"
|
|
||||||
echo "remote_endpoint = ${public_ip}"
|
|
||||||
echo -e "\n[Server]"
|
|
||||||
echo "app_port = ${wgd_port}"
|
|
||||||
} > "${config_file}"
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "Config file is not empty, using pre-existing."
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Verifying current variables..."
|
echo "Checking basic configuration:"
|
||||||
|
set_ini Peers peer_global_dns "${global_dns}"
|
||||||
|
|
||||||
# Check and update the DNS if it has changed
|
if [ -z "${public_ip}" ]; then
|
||||||
current_dns=$(grep "peer_global_dns = " "${config_file}" | awk '{print $NF}')
|
public_ip=$(curl -s ifconfig.me)
|
||||||
if [ "${global_dns}" == "$current_dns" ]; then
|
echo "Automatically detected public IP: ${public_ip}"
|
||||||
echo "DNS is set correctly, moving on."
|
|
||||||
|
|
||||||
else
|
|
||||||
echo "Changing default DNS..."
|
|
||||||
sed -i "s/^peer_global_dns = .*/peer_global_dns = ${global_dns}/" "${config_file}"
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Checking the current set public IP and changing it if it has changed.
|
set_ini Peers remote_endpoint "${public_ip}"
|
||||||
current_public_ip=$(grep "remote_endpoint = " "${config_file}" | awk '{print $NF}')
|
set_ini Server app_port "${wgd_port}"
|
||||||
if [ "${public_ip}" == "" ]; then
|
|
||||||
default_ip=$(curl -s ifconfig.me)
|
|
||||||
|
|
||||||
echo "Trying to fetch the Public-IP using ifconfig.me: ${default_ip}"
|
# Account settings - process all parameters
|
||||||
sed -i "s/^remote_endpoint = .*/remote_endpoint = ${default_ip}/" "${config_file}"
|
[[ -n "$username" ]] && echo "Configuring user account:"
|
||||||
elif [ "${current_public_ip}" != "${public_ip}" ]; then
|
# Basic account variables
|
||||||
sed -i "s/^remote_endpoint = .*/remote_endpoint = ${public_ip}/" "${config_file}"
|
[[ -n "$username" ]] && set_ini Account username "${username}"
|
||||||
else
|
|
||||||
echo "Public-IP is correct, moving on."
|
if [[ -n "$password" ]]; then
|
||||||
|
echo "- Setting password"
|
||||||
|
set_ini Account password "$(hash_password "${password}")"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Checking the current WGDashboard web port and changing if needed.
|
# Additional account variables
|
||||||
current_wgd_port=$(grep "app_port = " "${config_file}" | awk '{print $NF}')
|
[[ -n "$enable_totp" ]] && set_ini Account enable_totp "${enable_totp}"
|
||||||
if [ "${current_wgd_port}" == "${wgd_port}" ]; then
|
[[ -n "$totp_verified" ]] && set_ini Account totp_verified "${totp_verified}"
|
||||||
echo "Current WGD port is set correctly, moving on."
|
[[ -n "$totp_key" ]] && set_ini Account totp_key "${totp_key}"
|
||||||
else
|
|
||||||
echo "Changing default WGD port..."
|
# Welcome session
|
||||||
sed -i "s/^app_port = .*/app_port = ${wgd_port}/" "${config_file}"
|
[[ -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
|
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
|
||||||
|
if [ -n "${!var}" ]; then
|
||||||
|
echo "Configuring email settings:"
|
||||||
|
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}"
|
||||||
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# === CORE SERVICES ===
|
# Start service and monitor logs
|
||||||
start_core() {
|
start_and_monitor() {
|
||||||
printf "\n---------------------- STARTING CORE -----------------------\n"
|
printf "\n---------------------- STARTING CORE -----------------------\n"
|
||||||
|
|
||||||
# Due to some instances complaining about this, making sure its there every time.
|
# Due to some instances complaining about this, making sure its there every time.
|
||||||
@@ -148,23 +197,19 @@ start_core() {
|
|||||||
|
|
||||||
# Actually starting WGDashboard
|
# Actually starting WGDashboard
|
||||||
echo "Activating Python venv and executing the WireGuard Dashboard service."
|
echo "Activating Python venv and executing the WireGuard Dashboard service."
|
||||||
/bin/bash ./wgd.sh start
|
bash ./wgd.sh start
|
||||||
}
|
|
||||||
|
|
||||||
ensure_blocking() {
|
|
||||||
# Wait a second before continuing, to give the python program some time to get ready.
|
# Wait a second before continuing, to give the python program some time to get ready.
|
||||||
sleep 1s
|
sleep 1
|
||||||
echo -e "\nEnsuring container continuation."
|
echo -e "\nEnsuring container continuation."
|
||||||
|
|
||||||
# Find and tail the latest error and access logs if they exist
|
# Find and monitor log file
|
||||||
local logdir="${WGDASH}/src/log"
|
local logdir="${WGDASH}/src/log"
|
||||||
|
|
||||||
latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1)
|
latestErrLog=$(find "$logdir" -name "error_*.log" -type f -print | sort -r | head -n 1)
|
||||||
|
|
||||||
# Only tail the logs if they are found
|
# Only tail the logs if they are found
|
||||||
if [ -n "$latestErrLog" ]; then
|
if [ -n "$latestErrLog" ]; then
|
||||||
tail -f "$latestErrLog" &
|
tail -f "$latestErrLog" &
|
||||||
|
|
||||||
# Wait for the tail process to end.
|
# Wait for the tail process to end.
|
||||||
wait $!
|
wait $!
|
||||||
else
|
else
|
||||||
@@ -173,8 +218,7 @@ ensure_blocking() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute functions for the WireGuard Dashboard services, then set the environment variables
|
# Main execution flow
|
||||||
ensure_installation
|
ensure_installation
|
||||||
set_envvars
|
set_envvars
|
||||||
start_core
|
start_and_monitor
|
||||||
ensure_blocking
|
|
@@ -174,12 +174,18 @@ class AmneziaWireguardConfiguration(WireguardConfiguration):
|
|||||||
|
|
||||||
def getPeers(self):
|
def getPeers(self):
|
||||||
self.Peers.clear()
|
self.Peers.clear()
|
||||||
|
current_app.logger.info(f"Refreshing {self.Name} peer list")
|
||||||
|
|
||||||
if self.configurationFileChanged():
|
if self.configurationFileChanged():
|
||||||
with open(self.configPath, 'r') as configFile:
|
with open(self.configPath, 'r') as configFile:
|
||||||
p = []
|
p = []
|
||||||
pCounter = -1
|
pCounter = -1
|
||||||
content = configFile.read().split('\n')
|
content = configFile.read().split('\n')
|
||||||
try:
|
try:
|
||||||
|
if "[Peer]" not in content:
|
||||||
|
current_app.logger.info(f"{self.Name} config has no [Peer] section")
|
||||||
|
return
|
||||||
|
|
||||||
peerStarts = content.index("[Peer]")
|
peerStarts = content.index("[Peer]")
|
||||||
content = content[peerStarts:]
|
content = content[peerStarts:]
|
||||||
for i in content:
|
for i in content:
|
||||||
|
@@ -397,13 +397,17 @@ class WireguardConfiguration:
|
|||||||
def getPeers(self):
|
def getPeers(self):
|
||||||
tmpList = []
|
tmpList = []
|
||||||
current_app.logger.info(f"Refreshing {self.Name} peer list")
|
current_app.logger.info(f"Refreshing {self.Name} peer list")
|
||||||
|
|
||||||
if self.configurationFileChanged():
|
if self.configurationFileChanged():
|
||||||
with open(self.configPath, 'r') as configFile:
|
with open(self.configPath, 'r') as configFile:
|
||||||
p = []
|
p = []
|
||||||
pCounter = -1
|
pCounter = -1
|
||||||
content = configFile.read().split('\n')
|
content = configFile.read().split('\n')
|
||||||
try:
|
try:
|
||||||
if "[Peer]" in content:
|
if "[Peer]" not in content:
|
||||||
|
current_app.logger.info(f"{self.Name} config has no [Peer] section")
|
||||||
|
return
|
||||||
|
|
||||||
peerStarts = content.index("[Peer]")
|
peerStarts = content.index("[Peer]")
|
||||||
content = content[peerStarts:]
|
content = content[peerStarts:]
|
||||||
for i in content:
|
for i in content:
|
||||||
@@ -469,8 +473,6 @@ class WireguardConfiguration:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
tmpList.append(Peer(tempPeer, self))
|
tmpList.append(Peer(tempPeer, self))
|
||||||
else:
|
|
||||||
current_app.logger.warning(f"{self.Name} is an empty configuration")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
current_app.logger.error(f"{self.Name} getPeers() Error", e)
|
current_app.logger.error(f"{self.Name} getPeers() Error", e)
|
||||||
else:
|
else:
|
||||||
|
Reference in New Issue
Block a user