@@ -8,11 +8,13 @@
|
|||||||
|
|
||||||
You have found the easiest way to install & manage WireGuard on any Linux host!
|
You have found the easiest way to install & manage WireGuard on any Linux host!
|
||||||
|
|
||||||
|
<!-- markdownlint-disable MD033 -->
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./assets/screenshot.png" width="802" />
|
<img src="./assets/screenshot.png" alt="screenshot" width="802" />
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* All-in-one: WireGuard + Web UI.
|
* All-in-one: WireGuard + Web UI.
|
||||||
* Easy installation, simple to use.
|
* Easy installation, simple to use.
|
||||||
* List, create, edit, delete, enable & disable clients.
|
* List, create, edit, delete, enable & disable clients.
|
||||||
@@ -26,6 +28,7 @@ You have found the easiest way to install & manage WireGuard on any Linux host!
|
|||||||
* UI_TRAFFIC_STATS (default off)
|
* UI_TRAFFIC_STATS (default off)
|
||||||
* UI_SHOW_LINKS (default off)
|
* UI_SHOW_LINKS (default off)
|
||||||
* WG_ENABLE_EXPIRES_TIME (default off)
|
* WG_ENABLE_EXPIRES_TIME (default off)
|
||||||
|
* Prometheus metrics support
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
@@ -34,7 +37,7 @@ You have found the easiest way to install & manage WireGuard on any Linux host!
|
|||||||
|
|
||||||
## Versions
|
## Versions
|
||||||
|
|
||||||
We provide more then 1 docker image to get, this will help you decide which one is best for you. <br>
|
We provide more then 1 docker image to get, this will help you decide which one is best for you. <br\>
|
||||||
For **stable** versions instead of nightly or development please read **README** from the **production** branch!
|
For **stable** versions instead of nightly or development please read **README** from the **production** branch!
|
||||||
|
|
||||||
| tag | Branch | Example | Description |
|
| tag | Branch | Example | Description |
|
||||||
@@ -62,7 +65,7 @@ And log in again.
|
|||||||
|
|
||||||
To automatically install & run wg-easy, simply run:
|
To automatically install & run wg-easy, simply run:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name=wg-easy \
|
--name=wg-easy \
|
||||||
-e LANG=de \
|
-e LANG=de \
|
||||||
@@ -87,6 +90,8 @@ To automatically install & run wg-easy, simply run:
|
|||||||
|
|
||||||
The Web UI will now be available on `http://0.0.0.0:51821`.
|
The Web UI will now be available on `http://0.0.0.0:51821`.
|
||||||
|
|
||||||
|
The Prometheus metrics will now be available on `http://0.0.0.0:51821/metrics`. Grafana dashboard [21733](https://grafana.com/grafana/dashboards/21733-wireguard/)
|
||||||
|
|
||||||
> 💡 Your configuration files will be saved in `~/.wg-easy`
|
> 💡 Your configuration files will be saved in `~/.wg-easy`
|
||||||
|
|
||||||
WireGuard Easy can be launched with Docker Compose as well - just download
|
WireGuard Easy can be launched with Docker Compose as well - just download
|
||||||
@@ -109,7 +114,7 @@ These options can be configured by setting environment variables using `-e KEY="
|
|||||||
| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. |
|
| `WG_HOST` | - | `vpn.myserver.com` | The public hostname of your VPN server. |
|
||||||
| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. |
|
| `WG_DEVICE` | `eth0` | `ens6f0` | Ethernet device the wireguard traffic should be forwarded through. |
|
||||||
| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. |
|
| `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will listen on that (othwise default) inside the Docker container. |
|
||||||
| `WG_CONFIG_PORT`| `51820` | `12345` | The UDP port used on [Home Assistant Plugin](https://github.com/adriy-be/homeassistant-addons-jdeath/tree/main/wgeasy)
|
| `WG_CONFIG_PORT`| `51820` | `12345` | The UDP port used on [Home Assistant Plugin](https://github.com/adriy-be/homeassistant-addons-jdeath/tree/main/wgeasy)
|
||||||
| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. |
|
| `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. |
|
||||||
| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. |
|
| `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. |
|
||||||
| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. |
|
| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. |
|
||||||
@@ -126,7 +131,7 @@ These options can be configured by setting environment variables using `-e KEY="
|
|||||||
| `UI_SHOW_LINKS` | `false` | `true` | Enable display of a short download link in Web UI |
|
| `UI_SHOW_LINKS` | `false` | `true` | Enable display of a short download link in Web UI |
|
||||||
| `MAX_AGE` | `0` | `1440` | The maximum age of Web UI sessions in minutes. `0` means that the session will exist until the browser is closed. |
|
| `MAX_AGE` | `0` | `1440` | The maximum age of Web UI sessions in minutes. `0` means that the session will exist until the browser is closed. |
|
||||||
| `UI_ENABLE_SORT_CLIENTS` | `false` | `true` | Enable UI sort clients by name |
|
| `UI_ENABLE_SORT_CLIENTS` | `false` | `true` | Enable UI sort clients by name |
|
||||||
|
| `ENABLE_PROMETHEUS_METRICS` | `true` | `true` | Enable Prometheus metrics `http://0.0.0.0:51821/metrics` and `http://0.0.0.0:51821/metrics/json`|
|
||||||
|
|
||||||
> If you change `WG_PORT`, make sure to also change the exposed port.
|
> If you change `WG_PORT`, make sure to also change the exposed port.
|
||||||
|
|
||||||
|
|||||||
@@ -13,5 +13,5 @@ services:
|
|||||||
- NET_ADMIN
|
- NET_ADMIN
|
||||||
- SYS_MODULE
|
- SYS_MODULE
|
||||||
environment:
|
environment:
|
||||||
# - PASSWORD=p
|
# - PASSWORD_HASH=$$2y$$10$$hBCoykrB95WSzuV4fafBzOHWKu9sbyVa34GJr8VV5R/pIelfEMYyG # 'foobar123'
|
||||||
- WG_HOST=192.168.1.233
|
- WG_HOST=192.168.1.233
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ services:
|
|||||||
# - UI_SHOW_LINKS=true
|
# - UI_SHOW_LINKS=true
|
||||||
# - UI_ENABLE_SORT_CLIENTS=true
|
# - UI_ENABLE_SORT_CLIENTS=true
|
||||||
# - WG_ENABLE_EXPIRES_TIME=true
|
# - WG_ENABLE_EXPIRES_TIME=true
|
||||||
|
# - ENABLE_PROMETHEUS_METRICS=false
|
||||||
|
|
||||||
image: ghcr.io/wg-easy/wg-easy
|
image: ghcr.io/wg-easy/wg-easy
|
||||||
container_name: wg-easy
|
container_name: wg-easy
|
||||||
|
|||||||
@@ -41,3 +41,4 @@ module.exports.UI_CHART_TYPE = process.env.UI_CHART_TYPE || 0;
|
|||||||
module.exports.UI_SHOW_LINKS = process.env.UI_SHOW_LINKS || 'false';
|
module.exports.UI_SHOW_LINKS = process.env.UI_SHOW_LINKS || 'false';
|
||||||
module.exports.UI_ENABLE_SORT_CLIENTS = process.env.UI_ENABLE_SORT_CLIENTS || 'false';
|
module.exports.UI_ENABLE_SORT_CLIENTS = process.env.UI_ENABLE_SORT_CLIENTS || 'false';
|
||||||
module.exports.WG_ENABLE_EXPIRES_TIME = process.env.WG_ENABLE_EXPIRES_TIME || 'false';
|
module.exports.WG_ENABLE_EXPIRES_TIME = process.env.WG_ENABLE_EXPIRES_TIME || 'false';
|
||||||
|
module.exports.ENABLE_PROMETHEUS_METRICS = process.env.ENABLE_PROMETHEUS_METRICS || 'true';
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const {
|
|||||||
UI_SHOW_LINKS,
|
UI_SHOW_LINKS,
|
||||||
UI_ENABLE_SORT_CLIENTS,
|
UI_ENABLE_SORT_CLIENTS,
|
||||||
WG_ENABLE_EXPIRES_TIME,
|
WG_ENABLE_EXPIRES_TIME,
|
||||||
|
ENABLE_PROMETHEUS_METRICS,
|
||||||
} = require('../config');
|
} = require('../config');
|
||||||
|
|
||||||
const requiresPassword = !!PASSWORD_HASH;
|
const requiresPassword = !!PASSWORD_HASH;
|
||||||
@@ -286,6 +287,20 @@ module.exports = class Server {
|
|||||||
const { expireDate } = await readBody(event);
|
const { expireDate } = await readBody(event);
|
||||||
await WireGuard.updateClientExpireDate({ clientId, expireDate });
|
await WireGuard.updateClientExpireDate({ clientId, expireDate });
|
||||||
return { success: true };
|
return { success: true };
|
||||||
|
}))
|
||||||
|
.get('/metrics', defineEventHandler(async (event) => {
|
||||||
|
setHeader(event, 'Content-Type', 'text/plain');
|
||||||
|
if (ENABLE_PROMETHEUS_METRICS === 'true') {
|
||||||
|
return WireGuard.getMetrics();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}))
|
||||||
|
.get('/metrics/json', defineEventHandler(async (event) => {
|
||||||
|
setHeader(event, 'Content-Type', 'application/json');
|
||||||
|
if (ENABLE_PROMETHEUS_METRICS === 'true') {
|
||||||
|
return WireGuard.getMetricsJSON();
|
||||||
|
}
|
||||||
|
return '';
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const safePathJoin = (base, target) => {
|
const safePathJoin = (base, target) => {
|
||||||
|
|||||||
@@ -158,6 +158,7 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
|
|||||||
latestHandshakeAt: null,
|
latestHandshakeAt: null,
|
||||||
transferRx: null,
|
transferRx: null,
|
||||||
transferTx: null,
|
transferTx: null,
|
||||||
|
endpoint: null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// Loop WireGuard status
|
// Loop WireGuard status
|
||||||
@@ -186,6 +187,7 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
|
|||||||
client.latestHandshakeAt = latestHandshakeAt === '0'
|
client.latestHandshakeAt = latestHandshakeAt === '0'
|
||||||
? null
|
? null
|
||||||
: new Date(Number(`${latestHandshakeAt}000`));
|
: new Date(Number(`${latestHandshakeAt}000`));
|
||||||
|
client.endpoint = endpoint === '(none)' ? null : endpoint;
|
||||||
client.transferRx = Number(transferRx);
|
client.transferRx = Number(transferRx);
|
||||||
client.transferTx = Number(transferTx);
|
client.transferTx = Number(transferTx);
|
||||||
client.persistentKeepalive = persistentKeepalive;
|
client.persistentKeepalive = persistentKeepalive;
|
||||||
@@ -398,4 +400,75 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getMetrics() {
|
||||||
|
const clients = await this.getClients();
|
||||||
|
let wireguardPeerCount = 0;
|
||||||
|
let wireguardEnabledPeersCount = 0;
|
||||||
|
let wireguardConnectedPeersCount = 0;
|
||||||
|
let wireguardSentBytes = '';
|
||||||
|
let wireguardReceivedBytes = '';
|
||||||
|
let wireguardLatestHandshakeSeconds = '';
|
||||||
|
for (const client of Object.values(clients)) {
|
||||||
|
wireguardPeerCount++;
|
||||||
|
if (client.enabled === true) {
|
||||||
|
wireguardEnabledPeersCount++;
|
||||||
|
}
|
||||||
|
if (client.endpoint !== null) {
|
||||||
|
wireguardConnectedPeersCount++;
|
||||||
|
}
|
||||||
|
wireguardSentBytes += `wireguard_sent_bytes{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${Number(client.transferTx)}\n`;
|
||||||
|
wireguardReceivedBytes += `wireguard_received_bytes{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${Number(client.transferRx)}\n`;
|
||||||
|
wireguardLatestHandshakeSeconds += `wireguard_latest_handshake_seconds{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${client.latestHandshakeAt ? (new Date().getTime() - new Date(client.latestHandshakeAt).getTime()) / 1000 : 0}\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let returnText = '# HELP wg-easy and wireguard metrics\n';
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_configured_peers\n';
|
||||||
|
returnText += '# TYPE wireguard_configured_peers gauge\n';
|
||||||
|
returnText += `wireguard_configured_peers{interface="wg0"} ${Number(wireguardPeerCount)}\n`;
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_enabled_peers\n';
|
||||||
|
returnText += '# TYPE wireguard_enabled_peers gauge\n';
|
||||||
|
returnText += `wireguard_enabled_peers{interface="wg0"} ${Number(wireguardEnabledPeersCount)}\n`;
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_connected_peers\n';
|
||||||
|
returnText += '# TYPE wireguard_connected_peers gauge\n';
|
||||||
|
returnText += `wireguard_connected_peers{interface="wg0"} ${Number(wireguardConnectedPeersCount)}\n`;
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_sent_bytes Bytes sent to the peer\n';
|
||||||
|
returnText += '# TYPE wireguard_sent_bytes counter\n';
|
||||||
|
returnText += `${wireguardSentBytes}`;
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_received_bytes Bytes received from the peer\n';
|
||||||
|
returnText += '# TYPE wireguard_received_bytes counter\n';
|
||||||
|
returnText += `${wireguardReceivedBytes}`;
|
||||||
|
|
||||||
|
returnText += '\n# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake\n';
|
||||||
|
returnText += '# TYPE wireguard_latest_handshake_seconds gauge\n';
|
||||||
|
returnText += `${wireguardLatestHandshakeSeconds}`;
|
||||||
|
|
||||||
|
return returnText;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMetricsJSON() {
|
||||||
|
const clients = await this.getClients();
|
||||||
|
let wireguardPeerCount = 0;
|
||||||
|
let wireguardEnabledPeersCount = 0;
|
||||||
|
let wireguardConnectedPeersCount = 0;
|
||||||
|
for (const client of Object.values(clients)) {
|
||||||
|
wireguardPeerCount++;
|
||||||
|
if (client.enabled === true) {
|
||||||
|
wireguardEnabledPeersCount++;
|
||||||
|
}
|
||||||
|
if (client.endpoint !== null) {
|
||||||
|
wireguardConnectedPeersCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
wireguard_configured_peers: Number(wireguardPeerCount),
|
||||||
|
wireguard_enabled_peers: Number(wireguardEnabledPeersCount),
|
||||||
|
wireguard_connected_peers: Number(wireguardConnectedPeersCount),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user