Added wireguard service in container

This commit is contained in:
Capdeveloping 2022-06-25 16:33:48 +02:00
parent f43c59c043
commit a13b78b1f5
6 changed files with 212 additions and 89 deletions

View file

@ -13,11 +13,8 @@ RUN apk add --update --no-cache ${BUILD_DEPENDENCIES}
WORKDIR /build
# Add dependencies
COPY go.mod /build
COPY go.sum /build
COPY package.json /build
COPY yarn.lock /build
# Add sources
COPY . /build
# Prepare assets
RUN yarn install --pure-lockfile --production && \
@ -42,34 +39,30 @@ RUN mkdir -p assets/plugins && \
/build/node_modules/jquery-tags-input/ \
assets/plugins/
# Move custom assets
RUN cp -r /build/custom/ assets/
# Get go modules and build tool
RUN go mod download && \
go get github.com/GeertJohan/go.rice/rice
# Add sources
COPY . /build
# Move custom assets
RUN cp -r /build/custom/ assets/
# Build
RUN rice embed-go && \
CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -a -o wg-ui .
# Release stage
FROM alpine:3.11
FROM ubuntu:22.04
ENV TZ=Europe/Minsk
ENV DEBIAN_FRONTEND=noninteractive
RUN addgroup -S wgui && \
adduser -S -D -G wgui wgui
RUN apk --no-cache add ca-certificates
RUN apt-get update && apt upgrade -y && apt-get install -y wireguard wireguard-tools iptables iproute2
WORKDIR /app
RUN mkdir -p db
# Copy binary files
COPY --from=builder --chown=wgui:wgui /build/wg-ui /app
COPY --from=builder /build/wg-ui /app
RUN chmod +x wg-ui

View file

