How to Set Up WireGuard VPN Server on Fedora

Install WireGuard on Fedora, generate keys, configure the interface, and enable IP forwarding to start the VPN server.

You need a secure tunnel to your home network

You are sitting in a coffee shop with untrusted Wi-Fi. Your laptop connects to your home Fedora server through a WireGuard tunnel. All traffic is encrypted. You also want to access your home NAS from the office. WireGuard is the tool. It lives in the kernel. It is fast. Fedora includes it in the main repos. You need to set up the server interface, generate keys, and tell the firewall to let traffic through.

WireGuard creates a virtual network interface, usually wg0. It sits between your client and the server. The server assigns an IP from a private range, like 10.0.0.0/24. When a client sends a packet, the server receives it, decrypts it, and routes it. If the client wants the internet, the server performs Network Address Translation. The server replaces the client's private IP with its own public IP before forwarding the packet to the upstream router. This is masquerading. Without NAT, the client can only talk to the server. With NAT, the client can reach the whole internet.

Fedora uses firewalld by default. Do not use raw iptables commands in your scripts. They conflict with firewalld and get wiped on reload. Use firewall-cmd or configure firewalld zones. Also, wg-quick is the helper script that reads the config and brings up the interface. It handles PostUp and PostDown hooks. Trust the helper. Manual edits drift.

Install and generate keys

Install the tools and create the cryptographic keys. The private key stays on the server. The public key goes to the clients. Fedora's entropy pool is robust. Key generation is instant.

sudo dnf install wireguard-tools
# Install the userspace utilities. The kernel module loads automatically.
sudo wg genkey | sudo tee /etc/wireguard/private.key > /dev/null
# Generate a private key and save it securely.
sudo wg pubkey < /etc/wireguard/private.key | sudo tee /etc/wireguard/public.key
# Derive the public key. Clients need this to establish the tunnel.

Restrict access to the private key immediately. If an attacker reads this file, they can impersonate your server.

sudo chmod 600 /etc/wireguard/private.key
# Only root can read or write the private key.

Run chmod before creating the configuration. A misconfigured permission can expose the key to the whole system. SELinux expects keys in /etc/wireguard/ with specific contexts. If you move keys elsewhere, restore the context.

Configure the server interface

Create the configuration file for the wg0 interface. wg-quick reads this file and brings up the tunnel. It handles interface creation, address assignment, and hook execution.

[Interface]
Address = 10.0.0.1/24
# The server's IP inside the tunnel. Clients will receive IPs from this range.
ListenPort = 51820
# UDP port for WireGuard traffic. WireGuard only uses UDP.
PrivateKey = $(cat /etc/wireguard/private.key)
# Embed the private key. wg-quick resolves this variable at startup.
PostUp = firewall-cmd --zone=public --add-masquerade
# Enable NAT. Clients will appear to the internet as the server's IP.
PostUp = firewall-cmd --zone=public --add-port=51820/udp
# Open the port for incoming connections on the public zone.
PostDown = firewall-cmd --zone=public --remove-masquerade
# Disable NAT when the tunnel stops.
PostDown = firewall-cmd --zone=public --remove-port=51820/udp
# Close the port when the tunnel stops.

Save this as /etc/wireguard/wg0.conf. The PostUp commands run as root when the interface starts. They configure firewalld dynamically. The PostDown commands clean up when the interface stops. This keeps the firewall state consistent with the tunnel state.

If your server uses a different firewall zone, replace public with your zone name. Check your current zone with firewall-cmd --get-default-zone. WireGuard supports IPv6. Add an IPv6 address to the Address line if your network uses it. The format is Address = 10.0.0.1/24, fd42:42:42::1/64.

Enable the service

Start the WireGuard service and enable it for boot. systemd manages the lifecycle via the wg-quick@wg0 unit.

sudo systemctl enable --now wg-quick@wg0
# Enable the service for boot and start it immediately.

