mirror of
https://github.com/ngoduykhanh/wireguard-ui
synced 2024-05-19 14:06:37 +02:00
Added wireguard service in container
This commit is contained in:
parent
f43c59c043
commit
a13b78b1f5
27
Dockerfile
27
Dockerfile
|
@ -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
|
||||
|
||||
|
|
75
README.md
75
README.md
|
@ -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>
|
|
@ -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 {
|
||||
|
|
6
main.go
6
main.go
|
@ -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)
|
||||
|
|
|
@ -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 () {
|
||||
|
|
49
util/util.go
49
util/util.go
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue