Set Up WireGuard on Fedora: Done in 10 Minutes
I’ve been using Fedora as my main development machine for 2 years. What I love most is the fast package update cycle — WireGuard has been integrated directly into the kernel since version 5.6, so on Fedora you don’t need to install any external modules. Just wireguard-tools and you’re good to go.
Setting up WireGuard on Fedora differs from Ubuntu in that you need to handle both firewalld and SELinux — two things most guides skip over. This article goes straight to those parts.
Environment
- Fedora Server 40/41 (VPS or physical server)
- Public IP: e.g.,
203.0.113.10 - WireGuard subnet:
10.8.0.0/24 - WireGuard port:
51820/udp
Quick Start — Up and Running in 10 Minutes
Step 1: Install WireGuard Tools
sudo dnf install wireguard-tools -y
Step 2: Generate Server Key Pair
cd /etc/wireguard
sudo umask 077
sudo wg genkey | sudo tee server_private.key | sudo wg pubkey | sudo tee server_public.key
Save both of these values. Keep the private key absolutely secret; use the public key when configuring peers.
Step 3: Create the Server Config File
sudo nano /etc/wireguard/wg0.conf
File contents:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <server_private_key_contents>
# Enable IP forwarding when interface comes up
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = firewall-cmd --zone=public --add-interface=wg0
PostUp = firewall-cmd --zone=public --add-masquerade
PostDown = firewall-cmd --zone=public --remove-interface=wg0
PostDown = firewall-cmd --zone=public --remove-masquerade
# --- Peer 1 (client laptop) ---
[Peer]
PublicKey = <client_public_key>
AllowedIPs = 10.8.0.2/32
Step 4: Open firewalld Port for WireGuard
# Permanently open UDP port 51820
sudo firewall-cmd --permanent --add-port=51820/udp
sudo firewall-cmd --reload
Step 5: Enable IP Forwarding Permanently
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-wireguard.conf
sudo sysctl -p /etc/sysctl.d/99-wireguard.conf
Step 6: Start WireGuard and Enable Autostart
sudo systemctl enable --now wg-quick@wg0
Quick check:
sudo wg show
If you see the wg0 interface with listening port: 51820, the server setup is complete.
Deep Dive — Why Do It This Way?
firewalld and WireGuard: Why Do You Need Masquerade?
Fedora uses firewalld with the concept of zones, which is fundamentally different from traditional iptables. When a client connects to WireGuard and wants to reach the internet through the server, traffic needs to be NAT’d (masqueraded) — the server pretends to be the packet source on behalf of the client.
The PostUp/PostDown commands in wg0.conf run automatically when the interface comes up or goes down. No manual intervention needed after every reboot.
Just using WireGuard to SSH into the server without routing all traffic? Drop the masquerade section — your config will be much cleaner.
SELinux and wg-quick: What Most Guides Miss
This is where I once spent 30 minutes debugging on my first setup. On Fedora with SELinux in Enforcing mode, the sysctl command run from PostUp can sometimes be blocked by SELinux due to a context mismatch.
Check for AVC denials:
sudo ausearch -m avc -ts recent | grep wireguard
The cleanest fix: enable IP forwarding permanently via sysctl.d (done in Step 5). Then remove the PostUp = sysctl... line from wg0.conf:
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = <server_private.key>
PostUp = firewall-cmd --zone=public --add-interface=wg0
PostUp = firewall-cmd --zone=public --add-masquerade
PostDown = firewall-cmd --zone=public --remove-interface=wg0
PostDown = firewall-cmd --zone=public --remove-masquerade
Cleaner, and no longer dependent on the script’s SELinux context.
Client Configuration (Laptop/PC)
Generate Client Keys
# On the client machine (Linux/Mac)
wg genkey | tee client_private.key | wg pubkey | tee client_public.key
Copy client_public.key to the server and add it to wg0.conf under the [Peer] section (already set up in Step 3 above).
Client Config File
[Interface]
Address = 10.8.0.2/32
PrivateKey = <client_private.key>
DNS = 1.1.1.1
[Peer]
PublicKey = <server_public.key>
Endpoint = 203.0.113.10:51820
# Route all traffic through VPN
AllowedIPs = 0.0.0.0/0
# Only route internal traffic (internet traffic bypasses VPN)
# AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
On a Linux client, connect with:
sudo wg-quick up ./client.conf
Windows/Mac/iOS/Android — use the official WireGuard app, import the config file or scan a QR code and you’re done.
Advanced — Adding More Peers and Easier Management
Add New Peers Without Restarting the Service
WireGuard has a neat trick that OpenVPN can’t do: add peers on the fly without restarting the service or interrupting existing connections.
# Add new peer directly to the running interface
sudo wg set wg0 peer <new_client_public_key> allowed-ips 10.8.0.3/32
# Also save to config file to persist after reboot
sudo wg-quick save wg0
Script to Auto-Generate Config for New Clients
#!/bin/bash
# gen-client.sh — quickly generate a WireGuard client config
CLIENT_NAME="$1"
CLIENT_IP="$2" # e.g., 10.8.0.3
SERVER_PUBKEY=$(cat /etc/wireguard/server_public.key)
SERVER_ENDPOINT="203.0.113.10:51820"
CLIENT_PRIVKEY=$(wg genkey)
CLIENT_PUBKEY=$(echo "$CLIENT_PRIVKEY" | wg pubkey)
# Add to server config
echo -e "\n[Peer]\nPublicKey = $CLIENT_PUBKEY\nAllowedIPs = $CLIENT_IP/32" \
| sudo tee -a /etc/wireguard/wg0.conf
# Generate client config file
cat > "${CLIENT_NAME}.conf" <<EOF
[Interface]
Address = $CLIENT_IP/32
PrivateKey = $CLIENT_PRIVKEY
DNS = 1.1.1.1
[Peer]
PublicKey = $SERVER_PUBKEY
Endpoint = $SERVER_ENDPOINT
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF
echo "Config created: ${CLIENT_NAME}.conf"
echo "Client public key: $CLIENT_PUBKEY"
sudo bash gen-client.sh macbook 10.8.0.3
Tips from Real-World WireGuard Experience
1. Quick Connection Debugging
# Watch real-time traffic on interface wg0
sudo tcpdump -i wg0
# Monitor packet count per peer
watch -n 1 sudo wg show
# Test connection from client
ping 10.8.0.1 # ping server via VPN
2. Don’t Route 0.0.0.0/0 Unless You Actually Need To
Many people copy sample configs with AllowedIPs = 0.0.0.0/0 (full tunnel) when they only need to access an internal server. Split tunneling (AllowedIPs = 10.8.0.0/24) is noticeably faster — I tested this on a cafe network and latency dropped from ~80ms to ~25ms after switching to split tunnel. The client’s internet traffic goes directly without routing through the VPN server.
3. PersistentKeepalive — When Do You Need It?
Set PersistentKeepalive = 25 on the client side when the client is behind NAT — which covers most cases when using a laptop at home or a cafe. The server doesn’t need this. 25 seconds works fine with most routers, but if the connection keeps dropping, try lowering it to 15.
4. Back Up Your Private Key Right Now
# Back up the key somewhere else (off the server)
sudo cat /etc/wireguard/server_private.key
Losing the private key means reconfiguring everything from scratch for all peers. I went through this when a VPS snapshot failed — it took 2 hours to update configs across all devices. Not fun.
5. firewalld Zones — Watch Out with Multiple Interfaces
On servers with multiple NICs, be careful with firewalld zones. Check which zone each interface belongs to before adding masquerade:
sudo firewall-cmd --get-active-zones
The server’s public interface (eth0 or ens3) must be in the public zone for masquerade to work correctly.