Fedora's wg-quick helper sets net.ipv4.ip_forward=1 automatically. You do not need to run sysctl manually. The helper also manages the interface flags. Manual sysctl edits are redundant and can conflict with the helper.

Verify the setup

Check the interface status and firewall rules. The tunnel must be up, and masquerading must be active.

sudo wg show
# Display the interface state. Look for the public key and listening port.
sudo firewall-cmd --list-all
# Verify masquerade is enabled and port 51820 is open.

The wg show output should list the interface wg0 with the public key and the listening port. The firewall-cmd output should show masquerade: yes and 51820/udp in the ports list.

If the service fails to start, check the logs. WireGuard errors usually appear in the journal immediately.

sudo journalctl -xeu wg-quick@wg0
# Show recent logs for the WireGuard service with explanatory text.

Run journalctl first. Read the actual error before guessing. A syntax error in the config file stops the service instantly.

Authorize clients

The server is ready. Clients need a configuration to connect. Each client requires its own private key and the server's public key. The server config must list authorized peers. Each peer gets a section with their public key and allowed IPs.

Add a [Peer] section to /etc/wireguard/wg0.conf for each client.

[Peer]
PublicKey = <client-public-key>
# The client's public key.
AllowedIPs = 10.0.0.2/32
# The IP assigned to this client. /32 restricts the route to this single IP.

Reload the config after adding peers. wg-quick does not support hot-reloading peers. You must restart the interface.

sudo wg-quick down wg0
sudo wg-quick up wg0
# Restart the interface to apply peer changes.

The client configuration needs the server's public key, endpoint, and allowed IPs. The client AllowedIPs determines what traffic goes through the tunnel. Use 0.0.0.0/0 to route all traffic. Use 10.0.0.0/24 for LAN-only access.

Check the keys. A typo in a public key breaks the tunnel silently. The handshake will fail without a clear error message.

Common pitfalls

Several issues stop the tunnel from working. Identify the symptom and apply the fix.

The firewall blocks the port. If firewall-cmd --list-all does not show 51820/udp, the PostUp hook failed. Check the zone name. Cloud providers often require security group rules in addition to the host firewall. Open UDP 51820 in your cloud console. AWS, GCP, and Azure block inbound UDP by default.

The interface name is wrong. Some tutorials use eth0 in iptables rules. Fedora uses predictable names like ens192 or enp0s3. wg-quick does not care about the external interface name for NAT. The firewall-cmd masquerade applies to all traffic leaving the server. You do not need to specify the external interface in the WireGuard config.

SELinux denies access. If the service fails and journalctl shows AVC denials, restore the context. WireGuard expects keys in /etc/wireguard/ with specific contexts.

sudo restorecon -Rv /etc/wireguard/
# Restore default SELinux contexts for the WireGuard directory.

SELinux denials show up in journalctl -t setroubleshoot. Read those before disabling SELinux. Disabling SELinux is rarely the fix.

Masquerade is missing. If clients can ping the server but not the internet, masquerading is disabled. Verify firewall-cmd --list-all shows masquerade: yes. If you restart firewalld, the runtime masquerade might drop. The PostUp hook restores it when wg-quick restarts. If you need persistence across firewall restarts, add masquerade permanently.

sudo firewall-cmd --permanent --add-masquerade
# Persist masquerade across firewall restarts.
sudo firewall-cmd --reload
# Apply the permanent configuration.

Use permanent firewall rules when you restart firewalld frequently. Use PostUp hooks when you want the firewall state tied to the tunnel lifecycle.

When to use WireGuard

Choose the right tool for your network requirements. WireGuard excels in specific scenarios.

Use WireGuard when you want low latency, simple configuration, and modern cryptography. Use OpenVPN when you need TCP fallback or legacy firewall traversal. Use IPsec when you are integrating with enterprise directory services or require IKEv2 standards. Stay on the default wg-quick setup if you are running a personal server or small team.

WireGuard is a kernel module. It is faster than userspace VPNs. The configuration is minimal. The attack surface is small. It is the default choice for new deployments.

Where to go next