Files
wg-portal/docs/documentation/usage/backends.md
rwjack 54ca1d8aed
Some checks failed
Docker / Build and Push (push) Has been cancelled
Docker / release (push) Has been cancelled
github-pages / deploy (push) Has been cancelled
Add Pfsense backend (ALPHA) (#585)
* Add pfSense backend domain types and configuration

This adds the necessary domain types and configuration structures
for the pfSense backend support. Includes PfsenseInterfaceExtras and
PfsensePeerExtras structs, and the BackendPfsense configuration
with API URL, key, and timeout settings.

* Add low-level pfSense REST API client

Implements the HTTP client for interacting with the pfSense REST API.
Handles authentication via X-API-Key header, request/response parsing,
and error handling. Uses the pfSense REST API v2 endpoints as documented
at https://pfrest.org/.

* Implement pfSense WireGuard controller

This implements the InterfaceController interface for pfSense firewalls.
Handles WireGuard tunnel and peer management through the pfSense REST API.
Includes proper filtering of peers by interface (since API filtering doesn't
work) and parsing of the allowedips array structure with address/mask fields.

* Register pfSense controllers and update configuration

Registers the pfSense backend controllers in the controller manager
and adds example configuration to config.yml.sample. Also updates
README to mention pfSense backend support.

* Fix peer filtering and allowedips parsing for pfSense backend

The pfSense REST API doesn't support filtering peers by interface
via query parameters, so all peers are returned regardless of the
filter. This caused peers from all interfaces to be randomly assigned
to a single interface in wg-portal.

Additionally, the API returns allowedips as an array of objects with
"address" and "mask" fields instead of a comma-separated string,
which caused parsing failures.

Changes:
- Remove API filter from GetPeers() since it doesn't work
- Add client-side filtering by checking the "tun" field in peer responses
- Update convertWireGuardPeer() to parse allowedips array structure
- Add parseAddressArray() helper for parsing address objects
- Attempt to fetch interface addresses from /tunnel/{id}/address endpoint
  (endpoint may not be available in all pfSense versions)
- Add debug logging for peer filtering and address loading operations

Note: Interface addresses may still be empty if the address endpoint
is not available. Public Endpoint and Default DNS Servers are typically
configured manually in wg-portal as the pfSense API doesn't provide
this information.

* Extract endpoint, DNS, and peer names from pfSense peer data

The pfSense API provides endpoint, port, and description (descr) fields
in peer responses that can be used to populate interface defaults and
peer display names.

Changes:
- Extract endpoint and port from peers and combine them properly
- Fix peer name/description extraction to check "descr" field first
  (pfSense API uses "descr" instead of "description" or "comment")
- Add extractPfsenseDefaultsFromPeers() helper to extract common
  endpoint and DNS from peers during interface import
- Set PeerDefEndpoint and PeerDefDnsStr from peer data for pfSense
  backends during interface import
- Use most common endpoint/DNS values when multiple peers are present

* Fix interface display name to use descr field from pfSense API

The pfSense API uses "descr" field for tunnel descriptions, not
"description" or "comment". Updated convertWireGuardInterface()
to check "descr" first so that tunnel descriptions (e.g., "HQ VPN")
are displayed in the UI instead of just the tunnel name (e.g., "tun_wg0").

* Remove calls to non-working tunnel and peer detail endpoints

The pfSense REST API endpoints /api/v2/vpn/wireguard/tunnel/{id}
and /api/v2/vpn/wireguard/tunnel/{id}/address don't work and were
causing log spam. Removed these calls and use only the data from
the tunnel/peer list responses.

Also removed the peer detail endpoint call that was added for
statistics collection, as it likely doesn't work either.

* Fix unused variable compilation error

Removed unused deviceId variable that was causing build failure.

* Optimize tunnel address fetching to use /tunnel?id endpoint

Instead of using the separate /tunnel/address endpoint, now query
the specific tunnel endpoint /tunnel?id={id} which includes the
addresses array in the response. This avoids unnecessary API calls
and simplifies the code.

- GetInterface() now queries /tunnel?id={id} after getting tunnel ID
- loadInterfaceData() queries /tunnel?id={id} as fallback if addresses missing
- extractAddresses() properly parses addresses array from tunnel response
- Removed /tunnel/address endpoint calls

Signed-off-by: rwjack <jack@foss.family>

* Fix URL encoding issue in tunnel endpoint queries

Use Filters in PfsenseRequestOptions instead of passing query strings
directly in the path. This prevents the ? character from being encoded
as %3F, which was causing 404 errors.

- GetInterface() now uses Filters map for id parameter
- loadInterfaceData() now uses Filters map for id parameter

Signed-off-by: rwjack <jack@foss.family>

* update backend docs for pfsense

---------

Signed-off-by: rwjack <jack@foss.family>
2025-12-09 22:33:12 +01:00

92 lines
4.7 KiB
Markdown

# Backends
WireGuard Portal can manage WireGuard interfaces and peers on different backends.
Each backend represents a system where interfaces actually live.
You can register multiple backends and choose which one to use per interface.
A global default backend determines where newly created interfaces go (unless you explicitly choose another in the UI).
**Supported backends:**
- **Local** (default): Manages interfaces on the host running WireGuard Portal (Linux WireGuard via wgctrl). Use this when the portal should directly configure wg devices on the same server.
- **MikroTik** RouterOS (_beta_): Manages interfaces and peers on MikroTik devices via the RouterOS REST API. Use this to control WG interfaces on RouterOS v7+.
- **pfSense** (_alpha_): Manages interfaces and peers on pfSense firewalls via the pfSense REST API.
How backend selection works:
- The default backend is configured at `backend.default` (_local_ or the id of a defined MikroTik backend).
New interfaces created in the UI will use this backend by default.
- Each interface stores its backend. You can select a different backend when creating a new interface.
## Configuring MikroTik backends (RouterOS v7+)
> :warning: The MikroTik backend is currently marked beta. While basic functionality is implemented, some advanced features are not yet implemented or contain bugs. Please test carefully before using in production.
The MikroTik backend uses the [REST API](https://help.mikrotik.com/docs/spaces/ROS/pages/47579162/REST+API) under a base URL ending with /rest.
You can register one or more MikroTik devices as backends for a single WireGuard Portal instance.
### Prerequisites on MikroTik:
- RouterOS v7 with WireGuard support.
- REST API enabled and reachable over HTTP(S). A typical base URL is https://<router-address>:8729/rest or https://<router-address>/rest depending on your service setup.
- A dedicated RouterOS user with the following group permissions:
- **api** (for logging in via REST API)
- **rest-api** (for logging in via REST API)
- **read** (to read interface and peer data)
- **write** (to create/update interfaces and peers)
- **test** (to perform ping checks)
- **sensitive** (to read private keys)
- TLS certificate on the device is recommended. If you use a self-signed certificate during testing, set `api_verify_tls`: _false_ in wg-portal (not recommended for production).
Example WireGuard Portal configuration (config/config.yaml):
```yaml
backend:
# default backend decides where new interfaces are created
default: mikrotik-prod
mikrotik:
- id: mikrotik-prod # unique id, not "local"
display_name: RouterOS RB5009 # optional nice name
api_url: https://10.10.10.10/rest
api_user: wgportal
api_password: a-super-secret-password
api_verify_tls: true # set to false only if using self-signed during testing
api_timeout: 30s # maximum request duration
concurrency: 5 # limit parallel REST calls to device
debug: false # verbose logging for this backend
```
### Known limitations:
- The MikroTik backend is still in beta. Some features may not work as expected.
- Not all WireGuard Portal features are supported yet (e.g., no support for interface hooks)
## Configuring pfSense backends
> :warning: The pfSense backend is currently **alpha**. Only basic interface and peer CRUD are supported. Traffic statistics (rx/tx, last handshake) are not exposed by the pfSense REST API and will show as empty.
The pfSense backend talks to the pfSense REST API (pfSense Plus / CE with the REST API package installed). Point the backend at the appliance hostname without appending `/api/v2` — the portal appends `/api/v2` automatically.
### Prerequisites on pfSense:
- pfSense with the REST API package enabled (`System -> API`) and WireGuard configured.
- An API key with permissions for WireGuard endpoints. If you use a read-only key, set `core.restore_state: false` in `config.yml` to avoid write attempts at startup.
- HTTPS recommended; set `api_verify_tls: false` only for lab/self-signed setups.
Example WireGuard Portal configuration:
```yaml
backend:
# default backend decides where new interfaces are created
default: pfsense1
pfsense:
- id: pfsense1 # unique id, not "local"
display_name: Main pfSense # optional nice name
api_url: https://pfsense.example.com # no trailing /api/v2
api_key: your-api-key
api_verify_tls: true
api_timeout: 30s
concurrency: 5
debug: false
```
### Known limitations:
- Alpha quality: behavior and API coverage may change.
- Statistics (rx/tx bytes, last handshake) are not available from the pfSense REST API today.