Building a Secure, Split‑Tunnel WireGuard Homelab (End‑to‑End)

This page documents the complete, final configuration of a secure homelab built with WireGuard, Raspberry Pis, UFW, AdGuard Home, Fail2Ban, n8n automation, and Uptime Kuma. It is written as a from‑top‑to‑bottom reference: design intent, implementation, validation, and final security posture.

The goal is not maximum complexity, but clear, intentional security that is easy to operate and reason about.


Design Goals

  • Secure all management access using WireGuard
  • Preserve full internet speed (no full‑tunnel VPN)
  • Expose only explicitly intended public services
  • Eliminate accidental routing, NAT, and DNS side effects
  • Provide monitoring, alerting, and automated response
  • Keep the system auditable and maintainable

Final Architecture Overview

  • Main Server: WireGuard server and central management node
  • Raspberry Pi 1 & 2: WireGuard clients and service hosts
  • VPN Subnet: 10.8.0.0/24
  • Tunnel Mode: Split tunnel (VPN traffic only)
  • DNS: Local (AdGuard Home on Raspberry Pi)
  • Firewall: UFW (IPv4 only)
  • IPv6: Disabled intentionally

Only traffic destined for the VPN subnet traverses WireGuard. All normal internet traffic continues to use the local gateway.


WireGuard Configuration (Final)

Server — /etc/wireguard/wg0.conf

[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = PLEASE_PUT_YOUR_SERVER_PRIVATE_KEY

[Peer]
PublicKey = PLEASE_PUT_YOUR_PI1_PUBLIC_KEY
AllowedIPs = 10.8.0.2/32

[Peer]
PublicKey = PLEASE_PUT_YOUR_PI2_PUBLIC_KEY
AllowedIPs = 10.8.0.3/32

Raspberry Pi Clients — /etc/wireguard/wg0.conf

[Interface]
Address = PLEASE_PUT_YOUR_PI_WG_IP
PrivateKey = PLEASE_PUT_YOUR_PI_PRIVATE_KEY
# No DNS line (AdGuard Home runs locally)

[Peer]
PublicKey = PLEASE_PUT_YOUR_SERVER_PUBLIC_KEY
Endpoint = PLEASE_PUT_YOUR_SERVER_PUBLIC_IP_OR_DNS:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25

Critical rule: AllowedIPs = 10.8.0.0/24

Using /0 would unintentionally create a full‑tunnel VPN and introduce NAT dependencies. The /24 mask ensures a true split tunnel.


Routing Validation (Required)

On each Raspberry Pi:

ip route

Expected output:

  • Default route → LAN gateway
  • 10.8.0.0/24wg0

If the default route points to wg0, stop and correct the configuration before continuing.


DNS Design (AdGuard Home)

  • AdGuard Home runs locally on a Raspberry Pi
  • WireGuard does not override DNS
  • No DNS= directive exists in WireGuard configs

Public DNS services are intentionally exposed:

  • 53/udp, 53/tcp — DNS
  • 853/tcp — DNS‑over‑TLS

DNS logs feed automation for abuse detection and response.


IPv6 Policy

IPv6 is intentionally disabled to reduce complexity and avoid dual‑stack routing and DNS edge cases common in small environments.

Sysctl — /etc/sysctl.d/99-disable-ipv6.conf

net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.lo.disable_ipv6 = 1

UFW IPv6 toggle — /etc/default/ufw

IPV6=no

The environment operates entirely over IPv4.


Firewall Policy (UFW — Final)

Default Policy

ufw default deny incoming
ufw default allow outgoing

Publicly Exposed (Intentional)

  • 22/tcp — SSH (WireGuard‑only or rate‑limited)
  • 80/tcp — HTTP
  • 443/tcp — HTTPS
  • 51820/udp — WireGuard
  • 53/udp, 53/tcp — DNS
  • 853/tcp — DNS‑over‑TLS

WireGuard Internal Access

ufw allow in on wg0
ufw allow in on wg0 to any port 53
ufw allow in on wg0 to any port 853

SSH Access Model

Preferred (WireGuard‑only):

ufw allow from 10.8.0.0/24 to any port 22 proto tcp

External scans and LAN SSH attempts correctly show blocked.


SSH Hardening

  • SSH key‑only authentication
  • Password authentication disabled
  • Root login avoided or disabled
  • SSH reachable only via WireGuard IPs

Ping confirms network reachability. SSH access requires correct user and authorized key placement.


Docker Monitoring (Uptime Kuma)

  • Docker API is never public
  • Accessed only over WireGuard
  • Exposed via read‑only docker‑socket‑proxy

Firewall rule:

ufw allow from 10.8.0.0/24 to any port 2375

This allows monitoring without exposing control capabilities.


Detection, Alerting, and Automation

  • Fail2Ban blocks brute‑force attempts
  • AdGuard Home logs capture DNS abuse
  • n8n processes events every minute
  • Automated IP blocking is applied
  • Alerts are delivered to Slack
  • Uptime Kuma monitors hosts and containers

This provides a full detect → alert → respond pipeline.


Validation Checklist

wg
ip route
ping 10.8.0.1
ping 8.8.8.8
ping google.com
ufw status verbose
ss -tulpen | head -n 30

External port scans for SSH should show blocked. SSH access works only from WireGuard peers using WireGuard IPs.


Common Pitfalls (Avoided)

  • AllowedIPs = 0.0.0.0/0 (unintended full tunnel)
  • Overriding DNS when AdGuard runs locally
  • Exposing Docker APIs publicly
  • Using HTTPS proxies as Docker security
  • Relying on firewall NAT side effects

Final Summary

This setup results in a secure, split‑tunnel WireGuard network between a main server and multiple Raspberry Pis, while keeping performance high and avoiding unnecessary complexity.

The main server acts as the WireGuard server, and each Raspberry Pi connects as a client on a private VPN subnet (10.8.0.0/24). Only internal VPN traffic is routed through WireGuard, while normal internet traffic continues to use each device’s local gateway. This design avoids speed degradation and removes the need for NAT or full‑tunnel routing.

DNS handling is intentionally local. Because one Raspberry Pi runs AdGuard Home, WireGuard does not override system DNS settings, preventing common resolution issues and keeping behavior predictable.

IPv6 is permanently disabled to reduce complexity and avoid dual‑stack edge cases. The firewall exposes only explicitly intended services, and SSH access is restricted to WireGuard peers using key‑only authentication.

Monitoring, alerting, and automated response are handled through Uptime Kuma, Fail2Ban, and n8n, providing real‑time visibility and protection.

The final result is a fast, secure, low‑maintenance homelab with a clearly defined attack surface, intentional access paths, and documented operating procedures — designed for reliability rather than complexity.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Secret Link