mirror of
https://github.com/WGDashboard/WGDashboard-PRW.git
synced 2026-08-03 22:42:57 +00:00
feat: add docker files and fix dayjs build bug
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
#
|
||||
# AWG GOLANG BUILDING STAGE
|
||||
# Base: Alpine
|
||||
#
|
||||
|
||||
# Pull the current golang-alpine image.
|
||||
FROM golang:1.25-alpine3.23 AS awg-go
|
||||
|
||||
# Install build-dependencies.
|
||||
RUN apk add --no-cache \
|
||||
git \
|
||||
gcc \
|
||||
musl-dev
|
||||
|
||||
# Standard working directory for WGDashboard
|
||||
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 version && \
|
||||
go mod download && \
|
||||
go mod verify && \
|
||||
go build -ldflags '-linkmode external -extldflags "-fno-PIC -static"' -v -o /usr/bin
|
||||
#
|
||||
# AWG TOOLS BUILDING STAGE
|
||||
# Base: Alpine
|
||||
#
|
||||
FROM alpine:3.23 AS awg-tools
|
||||
|
||||
# Install needed dependencies.
|
||||
RUN apk add --no-cache \
|
||||
make \
|
||||
git \
|
||||
build-base \
|
||||
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.14-alpine3.23 AS pip-builder
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
|
||||
# Add the build dependencies and create a Python virtual environment.
|
||||
RUN apk add --no-cache \
|
||||
build-base \
|
||||
pkgconfig \
|
||||
python3-dev \
|
||||
postgresql-dev \
|
||||
libffi-dev \
|
||||
libpq \
|
||||
linux-headers \
|
||||
rust \
|
||||
cargo \
|
||||
&& 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
|
||||
RUN if [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \
|
||||
sed -i 's|psycopg\[binary\]|psycopg[c]|' /opt/wgdashboard/src/requirements.txt; \
|
||||
fi; \
|
||||
cat /opt/wgdashboard/src/requirements.txt
|
||||
|
||||
# Install the pip packages
|
||||
RUN . /opt/wgdashboard/src/venv/bin/activate && \
|
||||
pip3 install --upgrade pip && \
|
||||
pip3 install -r /opt/wgdashboard/src/requirements.txt
|
||||
|
||||
#
|
||||
# WGDashboard RUNNING STAGE
|
||||
# Base: Alpine
|
||||
#
|
||||
|
||||
# Running with the python-alpine image.
|
||||
FROM python:3.14-alpine3.23 AS final
|
||||
LABEL maintainer="dselen@nerthus.nl"
|
||||
|
||||
# Install only the runtime dependencies
|
||||
RUN apk add --no-cache \
|
||||
iproute2 iptables \
|
||||
bash curl procps openrc \
|
||||
tzdata wireguard-tools envsubst
|
||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||
|
||||
# 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
|
||||
|
||||
# Environment variables
|
||||
ARG wg_net="10.0.0.1"
|
||||
ARG wg_subn="24"
|
||||
ARG wg_port="51820"
|
||||
ENV TZ="Europe/Amsterdam" \
|
||||
global_dns="9.9.9.9" \
|
||||
wgd_port="10086" \
|
||||
public_ip="" \
|
||||
WGDASH=/opt/wgdashboard
|
||||
|
||||
# Create directories needed for operation
|
||||
RUN mkdir /data /configs -p ${WGDASH}/src /etc/amnezia/amneziawg \
|
||||
&& echo "name_servers=${global_dns}" >> /etc/resolvconf.conf
|
||||
|
||||
# Copy the venv and source files from local compiled locations or repos
|
||||
COPY ./src ${WGDASH}/src
|
||||
COPY --from=pip-builder /opt/wgdashboard/src/venv /opt/wgdashboard/src/venv
|
||||
COPY ./docker/templates/wg0.conf /tmp/wg0.conf.template
|
||||
COPY ./docker/templates/wgdashboard-oidc-providers.json /tmp/wg-dashboard-oidc-providers.json.template
|
||||
# Copy in the runtime script, essential.
|
||||
COPY ./docker/entrypoint.sh /entrypoint.sh
|
||||
|
||||
# First WireGuard interface template
|
||||
RUN export out_adapt=$(ip -o -4 route show to default | awk '{print $NF}') \
|
||||
&& envsubst < /tmp/wg0.conf.template > /configs/wg0.conf.template \
|
||||
&& chmod 600 /configs/wg0.conf.template \
|
||||
&& cat /configs/wg0.conf.template
|
||||
|
||||
# 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
|
||||
|
||||
# Expose ports on the container
|
||||
EXPOSE 10086
|
||||
WORKDIR $WGDASH/src
|
||||
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
@@ -0,0 +1,217 @@
|
||||
# WGDashboard Docker Explanation:
|
||||
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 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>
|
||||
<img
|
||||
src="https://wgdashboard-resources.tor1.cdn.digitaloceanspaces.com/Logos/Logo-2-Rounded-512x512.png"
|
||||
alt="WG-Dashboard Logo"
|
||||
title="WG-Dashboard Logo"
|
||||
style="display: block; margin: 0 auto;"
|
||||
width="150"
|
||||
height="150"
|
||||
/>
|
||||
<br>
|
||||
|
||||
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>, <branch-name> (if built) 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 the Github Container Registry (ghcr.io), Docker Hub (docker.io) or build it yourself. The image is available at:
|
||||
|
||||
> `docker.io` is in most cases automatically resolved by the Docker application. Therefor you can ofter specify: `donaldzou/wgdashboard:latest`
|
||||
|
||||
### 🔧 Quick Docker Run Command
|
||||
|
||||
Here's an example to get it up and running quickly:
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name wgdashboard \
|
||||
--restart unless-stopped \
|
||||
-p 10086:10086/tcp \
|
||||
-p 51820:51820/udp \
|
||||
--cap-add NET_ADMIN \
|
||||
ghcr.io/wgdashboard/wgdashboard:latest
|
||||
```
|
||||
|
||||
> ⚠️ The default WireGuard port is `51820/udp`. If you change this, update the `/etc/wireguard/wg0.conf` accordingly.
|
||||
|
||||
---
|
||||
|
||||
### 📦 Docker Compose Alternative (see the [compose file](./compose.yaml))
|
||||
|
||||
You can also use Docker Compose for easier configuration:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
wgdashboard:
|
||||
image: ghcr.io/wgdashboard/wgdashboard:latest
|
||||
restart: unless-stopped
|
||||
container_name: wgdashboard
|
||||
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:
|
||||
```
|
||||
|
||||
> 📁 You can customize the **volume paths** on the host to fit your needs. The example above uses Docker volumes.
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Updating the Container
|
||||
|
||||
Updating the WGDashboard container should be through 'The Docker Way' - by pulling the newest/newer image and replacing this old one.
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Environment Variables
|
||||
|
||||
| Variable | Accepted Values | Default | Example | Description |
|
||||
| ------------------ | ---------------------------------------- | ----------------------- | --------------------- | ----------------------------------------------------------------------- |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `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. |
|
||||
| `database_type` | `sqlite`, `postgresql`, `mariadb+mariadbconnector`, etc. | `-` | `postgresql` | Type of [sqlalchemy database engine](https://docs.sqlalchemy.org/en/21/core/engines.html). |
|
||||
| `database_host` | Any non-empty string | `-` | `localhost` | IP-Address or hostname of the SQL-database server. |
|
||||
| `database_port` | Any non-empty string (or int for port) | `-` | `5432` | Port for the database communication. |
|
||||
| `database_username`| Valid database username | `-` | `database_user` | Database user username. |
|
||||
| `database_password`| Valid database password | `-` | `database_password` | Database user password. |
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Port Forwarding Note
|
||||
|
||||
When using multiple WireGuard interfaces, remember to **open their respective ports** on the host.
|
||||
|
||||
Examples:
|
||||
```yaml
|
||||
# Individual mapping
|
||||
- 51821:51821/udp
|
||||
|
||||
# Or port range
|
||||
- 51820-51830:51820-51830/udp
|
||||
```
|
||||
|
||||
> 🚨 **Security Tip:** Only expose ports you actually use.
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Building the Image Yourself
|
||||
|
||||
To build from source:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/WGDashboard/WGDashboard.git
|
||||
cd WGDashboard
|
||||
docker build . -f docker/Dockerfile -t yourname/wgdashboard:latest
|
||||
```
|
||||
|
||||
Example output:
|
||||
```shell
|
||||
docker images
|
||||
|
||||
REPOSITORY TAG IMAGE ID CREATED SIZE
|
||||
yourname/wgdashboard latest c96fd96ee3b3 42 minutes ago 314MB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Dockerfile Overview
|
||||
|
||||
Here's a brief overview of the Dockerfile stages used in the image build:
|
||||
|
||||
### 1. **Build Tools & Go Compilation**
|
||||
|
||||
```Dockerfile
|
||||
FROM golang:1.24 AS compiler
|
||||
WORKDIR /go
|
||||
|
||||
RUN apt-get update && apt-get install -y ...
|
||||
RUN git clone ... && make
|
||||
...
|
||||
```
|
||||
|
||||
### 2. **Binary Copy to Scratch**
|
||||
|
||||
```Dockerfile
|
||||
FROM scratch AS bins
|
||||
COPY --from=compiler /go/amneziawg-go/amneziawg-go /amneziawg-go
|
||||
...
|
||||
```
|
||||
|
||||
### 3. **Final Alpine Container Setup**
|
||||
|
||||
```Dockerfile
|
||||
FROM alpine:latest
|
||||
COPY --from=bins ...
|
||||
RUN apk update && apk add --no-cache ...
|
||||
COPY ./src ${WGDASH}/src
|
||||
COPY ./docker/entrypoint.sh /entrypoint.sh
|
||||
...
|
||||
EXPOSE 10086
|
||||
ENTRYPOINT ["/bin/bash", "/entrypoint.sh"]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Entrypoint Overview
|
||||
|
||||
### Major Functions:
|
||||
|
||||
- **`ensure_installation`**: Sets up the app, database, and Python environment.
|
||||
- **`set_envvars`**: Writes `wg-dashboard.ini` and applies environment variables.
|
||||
- **`start_core`**: Starts the main WGDashboard service.
|
||||
- **`ensure_blocking`**: Tails the error log to keep the container process alive.
|
||||
|
||||
---
|
||||
|
||||
## ✅ Final Notes
|
||||
|
||||
- Use `docker logs wgdashboard` for troubleshooting.
|
||||
- Access the web interface via `http://your-ip:10086` (or whichever port you specified in the compose).
|
||||
- The first time run will auto-generate WireGuard keys and configs (configs are generated from the template).
|
||||
|
||||
## Closing remarks:
|
||||
|
||||
For feedback please submit an issue to the repository. Or message dselen@nerthus.nl.
|
||||
@@ -0,0 +1,43 @@
|
||||
services:
|
||||
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:v4.3.2-dev
|
||||
|
||||
# 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 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:
|
||||
#- wg_autostart=wg0
|
||||
#- 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:
|
||||
- 10087: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:
|
||||
data:
|
||||
@@ -0,0 +1,329 @@
|
||||
#!/bin/bash
|
||||
|
||||
config_file="/data/wg-dashboard.ini"
|
||||
runtime_pid=""
|
||||
|
||||
trap 'stop_service' SIGTERM
|
||||
|
||||
# Hash password with bcrypt
|
||||
hash_password() {
|
||||
${WGDASH}/src/venv/bin/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)
|
||||
|
||||
# Dont 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() {
|
||||
echo "[WGDashboard] Stopping WGDashboard..."
|
||||
|
||||
local max_rounds="10"
|
||||
local round="0"
|
||||
local runtime_pid=""
|
||||
|
||||
while true; do
|
||||
round=$((round + 1))
|
||||
|
||||
if [[ -f ${WGDASH}/src/gunicorn.pid ]]; then
|
||||
runtime_pid=$(cat ${WGDASH}/src/gunicorn.pid)
|
||||
|
||||
echo "Running as PID: ${runtime_pid}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ $round -eq $max_rounds ]]; then
|
||||
echo "Reached breaking point!"
|
||||
return 1
|
||||
|
||||
fi
|
||||
|
||||
sleep 0.5s
|
||||
done
|
||||
|
||||
kill $runtime_pid
|
||||
exit 0
|
||||
}
|
||||
|
||||
echo "------------------------- START ----------------------------"
|
||||
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
|
||||
|
||||
# PERSISTENCE FOR databases directory
|
||||
# Create required directories and links
|
||||
if [ ! -d "/data/db" ]; then
|
||||
echo "Creating database dir"
|
||||
mkdir -p /data/db
|
||||
fi
|
||||
|
||||
if [[ ! -L "${WGDASH}/src/db" ]] && [[ -d "${WGDASH}/src/db" ]]; then
|
||||
echo "Removing ${WGDASH}/src/db since its not a symbolic link."
|
||||
rm -rfv "${WGDASH}/src/db"
|
||||
fi
|
||||
if [[ -L "${WGDASH}/src/db" ]]; then
|
||||
echo "${WGDASH}/src/db is a symbolic link."
|
||||
else
|
||||
ln -sv /data/db "${WGDASH}/src/db"
|
||||
fi
|
||||
|
||||
# PERSISTENCE FOR wg-dashboard-oidc-providers.json
|
||||
if [ ! -f "/data/wg-dashboard-oidc-providers.json" ]; then
|
||||
echo "Creating wg-dashboard-oidc-providers.json file"
|
||||
cp -v /tmp/wg-dashboard-oidc-providers.json.template /data/wg-dashboard-oidc-providers.json
|
||||
fi
|
||||
if [[ ! -L "${WGDASH}/src/wg-dashboard-oidc-providers.json" ]] && [[ -f "${WGDASH}/src/wg-dashboard-oidc-providers.json" ]]; then
|
||||
echo "Removing ${WGDASH}/src/wg-dashboard-oidc-providers.json since its not a symbolic link."
|
||||
rm -fv "${WGDASH}/src/wg-dashboard-oidc-providers.json"
|
||||
fi
|
||||
if [[ -L "${WGDASH}/src/wg-dashboard-oidc-providers.json" ]]; then
|
||||
echo "${WGDASH}/src/wg-dashboard-oidc-providers.json is a symbolic link."
|
||||
else
|
||||
ln -sv /data/wg-dashboard-oidc-providers.json "${WGDASH}/src/wg-dashboard-oidc-providers.json"
|
||||
fi
|
||||
|
||||
# PERSISTENCE FOR wg-dashboard.ini
|
||||
if [ ! -f "${config_file}" ]; then
|
||||
echo "Creating wg-dashboard.ini file"
|
||||
touch "${config_file}"
|
||||
fi
|
||||
if [[ ! -L "${WGDASH}/src/wg-dashboard.ini" ]] && [[ -f "${WGDASH}/src/wg-dashboard.ini" ]]; then
|
||||
echo "Removing ${WGDASH}/src/wg-dashboard.ini since its not a symbolic link."
|
||||
rm -fv "${WGDASH}/src/wg-dashboard.ini"
|
||||
fi
|
||||
if [[ -L "${WGDASH}/src/wg-dashboard.ini" ]]; then
|
||||
echo "${WGDASH}/src/wg-dashboard.ini is a symbolic link."
|
||||
else
|
||||
ln -sv "${config_file}" "${WGDASH}/src/wg-dashboard.ini"
|
||||
fi
|
||||
|
||||
# Setup WireGuard if needed
|
||||
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."
|
||||
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 https://ifconfig.me)
|
||||
if [ -z "${public_ip}" ]; then
|
||||
echo "Using fallback public IP resolution website"
|
||||
public_ip=$(curl -s https://api.ipify.org)
|
||||
fi
|
||||
if [ -z "${public_ip}" ]; then
|
||||
echo "Failed to resolve publicly. Using private address."
|
||||
public_ip=$(hostname -i)
|
||||
fi
|
||||
echo "Automatically detected public IP: ${public_ip}"
|
||||
fi
|
||||
|
||||
set_ini Peers remote_endpoint "${public_ip}"
|
||||
set_ini Server app_port "${wgd_port}"
|
||||
|
||||
# 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
|
||||
|
||||
# Database (check if any settings need to be configured)
|
||||
database_vars=("database_type" "database_host" "database_port" "database_username" "database_password")
|
||||
for var in "${database_vars[@]}"; do
|
||||
if [ -n "${!var}" ]; then
|
||||
echo "Configuring database settings:"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# Database (iterate through all possible fields)
|
||||
database_fields=("type:database_type" "host:database_host" "port:database_port"
|
||||
"username:database_username" "password:database_password")
|
||||
|
||||
for field_pair in "${database_fields[@]}"; do
|
||||
IFS=: read -r field var <<< "$field_pair"
|
||||
[[ -n "${!var}" ]] && set_ini Database "$field" "${!var}"
|
||||
done
|
||||
|
||||
# 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
|
||||
}
|
||||
|
||||
# Start service and monitor logs
|
||||
start_and_monitor() {
|
||||
printf "\n---------------------- STARTING CORE -----------------------\n"
|
||||
|
||||
# Due to resolvconf resetting the DNS we echo back the one we defined (or fallback to default).
|
||||
resolvconf -u
|
||||
|
||||
# Due to some instances complaining about this, making sure its there every time.
|
||||
mkdir -p /dev/net
|
||||
mknod /dev/net/tun c 10 200
|
||||
chmod 600 /dev/net/tun
|
||||
|
||||
# Actually starting WGDashboard
|
||||
echo "Starting WGDashboard directly with Gunicorn..."
|
||||
|
||||
[[ ! -d ${WGDASH}/src/log ]] && mkdir ${WGDASH}/src/log
|
||||
[[ ! -d ${WGDASH}/src/download ]] && mkdir ${WGDASH}/src/download
|
||||
|
||||
${WGDASH}/src/venv/bin/gunicorn --config ${WGDASH}/src/gunicorn.conf.py
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Loading WGDashboard failed... Look above for details."
|
||||
fi
|
||||
|
||||
# Wait a second before continuing, to give the python program some time to get ready.
|
||||
echo -e "\nEnsuring container continuation."
|
||||
|
||||
local max_rounds="10"
|
||||
local round="0"
|
||||
|
||||
# Hang in there for 10s for Gunicorn to get ready
|
||||
while true; do
|
||||
round=$((round + 1))
|
||||
|
||||
local latest_error=$(ls -t ${WGDASH}/src/log/error_*.log 2> /dev/null | head -n 1)
|
||||
|
||||
if [[ $round -eq $max_rounds ]]; then
|
||||
echo "Reached breaking point!"
|
||||
break
|
||||
|
||||
fi
|
||||
|
||||
if [[ -z $latest_error ]]; then
|
||||
echo -e "Logs not yet present! Retrying in 1 second!"
|
||||
sleep 1s
|
||||
|
||||
else
|
||||
break
|
||||
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if [[ -z $latest_error ]]; then
|
||||
echo -e "No error logs founds... Please investigate.\nExiting in 3 minutes..."
|
||||
sleep 180s
|
||||
exit 1
|
||||
|
||||
else
|
||||
tail -f "$latest_error" &
|
||||
tail_pid=$!
|
||||
|
||||
wait $tail_pid
|
||||
fi
|
||||
}
|
||||
|
||||
# Main execution flow
|
||||
ensure_installation
|
||||
set_envvars
|
||||
start_and_monitor
|
||||
@@ -0,0 +1,8 @@
|
||||
[Interface]
|
||||
Address = ${wg_net}/24
|
||||
PrivateKey =
|
||||
PostUp = iptables -t nat -I POSTROUTING 1 -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE; iptables -I FORWARD -i wg0 -o wg0 -j DROP
|
||||
PreDown = iptables -t nat -D POSTROUTING -s ${wg_net}/24 -o ${out_adapt} -j MASQUERADE; iptables -D FORWARD -i wg0 -o wg0 -j DROP
|
||||
ListenPort = ${wg_port}
|
||||
SaveConfig = true
|
||||
DNS = ${global_dns}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"Admin": {
|
||||
"Provider": {
|
||||
"client_id": "",
|
||||
"client_secret": "",
|
||||
"issuer": ""
|
||||
}
|
||||
},
|
||||
"Client": {
|
||||
"Provider": {
|
||||
"client_id": "",
|
||||
"client_secret": "",
|
||||
"issuer": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user