# wg-portal manages interfaces in place, and that is the whole design

> WireGuard Portal v2 is a single Go binary that drives existing WireGuard interfaces through wgctrl rather than writing configuration files and reloading them. That is why it needs NET_ADMIN and host networking in Docker, and why the out of scope list rules out importing private keys from a setup it did not create.

**h44z/wg-portal** — WireGuard Configuration Portal with LDAP connection

- Repository: https://github.com/h44z/wg-portal
- Website: https://wgportal.org/
- Stars: 1,849 · Forks: 201
- Language: Go
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/h44z-wg-portal

## It talks to a running interface, not to a config file

The portal is described as a web based configuration portal for WireGuard server management, and the sentence that explains its behaviour is about the library it uses. It uses the WireGuard wgctrl library to manage existing VPN interfaces, which the README says allows activation or deactivation of new users without disturbing existing VPN connections.

That is the design decision everything else follows from. Because the tool operates on a live interface, enabling a peer is a change to the running interface rather than a rewrite of wg0.conf followed by a reload. Existing tunnels stay up while a new one is added, which is the operational property that matters when you are onboarding users rather than rebuilding a server.

The application stack names the two libraries behind that: wgctrl-go and netlink for interface handling, Bootstrap for the HTML templates, and Vue.js for the frontend. The web UI is described as responsive, multi-language and dark mode.

Self-hosting is the deployment story in one sentence: the whole application is a single binary. Combined with the multi-stage Dockerfile, which builds the frontend with node:lts-alpine and the backend with golang:1.27-alpine and copies the compiled frontend into the backend tree before compiling, the artifact is one static Go binary with CGO_ENABLED=0, built with netgo and static external ldflags. There is no runtime to install.

The README also states that the portal can be used with existing WireGuard setups and supports multiple WireGuard interfaces, plus multiple backends: wgctrl, MikroTik or pfSense.

## What the README puts outside the boundary

The out of scope list is short and specific, and each exclusion predicts a support question later.

Automatic generation or application of any iptables or nftables rules is not in scope. The portal adds and removes peers; it does not open the ports that make the tunnel reachable. That remains a manual step in whatever tool you already use, and it is the most common gap for a new operator to discover.

Support for operating systems other than Linux is out of scope, which follows from the netlink based interface handling.

Automatic import of private keys of an existing WireGuard setup is also out of scope. This is the one that shapes adoption. If your server's private key was generated by hand and lives in a config file, the portal does not take ownership of it. That is arguably correct, since a portal with a database of peers still needs the server identity to stay where it is, but it does mean the setup is a hybrid rather than a clean handover.

For context on scale, the feature list covers automatic IP selection from the network pool assigned to the client, QR code generation for mobile clients, email of the QR code and client configuration to the client, wg-quick style configuration file generation as wgX.conf when required, peer expiry, IPv6 readiness, a REST API for management and deployment, webhooks for custom actions on peer, interface or user updates, and Prometheus metrics for monitoring and alerting. Route and DNS settings are handled the way wg-quick handles them rather than being invented separately, which matters because clients parse AllowedIPs literally.

## Container deployment needs host networking and NET_ADMIN

The docker-compose.yml in the repository is the reference deployment, and every unusual setting in it is load bearing.

```yaml
services:
  wg-portal:
    image: wgportal/wg-portal:v2
    container_name: wg-portal
    restart: unless-stopped
    logging:
      options:
        max-size: "10m"
        max-file: "3"
    cap_add:
      - NET_ADMIN
    network_mode: "host"
    volumes:
      - /etc/wireguard:/etc/wireguard
      - ./data:/app/data
      - ./config:/app/config
```

NET_ADMIN is required because the portal configures interfaces through netlink. Host network mode is what allows a container to reach existing WireGuard interfaces, and the compose file carries a comment saying to ensure that access to the UI is properly secured, which is worth taking literally: with host networking the web interface is exposed on the host's addresses rather than behind a bridge.

Three volumes are mounted. /etc/wireguard is the host's WireGuard directory, which is how the portal reads and generates wgX.conf../data is the application data directory, which is where the database lives when using the embedded SQLite option../config maps to /app/config, and the repository ships config.yml.sample as the reference for what goes there.

There is also a commented out migration line in the compose file, a command of ["-migrateFrom=/app/data/wg_portal.db"], which indicates the portal can migrate an existing SQLite file. Whether you need it depends on whether you are upgrading from an earlier layout.

The image reference has moved. The README carries an IMPORTANT note saying that since the project was accepted by the Docker-Sponsored Open Source Program, the Docker image location has moved to wgportal/wg-portal, and asks users to update from h44z/wg-portal. The Makefile in the repository still defines IMAGE=h44z/wg-portal, which is a small inconsistency worth knowing about if you build locally.

## Databases, authentication backends and the API surface

User sources are pluggable across three families. A database is supported, with SQLite, MySQL, MsSQL and Postgres named. OAuth is supported. LDAP is supported, covering both Active Directory and OpenLDAP.

