Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,11 @@ RUN apk add --no-cache \
iptables \
sqlite \
iproute2 \
openresolv \
ca-certificates

# Traffic control CLI: `/sbin/tc` is provided by Alpine's iproute2 (listed above).

EXPOSE 8080

COPY --from=builder /out/netplug /usr/local/bin/netplug
Expand Down
30 changes: 26 additions & 4 deletions cmd/netplug/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"log"
"log/slog"
"net/http"
"os"
"os/signal"
Expand All @@ -20,6 +21,8 @@ import (
"netplug-go/internal/app"
"netplug-go/internal/assets"
"netplug-go/internal/db"
"netplug-go/internal/pcq"
"netplug-go/internal/view"
"netplug-go/internal/wireguard"
webstatic "netplug-go/web/static"
)
Expand Down Expand Up @@ -47,6 +50,9 @@ func main() {
if err := db.Migrate(sqlDB); err != nil {
log.Fatal(err)
}
if err := db.ApplySchemaPatches(sqlDB); err != nil {
log.Fatal(err)
}
if err := db.BootstrapAdmin(sqlDB); err != nil {
log.Fatal(err)
}
Expand All @@ -59,10 +65,16 @@ func main() {
sessionManager.Cookie.SameSite = http.SameSiteLaxMode
sessionManager.Cookie.Secure = cfg.CookieSecure

var svcLog *slog.Logger
if cfg.Debug {
svcLog = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
}

svc := &app.Services{
DB: sqlDB,
Sessions: sessionManager,
Config: cfg,
DB: sqlDB,
Sessions: sessionManager,
Config: cfg,
Logger: svcLog,
StartedAt: time.Now(),
}

Expand All @@ -80,6 +92,7 @@ func main() {
http.ServeFileFS(w, r, webstatic.FS(), webstatic.PlugIconPath())
})

view.SetPCQDisabled(cfg.PCQDisabled)
app.RegisterRoutes(r, svc)

server := &http.Server{
Expand All @@ -104,6 +117,16 @@ func main() {
log.Printf("wireguard startup: config not applied: %s", res.Text)
} else {
log.Printf("wireguard startup: interface is up")
if !cfg.PCQDisabled {
if _, err := pcq.Apply(sqlDB, cfg.WGInterface, false, pcq.ApplyOpts{
Debug: cfg.Debug,
Logger: svc.Logger,
}); err != nil {
if svc.Logger == nil {
log.Printf("pcq startup: %v", err)
}
}
}
}
}

Expand All @@ -121,4 +144,3 @@ func main() {
fmt.Fprintf(os.Stderr, "shutdown error: %v\n", err)
}
}

4 changes: 3 additions & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ services:
args:
GO_VERSION: ${GO_VERSION:-1.24}
GIT_COMMIT: ${GIT_COMMIT:-}
image: ${IMAGE_NAME:-netplug-wireguard}:${IMAGE_TAG:-latest}
#image: ${IMAGE_NAME:-netplug-wireguard}:${IMAGE_TAG:-latest}
container_name: ${NETPLUG_CONTAINER_NAME:-netplug-wireguard}
restart: ${NETPLUG_RESTART_POLICY:-unless-stopped}
init: true
Expand All @@ -41,6 +41,8 @@ services:
HTTP_ADDR: ${HTTP_ADDR:-:8080}
WG_INTERFACE: ${WG_INTERFACE:-wg0}
WIREGUARD_SYNC_INTERVAL_SEC: ${WIREGUARD_SYNC_INTERVAL_SEC:-30}
NETPLUG_PCQ_DISABLE: ${NETPLUG_PCQ_DISABLE:-}
NETPLUG_DEBUG: ${NETPLUG_DEBUG:-}
COOKIE_SECURE: ${COOKIE_SECURE:-false}
BOOTSTRAP_ADMIN_USERNAME: ${BOOTSTRAP_ADMIN_USERNAME:-}
BOOTSTRAP_ADMIN_PASSWORD: ${BOOTSTRAP_ADMIN_PASSWORD:-}
Expand Down
27 changes: 26 additions & 1 deletion internal/app/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
)

type Config struct {
Expand All @@ -13,7 +14,9 @@ type Config struct {
DBPath string
CookieSecure bool
WGInterface string
WGInterval int // seconds
WGInterval int // seconds
PCQDisabled bool // NETPLUG_PCQ_DISABLE removes tc shaping managed by NetPlug
Debug bool // NETPLUG_DEBUG enables JSON structured debug logs (e.g. PCQ tc apply)

ProjectRoot string
}
Expand All @@ -38,6 +41,9 @@ func LoadConfig() (Config, error) {
}

wgIface := env("WG_INTERFACE", "wg0")
pcqDisable := envBoolFlexible("NETPLUG_PCQ_DISABLE", false)
debug := envBoolFlexible("NETPLUG_DEBUG", false)

wgInterval := 30
if v := os.Getenv("WIREGUARD_SYNC_INTERVAL_SEC"); v != "" {
n, err := strconv.Atoi(v)
Expand All @@ -54,6 +60,8 @@ func LoadConfig() (Config, error) {
CookieSecure: cookieSecure,
WGInterface: wgIface,
WGInterval: wgInterval,
PCQDisabled: pcqDisable,
Debug: debug,
ProjectRoot: root,
}, nil
}
Expand All @@ -71,3 +79,20 @@ func env(key, fallback string) string {
return fallback
}

func envBoolFlexible(key string, fallback bool) bool {
v := strings.TrimSpace(strings.ToLower(os.Getenv(key)))
switch v {
case "":
return fallback
case "1", "true", "yes", "on":
return true
case "0", "false", "no", "off":
return false
default:
b, err := strconv.ParseBool(v)
if err != nil {
return fallback
}
return b
}
}
Loading
Loading