Hi all,
Sharing a package I built for the case where WireGuard is not blocked by port, but by shape: the handshake has a fixed layout that DPI can fingerprint, and where that gets filtered the tunnel simply never comes up — nothing logs an error, it just sits there connecting. AmneziaWG is a WireGuard fork that changes what the packets look like on the wire while keeping the same cryptography. There was no pfSense package for it, so I wrote one. It adds VPN → AmneziaWG.
What it does:
Tunnels and peers managed from the GUI at the level of the official WireGuard package: tunnels, peers, settings, status page and a dashboard widget.
The Obfuscation section, which is the part no other package has: the 16 parameters (Jc/Jmin/Jmax, S1–S4, H1–H4, I1–I5), each one drawn per tunnel instead of shipped as a constant. A value that arrives the same in every installation is a signature of its own — it trades the fingerprint you are hiding for a brand new one.
A compatibility selector per tunnel (AmneziaWG 1.x or 2.0) that states what the weakest end understands, and leaves anything above it out of both configuration files even when a value is stored. One parameter different on one side means the handshake never completes and nothing reports why, so that is the part I most wanted to make hard to get wrong.
One form creates the peer and hands you the client file: a .zip download, a QR to scan from the app, or delivery by email through the SMTP the firewall already has under System → Advanced → Notifications. It auto-fills what it can — next free address on the tunnel, your Dynamic DNS hostnames as endpoint options, the listen port, the MTU, DNS presets.
Or untick the client box and register a peer from a public key you were given, which is what a site to site link needs.
Important — how it works under the hood:
Each tunnel is an amneziawg-go process in userspace, supervised by the package's service. There is no kernel module: AmneziaWG has one (if_amn.ko), but it will not load on pfSense — it is pinned to an exact __FreeBSD_version and pfSense runs Netgate's own kernels. Interfaces are named tun9000–tun9999 on purpose, because a plain tunN name is what makes pfSense list them under Interfaces → Assignments, so a tunnel can be assigned and get firewall rules and a gateway like any other interface.
It depends on no other package and it does not touch the official WireGuard package — separate paths, separate control sockets, separate service. Both run side by side on the same firewall; that is how mine is set up.
Three trade-offs I want to be upfront about:
Userspace costs CPU. Measured on an Intel i5-3570 (4 cores, Ivy Bridge): ~830 Mbps of payload with both encryption and decryption on the same box. The obfuscation itself is free — 835 vs 828 Mbps with it turned off — but kernel WireGuard moves about 2.5x more per core. Plenty for a home or small office link; if you need line rate, kernel WireGuard is still the right tool. This exists for when WireGuard is the thing being blocked.
The bundled amneziawg-go is not the stock binary. It is built from source with a FreeBSD sticky sockets patch and reports -sticky1. Without it, a firewall with more than one WAN cannot complete a handshake on any WAN that does not hold the default gateway: the reply leaves through the default gateway's interface carrying the wrong source address, and the client discards it. The patch is upstream at amnezia-vpn/amneziawg-go#180. A plain pkg install of amneziawg-go would silently undo it.
Generating a client file stores that client's private key in config.xml, so the file can be handed out again later — re-download it, show the QR again, resend the mail. That means it also lands in your backups and in AutoConfigBackup. It is a checkbox: untick it and the peer is registered from a public key with nothing stored, which is the safer practice.
Requires:
Nothing else installed. Tested only on pfSense CE 2.9.0-BETA (FreeBSD 16), amd64 — that version, on a single firewall, and nothing else. 2.8.1 (FreeBSD 15) is deliberately out of scope: the .pkg declares the FreeBSD:16:amd64 ABI, so pkg add refuses to install it there rather than putting something unverified on a firewall.
Install:
Download the .pkg from the release: https://github.com/MarceloMayo74/pfsense-amneziawg/releases/tag/v1.0.0
With SSH:
scp pfSense-pkg-AmneziaWG-1.0.0-FreeBSD-16-amd64.pkg root@FIREWALL:/root/
ssh root@FIREWALL
pkg add /root/pfSense-pkg-AmneziaWG-1.0.0-FreeBSD-16-amd64.pkg
Or without leaving the browser: Diagnostics → Command Prompt, "Upload File", pick the .pkg — it lands in /tmp — then under "Execute Shell Command":
pkg add /tmp/pfSense-pkg-AmneziaWG-1.0.0-FreeBSD-16-amd64.pkg
pkg add warns that the package doesn't come from a repository — that's expected, it isn't in the official repo or any unofficial one. Then open VPN → AmneziaWG.
To remove it: pkg delete -y pfSense-pkg-AmneziaWG. Tunnels and peers stay in config.xml unless you turn off Keep Configuration in Settings first. And note that a pfSense system upgrade only reinstalls packages that come from the official repository, so run pkg add again after upgrading.
Repo with the full technical detail, and where to file anything: https://github.com/MarceloMayo74/pfsense-amneziawg
Apache 2.0. The GPLv2 awg(8) binary that ships inside has its corresponding source published beside the .pkg in the same release, as the licence requires. Feedback, issues and PRs all welcome. Thanks for reading!
[image: 1786749319811-obfuscation.png]
[image: 1786749339974-peer-client.png]
[image: 1786749351369-peers-list.png]
[image: 1786749364250-status.png]
[image: 1786749375279-widget.png]