@ -9,6 +9,9 @@ A web user interface to manage your WireGuard setup.
- Authentication
- Manage extra client's information (name, email, etc)
- Retrieve configs using QR code / file
- start wireguard interface / rules
- stop wireguard interface / rules
- restart wireguard interface / rules
## Run WireGuard-UI
@ -32,8 +35,8 @@ docker-compose up
Note:
- There is a Status option that needs docker to be able to access the network of the host in order to read the
wireguard interface stats. See the `cap_add` and `network_mode` options on the docker-compose.yaml
- There is a Status option that needs docker to be able to access the network of the host in order to read the
wireguard interface stats. See the `cap_add` and `network_mode` options on the docker-compose.yaml
- Because the `network_mode` is set to `host`, we don't need to specify the exposed ports. The app will listen on port `5000` by default.
@ -100,72 +103,6 @@ EMAIL_FROM_ADDRESS: the sender's email address
EMAIL_FROM_NAME: the sender's name
```
## Auto restart WireGuard daemon
WireGuard-UI only takes care of configuration generation. You can use systemd to watch for the changes and restart the service. Following is an example:
### systemd
Create /etc/systemd/system/wgui.service
```
[Unit]
Description=Restart WireGuard
After=network.target
[Service]
Type=oneshot
ExecStart=/usr/bin/systemctl restart wg-quick@wg0.service
[Install]
RequiredBy=wgui.path
```
Create /etc/systemd/system/wgui.path
```
[Unit]
Description=Watch /etc/wireguard/wg0.conf for changes
[Path]
PathModified=/etc/wireguard/wg0.conf
[Install]
WantedBy=multi-user.target
```
Apply it
```
systemctl enable wgui.{path,service}
systemctl start wgui.{path,service}
```
### openrc
Create and `chmod +x` /usr/local/bin/wgui
```
#!/bin/sh
wg-quick down wg0
wg-quick up wg0
```
Create and `chmod +x` /etc/init.d/wgui
```
#!/sbin/openrc-run
command=/sbin/inotifyd
command_args="/usr/local/bin/wgui /etc/wireguard/wg0.conf:w"
pidfile=/run/${RC_SVCNAME}.pid
command_background=yes
```
Apply it
```
rc-service wgui start
rc-update add wgui default
```
## Build
### Build docker image
@ -208,4 +145,4 @@ MIT. See [LICENSE](https://github.com/ngoduykhanh/wireguard-ui/blob/master/LICEN
## Support
If you like the project and want to support it, you can *buy me a coffee*
<a href="https://www.buymeacoffee.com/khanhngo" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>
<a href="https://www.buymeacoffee.com/khanhngo" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/default-orange.png" alt="Buy Me A Coffee" height="41" width="174"></a>

View file

@ -686,6 +686,82 @@ func SuggestIPAllocation(db store.IStore) echo.HandlerFunc {
}
}
// Restart Wireguard Server handler to stop Wireguard server
func RestartServer(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
return func(c echo.Context) error {
settings, err := db.GetGlobalSettings()
if err != nil {
log.Error("Cannot get global settings: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get global settings"})
}
// Stop Server
err = util.StopWireGuardServer(settings)
if err != nil {
log.Error("Cannot stop server: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
false, fmt.Sprintf("Cannot stop server: %v", err),
})
}
// Start Server
err = util.StartWireGuardServer(settings)
if err != nil {
log.Error("Cannot start server: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
false, fmt.Sprintf("Cannot start server: %v", err),
})
}
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Restarted Wireguard Server successfully"})
}
}
// Stop Wireguard Server handler to stop Wireguard server
func StopServer(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
return func(c echo.Context) error {
settings, err := db.GetGlobalSettings()
if err != nil {
log.Error("Cannot get global settings: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get global settings"})
}
// Stop Server
err = util.StopWireGuardServer(settings)
if err != nil {
log.Error("Cannot stop server: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
false, fmt.Sprintf("Cannot stop server: %v", err),
})
}
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Stopped Wireguard Server successfully"})
}
}
// Start Wireguard Server handler to start Wireguard server
func StartServer(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
return func(c echo.Context) error {
settings, err := db.GetGlobalSettings()
if err != nil {
log.Error("Cannot get global settings: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{false, "Cannot get global settings"})
}
// Start Server
err = util.StartWireGuardServer(settings)
if err != nil {
log.Error("Cannot start server: ", err)
return c.JSON(http.StatusInternalServerError, jsonHTTPResponse{
false, fmt.Sprintf("Cannot start server: %v", err),
})
}
return c.JSON(http.StatusOK, jsonHTTPResponse{true, "Started Wireguard Server successfully"})
}
}
// ApplyServerConfig handler to write config file and restart Wireguard server
func ApplyServerConfig(db store.IStore, tmplBox *rice.Box) echo.HandlerFunc {
return func(c echo.Context) error {

View file

@ -17,7 +17,7 @@ import (
var (
// command-line banner information
appVersion = "development"
appVersion = "development-2"
gitCommit = "N/A"
gitRef = "N/A"
buildTime = fmt.Sprintf(time.Now().UTC().Format("01-02-2006 15:04:05"))
@ -97,6 +97,7 @@ func init() {
//fmt.Println("Session secret\t:", util.SessionSecret)
fmt.Println("Custom wg.conf\t:", util.WgConfTemplate)
fmt.Println("Base path\t:", util.BasePath + "/")
}
func main() {
@ -154,6 +155,9 @@ func main() {
app.GET(util.BasePath + "/api/machine-ips", handler.MachineIPAddresses(), handler.ValidSession)
app.GET(util.BasePath + "/api/suggest-client-ips", handler.SuggestIPAllocation(db), handler.ValidSession)
app.GET(util.BasePath + "/api/apply-wg-config", handler.ApplyServerConfig(db, tmplBox), handler.ValidSession)
app.GET(util.BasePath + "/api/start-wg", handler.StartServer(db, tmplBox), handler.ValidSession)
app.GET(util.BasePath + "/api/stop-wg", handler.StopServer(db, tmplBox), handler.ValidSession)
app.GET(util.BasePath + "/api/restart-wg", handler.RestartServer(db, tmplBox), handler.ValidSession)
app.GET(util.BasePath + "/wake_on_lan_hosts", handler.GetWakeOnLanHosts(db), handler.ValidSession)
app.POST(util.BasePath + "/wake_on_lan_host", handler.SaveWakeOnLanHost(db), handler.ValidSession)
app.DELETE(util.BasePath + "/wake_on_lan_host/:mac_address", handler.DeleteWakeOnHost(db), handler.ValidSession)

View file

@ -64,6 +64,12 @@
<button style="margin-left: 0.5em;" type="button" class="btn btn-outline-danger btn-sm" data-toggle="modal"
data-target="#modal_apply_config"><i class="nav-icon fas fa-check"></i> Apply
Config</button>
<button id="start-wg" style="margin-left: 0.5em;" type="button"
class="btn btn-outline-success btn-sm"><i class="nav-icon fa fa-play"></i> Start</button>
<button id="stop-wg" style="margin-left: 0.5em;" type="button"
class="btn btn-outline-danger btn-sm"><i class="nav-icon fa fa-stop"></i> Stop</button>
<button id="restart-wg" style="margin-left: 0.5em;" type="button"
class="btn btn-outline-success btn-sm"><i class="nav-icon fa fa-retweet"></i> Restart</button>
{{if .baseData.CurrentUser}}
<button onclick="location.href='{{.basePath}}/logout';" style="margin-left: 0.5em;" type="button"
class="btn btn-outline-danger btn-sm"><i class="nav-icon fas fa-sign-out-alt"></i> Logout</button>
@ -246,7 +252,7 @@
</button>
</div>
<div class="modal-body">
<p>Do you want to write config file and restart WireGuard server?</p>
<p>Do you want to write config file?</p>
</div>
<div class="modal-footer justify-content-between">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
@ -489,6 +495,66 @@
});
});
// restart wireguard button event
$(document).ready(function () {
$("#restart-wg").click(function () {
$.ajax({
cache: false,
method: 'GET',
url: '{{.basePath}}/api/restart-wg',
dataType: 'json',
contentType: "application/json",
success: function(data) {
toastr.success('Wireguard restart successfully');
},
error: function(jqXHR, exception) {
const responseJson = jQuery.parseJSON(jqXHR.responseText);
toastr.error(responseJson['message']);
}
});
});
});
// stop wireguard button event
$(document).ready(function () {
$("#stop-wg").click(function () {
$.ajax({
cache: false,
method: 'GET',
url: '{{.basePath}}/api/stop-wg',
dataType: 'json',
contentType: "application/json",
success: function(data) {
toastr.success('Wireguard stopped successfully');
},
error: function(jqXHR, exception) {
const responseJson = jQuery.parseJSON(jqXHR.responseText);
toastr.error(responseJson['message']);
}
});
});
});
// start wireguard button event
$(document).ready(function () {
$("#start-wg").click(function () {
$.ajax({
cache: false,
method: 'GET',
url: '{{.basePath}}/api/start-wg',
dataType: 'json',
contentType: "application/json",
success: function(data) {
toastr.success('Wireguard started successfully');
},
error: function(jqXHR, exception) {
const responseJson = jQuery.parseJSON(jqXHR.responseText);
toastr.error(responseJson['message']);
}
});
});
});
// apply_config_confirm button event
$(document).ready(function () {
$("#apply_config_confirm").click(function () {

View file

@ -7,6 +7,7 @@ import (
"io/ioutil"
"net"
"os"
"os/exec"
"strconv"
"strings"
"text/template"
@ -375,6 +376,52 @@ func ValidateIPAllocation(serverAddresses []string, ipAllocatedList []string, ip
return true, nil
}
// StopWireguard Server to stop Wireguard server with config. e.g. wg0.conf
func StopWireGuardServer(globalSettings model.GlobalSetting) error {
app := "wg-quick"
arg0 := "down"
arg1 := globalSettings.ConfigFilePath
cmd := exec.Command(app, arg0, arg1)
stdout, err := cmd.Output()
if err != nil {
fmt.Println(err.Error())
return err
}
// Print the output
fmt.Println(string(stdout))
return nil
}
// StartWireguard Server to start Wireguard server with config. e.g. wg0.conf
func StartWireGuardServer(globalSettings model.GlobalSetting) error {
app := "wg-quick"
arg0 := "up"
arg1 := globalSettings.ConfigFilePath
cmd := exec.Command(app, arg0, arg1)
stdout, err := cmd.Output()
if err != nil {
fmt.Println(err.Error())
return err
}
// Print the output
fmt.Println(string(stdout))
return nil
}
// WriteWireGuardServerConfig to write Wireguard server config. e.g. wg0.conf
func WriteWireGuardServerConfig(tmplBox *rice.Box, serverConfig model.Server, clientDataList []model.ClientData, globalSettings model.GlobalSetting) error {
var tmplWireguardConf string
@ -456,4 +503,4 @@ func LookupEnvOrStrings(key string, defaultVal []string) []string {
return strings.Split(val, ",")
}
return defaultVal
}
}