# wireguard-macos **Repository Path**: SRIM/wireguard-macos ## Basic Information - **Project Name**: wireguard-macos - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-27 - **Last Updated**: 2026-05-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README
The easiest way to run a WireGuard VPN server on macOS
One command to set up a full WireGuard server on any Mac — with auto-start, NAT, QR codes, and live monitoring.
--- ## Why wireguard-macos? Running a WireGuard server on macOS is full of platform-specific traps. Existing scripts and guides fail because they don't handle all of them together: | Problem | What goes wrong | How we fix it | | --- | --- | --- | | **Apple Silicon paths** | Homebrew installs to `/opt/homebrew`, not `/usr/local`. Most scripts hardcode Intel paths. | Auto-detect architecture at install time | | **bash 3.2** | macOS ships bash 3.2 (2007). `wg-quick` needs bash 4+. `sudo wg-quick` fails silently. | Force Homebrew bash via wrapper | | **`utun` interfaces** | macOS maps WireGuard to `utun0`, `utun3`, etc. — not `wg0`. Status checks break. | Detect active `utun` dynamically | | **`/etc/pf.conf` fragility** | Direct edits get overwritten on macOS updates. | Use `pfctl` anchors instead | | **Homebrew + root** | `brew install` refuses to run as root. `sudo ./install.sh` breaks immediately. | Run as user, `sudo` only where needed | **wireguard-macos solves all five.** No Docker, no VM, no hacks — just clean shell scripts that work with macOS, not against it. ## Comparison | Feature | **wireguard-macos** | wg-easy | PiVPN | Manual setup | | --- | :---: | :---: | :---: | :---: | | macOS native | **Yes** | No (Docker) | No (Linux) | Partial | | Apple Silicon | **Yes** | N/A | N/A | Manual | | One-command install | **Yes** | Yes | Yes | No | | Auto-start on boot | **Yes** | Docker restart | systemd | Manual | | NAT survives OS updates | **Yes** | N/A | N/A | No | | QR codes for mobile | **Yes** | Yes | Yes | Manual | | Post-quantum preshared keys | **Yes** | No | Optional | Manual | | Live monitoring dashboard | **Yes** | Web UI | No | No | | No Docker required | **Yes** | No | Yes | Yes | ## Quick Start ```bash git clone https://github.com/hjunhuh/wireguard-macos.git cd wireguard-macos # Install server (do NOT use sudo — it will ask when needed) ./install.sh ``` The installer will prompt for: | Prompt | Example | Default | | --- | --- | --- | | Endpoint | `203.0.113.5:51820` | _(required)_ | | Server VPN IP | `10.0.10.1` | `10.0.10.1` | | DNS server | `1.1.1.1` | `1.1.1.1` | | WAN interface | `en0` | `en0` | ### Prerequisites - macOS 13 (Ventura) or later - [Homebrew](https://brew.sh) installed - A router with UDP port forwarding capability - A static public IP or DDNS hostname ## Usage ### Add a client ```bash ./client.sh iphone ./client.sh macbook ``` A QR code is printed to the terminal. Scan it with the [WireGuard app](https://www.wireguard.com/install/) on iOS/Android, or import the generated `.conf` file on desktop clients. ### Start / Stop > **Important:** Always use the Homebrew bash path. Running `sudo wg-quick` directly uses macOS system bash 3.2, which will fail. ```bash # Start sudo /opt/homebrew/bin/bash /opt/homebrew/bin/wg-quick up /opt/homebrew/etc/wireguard/wg0.conf # Stop sudo /opt/homebrew/bin/bash /opt/homebrew/bin/wg-quick down /opt/homebrew/etc/wireguard/wg0.conf ``` The server starts automatically on boot via `launchd`, so manual start is only needed the first time. ### Check status ```bash sudo ./status.sh ``` ``` ============================================================ WireGuard Server Status ============================================================ Status: RUNNING (interface: utun10) interface: utun10 public key: ... private key: (hidden) listening port: 51820 peer: ... preshared key: (hidden) allowed ips: 10.0.10.2/32 IP forwarding: ENABLED NAT rule: ACTIVE (nat on en0 inet from 10.0.10.0/24 to any -> (en0)) Registered clients: - iphone (10.0.10.2) - macbook (10.0.10.3) ============================================================ ``` ### Real-time monitor ```bash sudo ./monitor.sh ``` A live dashboard that refreshes every 2 seconds: ``` ============================================================ WireGuard Monitor [2026-03-03 14:32:05] ============================================================ Interface: utun10 Port: 51820 Public Key: aBcDeFgHiJkLmNoPqRsT... Uptime: 3d 14h 22m Peers: 2/3 online ------------------------------------------------------------ CLIENT STATUS ENDPOINT LAST HANDSHAKE ------------------------------------------------------------ iphone ONLINE 203.0.113.50:4921 12s ago RX: 145.2 MB (52.3 KB/s) TX: 1.2 GB (128.7 KB/s) macbook ONLINE 198.51.100.8:51820 45s ago RX: 2.3 GB (1.2 MB/s) TX: 523.4 MB (256.0 KB/s) ipad OFFLINE -- 3h 12m ago RX: 89.1 MB (0 B/s) TX: 12.3 MB (0 B/s) ------------------------------------------------------------ TOTALS RX: 2.5 GB (1.3 MB/s) TX: 1.7 GB (384.7 KB/s) PEERS 3 registered, 2 online, 1 offline ============================================================ Refresh: 2s | Ctrl+C to exit ============================================================ ``` ### Uninstall ```bash sudo ./remove.sh ``` Stops WireGuard, removes the `launchd` service, disables IP forwarding, and optionally deletes all keys and configuration files. ## File Structure After installation: ``` /opt/homebrew/etc/wireguard/ ├── wg0.conf # Server config (includes peers) ├── wg0.conf.def # Backup of server config (no peers) ├── postup.sh # NAT enable script (pfctl anchor) ├── postdown.sh # NAT disable + anchor flush ├── wg-quick-sudo.sh # Homebrew bash wrapper ├── server_public.key ├── server_private.key ├── endpoint.var ├── dns.var ├── vpn_subnet.var ├── wan_interface_name.var ├── last_used_ip.var └── clients/ ├── iphone/ │ ├── iphone.conf # Client config (share this) │ ├── privatekey │ ├── publickey │ ├── presharedkey │ └── ip └── macbook/ └── ... /Library/LaunchDaemons/ └── com.wireguard.wg0.plist # Auto-start on boot ``` ## How It Works ### NAT (Network Address Translation) Instead of editing `/etc/pf.conf` (which gets overwritten on macOS updates), this project uses `pfctl` anchors: - **PostUp** adds NAT + pass rules to the `com.apple/wireguard` anchor and saves the pf token - **PostDown** flushes the anchor rules, releases the pf token, and removes the subnet route This approach was [proposed by lifepillar](https://github.com/barrowclift/barrowclift.github.io/issues/1) as an improvement to the original [Barrowclift guide](https://barrowclift.me/articles/wireguard-server-on-macos). ### Auto-start A `launchd` plist is registered at `/Library/LaunchDaemons/com.wireguard.wg0.plist` with `RunAtLoad: true`. It calls `wg-quick up` via Homebrew bash with the correct `PATH` environment variable set, avoiding the bash 3 and path issues entirely. ## Router Configuration After installation, configure port forwarding on your router: | Field | Value | | --- | --- | | External port | The port from your endpoint (default: `51820`) | | Internal IP | Your Mac's LAN IP | | Internal port | Same as external | | Protocol | **UDP** | ## Troubleshooting