The go.mod explains how much is really here. The database layer is GORM with drivers for MySQL, Postgres and SQL Server, plus glebarez/sqlite as a pure Go SQLite implementation, so no cgo and no separate SQLite library in the image. Authentication pulls in go-ldap/ldap/v3, coreos/go-oidc/v3 for OpenID Connect, golang.org/x/oauth2, and go-webauthn/webauthn for passkeys, which the feature list calls Passkey support. Session handling uses alexedwards/scs/v2.

The API is generated rather than hand-written. The Makefile has a codegen target that runs swag init with a pascalcase property strategy, parseInternal and a general info file at server/api.go, outputting into server/docs/, then runs go fmt on the result. That target regenerates the autogenerated API docs, which tells you the REST API is documented with Swagger tooling rather than maintained as prose.

Everything else in the dependency list maps to a feature. gorilla/websocket and vardius/message-bus suggest live updates in the UI and an internal event mechanism, which is consistent with a webhook feature. yeqown/go-qrcode and its compressed writer are the QR code path, xhit/go-simple-mail is the email path, go-playground/validator is request validation, prometheus-community/pro-bing with client_golang is the metrics surface, go-pkgz/routegroup handles route grouping, pgregory.net/rapid is a property based testing library, and a8m/envsubst plus gopkg.in/yaml.v3 mean the sample config supports environment substitution.

The module declares go 1.27, matching the golang:1.27-alpine builder image in the Dockerfile.

## Operations, maintenance and the thing to check first

The monitoring story is specific: Prometheus metrics are exposed for monitoring and alerting. The Dockerfile exposes 8787/tcp for metrics, 8888 for the web interface and the WireGuard port, and sets TZ=UTC. If you plan to alert on tunnel health rather than host health, confirming the scrape path to 8787 is the first thing to verify after deployment, because a self-hosted portal that nobody can see failing is the failure mode nobody notices.

The container image is deliberately small in shape. A scratch stage carries only the compiled binary for export, and the final image is alpine:3.24 with bash, curl, iptables, nftables, openresolv, wireguard-tools and tzdata installed. The presence of iptables, nftables, openresolv and wireguard-tools in the image while the README says rule generation is out of scope is worth noting: the tools are present for the wg-quick style handling of route and DNS settings that the feature list claims, and for your own use inside the container.

Maintenance runs through the Makefile, which separates user targets from internal ones with the help target reading both comment styles. Codegen regenerates API docs, update runs go get -u and go mod tidy, format runs go fmt, and test is composed of test-vet and test-race. There is a test-in-docker target that runs make test inside golang:$(GOVERSION) with the working directory mounted, explicitly for non-Linux environments such as MacOS, which is a reasonable concession given the Linux-only support position.

For an alternative, the practical comparison is with running WireGuard with a static config and scripting it. Scripting has fewer moving parts and no database to back up; the portal earns its place when the number of peers changes often enough that editing config files by hand becomes the bottleneck. The dependency list shows the cost side clearly, which is a full identity stack, four database drivers, metrics, mail and a code generation step.

Releases move steadily: v2.3.1 on 2026-06-12, v2.3.0 on 2026-06-05, v2.2.3 on 2026-04-03. The last push was on 2026-10-13 and the repository is not archived, so maintenance is current. The licence is MIT.

## Conclusion

Adopt wg-portal if you already run WireGuard on Linux and want to hand out and revoke peer configurations from a web UI without touching configuration files, especially where user accounts already live in Active Directory or OpenLDAP. Do not adopt it expecting firewall management, non-Linux support, or takeover of private keys from a hand built setup, since the README places all three out of scope. Before deploying, pull the image as wgportal/wg-portal rather than the older h44z/wg-portal name, keep the host network mode and NET_ADMIN capability the compose file specifies, and confirm the Prometheus metrics on port 8787 reach your scraper before you rely on them for alerting.

## FAQ

### Which Docker image should I use for WireGuard Portal?

Use wgportal/wg-portal. The README carries an IMPORTANT note that the image location moved to wgportal/wg-portal after the project was accepted by the Docker-Sponsored Open Source Program, and asks users to update from the older h44z/wg-portal name.

### Does wg-portal manage firewall rules for me?

No. Automatic generation or application of any iptables or nftables rules is listed under what is out of scope, alongside support for operating systems other than Linux and automatic import of private keys from an existing setup.

### Which authentication sources can wg-portal use?

A database, which can be SQLite, MySQL, MsSQL or Postgres, or OAuth, or LDAP with Active Directory or OpenLDAP. Passkey support is also listed among the features, backed by the go-webauthn library in go.mod.

### Why does the wg-portal Docker Compose file need NET_ADMIN and host networking?

The portal configures WireGuard interfaces in place through wgctrl and netlink, which needs the NET_ADMIN capability, and host network mode is what lets the container reach those existing interfaces. The compose file comments that access to the UI must be properly secured when using host networking.

## Sources

- [h44z/wg-portal on GitHub](https://github.com/h44z/wg-portal)
- [License: MIT](https://github.com/h44z/wg-portal/blob/master/LICENSE)
- [Project website](https://wgportal.org/)
- [README](https://github.com/h44z/wg-portal/blob/master/README.md)
- [Releases](https://github.com/h44z/wg-portal/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/h44z-wg-portal
