A complete, production-ready home laboratory infrastructure based on pfSense, Hyper-V, Samba AD, VLANs, and DMZ isolation with Traefik reverse proxy.
This laboratory is the result of my self-taught learning with the help of AI and my own experience. You use it at your own risk. Everything I publish is tested and works.
- Project Overview
- Architecture & Components
- Network Topology & VLAN Segmentation
- Security & Firewall Rules
- Installation & Configuration Guide
- Services & Deployment
- Traefik Reverse Proxy Deployment
- Advanced Features & Troubleshooting
- Future Enhancements
- References & Support
This project documents a complete, isolated home laboratory running on Hyper-V with enterprise-grade network segmentation using pfSense as the central firewall and router.
✅ Complete Network Isolation – Home network remains untouched via double NAT
✅ VLAN Segmentation – 4 logical security zones (Infra, Servers, Clients, DMZ)
✅ Active Directory – Samba 4 AD DC for centralized management
✅ Firewalling – Granular rules with default-deny policy
✅ DMZ Security – Isolated zone for externally-exposed services
✅ Reverse Proxy – Traefik v3.6 with centralized routing for all DMZ services
✅ DNS Resolution – Centralized DNS with internal domain (homelab.local)
✅ Auto SSL – Self-signed certificates for internal lab (Let's Encrypt ready)
✅ Production-Ready – Suitable for learning and professional experimentation
┌─────────────────────────────────────────────────────────────┐
│ Internet │
└────────────────────────────┬────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Home Network Router (192.168.2.0/24) │
└────────────────────────────┬────────────────────────────────┘
│
WAN (192.168.2.141)
│
┌───────────────────┴───────────────────┐
│ │
┌────▼────┐ ┌────▼────┐
│ Hyper-V │◄──────────────────────────►│ pfSense │
│ Host │ vSwitches │ VM │
└────┬────┘ └────┬────┘
│ │
┌─────┴────────┬──────────────┬──────────────┴─────┐
│ │ │ │
VLAN 10 VLAN 20 VLAN 30 VLAN 40
(Infra) (Servers) (Clients) (DMZ)
192.168.10.0 192.168.20.0 192.168.30.0 192.168.40.0
│ │ │ │
│ │ │ │
DC/DNS n8n, Apps Test Clients nginx
Samba AD Containers Windows/Linux Web Server
DMZ Traffic Flow (New Architecture):
Internet → pfSense NAT (80/443) → Traefik (.40) → Nginx (.50)
Each VLAN represents a security domain with independent firewall rules, DHCP scope, and DNS configuration.
| Component | Role | Location | IP Address | Status |
|---|---|---|---|---|
| pfSense VM | Firewall & Router | Hyper-V | WAN: 192.168.2.141 | ✅ Running |
| Samba AD DC | Directory Services | VLAN 10 | 192.168.10.10 | ✅ Running |
| Traefik | Reverse Proxy | VLAN 40 (DMZ) | 192.168.40.40 | ✅ Running |
| Nginx Server | Web Server | VLAN 40 (DMZ) | 192.168.40.50 | ✅ Running |
- Hyper-V: Windows Server or Pro
- 2 Virtual Switches:
- vSwitch-LAB-WAN (external, connected to physical NIC)
- vSwitch-LAB-LAN (internal, trunk mode for all VLANs)
- Multiple VMs: Ubuntu Server, Windows Desktop, Docker containers
Network:
- Gateway: 192.168.10.1
- Subnet: 192.168.10.0/24
- DHCP: 192.168.10.50–199
- DNS Resolver: Internal Samba DNS (192.168.10.10)
Services:
- Samba 4 AD DC (192.168.10.10)
- Centralized DNS server for
homelab.local - NTP services
- Core directory services
Security Rules:
- Allow DNS, Kerberos (88), LDAP (389), SMB (445), RPC (135, 1024-65535) to/from DC
- Allow outbound Internet
- Deny inter-VLAN access
Domain-Joined Machines:
- Servers in VLAN 20
- Workstations in VLAN 30
- NOT DMZ (intentionally isolated)
Network:
- Gateway: 192.168.20.1
- Subnet: 192.168.20.0/24
- DHCP: 192.168.20.50–199
Services:
- Docker containers
- n8n (workflow automation)
- Backend APIs
- Development & testing environments
Security Rules:
- Allow outbound Internet
- Allow access to VLAN 10 DC (for domain services)
- Deny access to DMZ
Network:
- Gateway: 192.168.30.1
- Subnet: 192.168.30.0/24
- DHCP: 192.168.30.50–199
Services:
- Windows desktop machines (AD testing)
- Linux client machines (SSSD joined)
- Test workstations
Security Rules:
- Allow access to VLAN 10 (DC, DNS, Kerberos)
- Allow outbound Internet
- Deny access to VLAN 20, VLAN 40
Network:
- Gateway: 192.168.40.1
- Subnet: 192.168.40.0/24
- DHCP: 192.168.40.50–199
- DNS Resolver: External only (1.1.1.1, 8.8.8.8)
Purpose:
- Externally-exposed web services
- Reverse proxies (Traefik at .40)
- Backend services (Nginx at .50)
- Public-facing applications
Critical Security Property:
🔒 NOT Domain-Joined – completely isolated from Active Directory
Security Rules:
- ✅ Allow outbound: HTTP (80), HTTPS (443), DNS (53) only
- ✅ Allow inbound: WAN via NAT port forwarding (ports 80/443 → Traefik)
- ❌ Block ALL access to internal VLANs (10, 20, 30) using RFC1918 alias
- ❌ No access to AD DC
- ✅ Allow intra-DMZ communication (Traefik ↔ Nginx)
Default Deny + Explicit Allow
Every VLAN follows this principle:
- ❌ All inter-VLAN traffic blocked by default
- ✅ Only explicitly configured traffic allowed
- ✅ Each rule specifies source, destination, and ports
- 📊 All rules logged for audit and troubleshooting
A firewall alias combining all private networks for easy DMZ isolation:
Name: RFC1918
Description: Private IPv4 networks
Networks:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16
Used by DMZ firewall rules to block all internal networks in a single rule.
| Source VLAN | Destination | Ports | Protocol | Action | Purpose |
|---|---|---|---|---|---|
| All | pfSense | 53 | TCP/UDP | Allow | DNS resolution |
| 10, 20, 30 | Any | Any | Any | Allow | Internet access |
| 40 | Any | 80, 443, 53 | TCP/UDP | Allow | HTTP/HTTPS/DNS outbound |
| 40 | RFC1918 | All | Any | Block | DMZ isolation |
| 40 | 40 subnet | All | Any | Allow | Intra-DMZ (Traefik ↔ Nginx) |
| 30 | 10.10 | 53, 88, 389, 445, 135, 1024-65535 | TCP/UDP | Allow | Domain services |
| 20 | 10.10 | 53, 88, 389, 445, 135, 1024-65535 | TCP/UDP | Allow | Domain services |
For externally-exposed services (via Traefik):
| WAN Port | Protocol | DMZ IP | DMZ Port | Service | Status |
|---|---|---|---|---|---|
| 80 | TCP | 192.168.40.40 | 80 | HTTP → Traefik | ✅ Active |
| 443 | TCP | 192.168.40.40 | 443 | HTTPS → Traefik | ✅ Active |
Note: All traffic now goes to Traefik first, which then routes to backend services (Nginx, APIs, etc.)
Hardware Requirements:
- Windows Server 2016+ or Hyper-V Pro (Windows 10/11 Pro/Enterprise)
- 4+ CPU cores
- 16+ GB RAM (8GB minimum)
- 500GB+ free disk space
Network Requirements:
- Existing home/lab network with Internet connectivity
- One network interface card (dual NICs recommended)
Create Hyper-V VM:
- 2 vCPU, 2–4 GB RAM, 20–40 GB disk
- 2 vNICs: WAN (external) + LAN (internal, trunk)
Virtual Switches (PowerShell):
# External switch for WAN
New-VMSwitch -Name "vSwitch-LAB-WAN" -NetAdapterName "Ethernet"
# Internal switch for LAN (VLANs)
New-VMSwitch -Name "vSwitch-LAB-LAN" -SwitchType Internal
# Attach to pfSense VM
Add-VMNetworkAdapter -VMName "VM-pfsense" -SwitchName "vSwitch-LAB-WAN"
Add-VMNetworkAdapter -VMName "VM-pfsense" -SwitchName "vSwitch-LAB-LAN"
# Enable trunk on LAN interface
Get-VMNetworkAdapter -VMName "VM-pfsense" |
Where-Object {$_.SwitchName -eq "vSwitch-LAB-LAN"} |
Set-VMNetworkAdapterVlan -Trunk -AllowedVlanIdList "10,20,30,40" -NativeVlanId 0pfSense Web UI Configuration:
- Interfaces → VLANs: Create VLAN 10, 20, 30, 40
- Interfaces → Assignments: Assign OPT1–4 to each VLAN
- Services → DHCP Server: Configure DHCP for each VLAN
- Services → DNS Resolver: Conditional forward (homelab.local → 192.168.10.10)
Ubuntu Server VM:
- VLAN: 10 (Infra)
- IP: 192.168.10.10/24 (static)
- Hostname: dc1
- FQDN: dc1.homelab.local
Network Configuration (/etc/netplan/00-installer-config.yaml):
network:
version: 2
ethernets:
ens18:
dhcp4: no
addresses:
- 192.168.10.10/24
routes:
- to: default
via: 192.168.10.1
nameservers:
addresses:
- 127.0.0.1Apply:
sudo netplan applyInstall Samba 4 AD DC:
sudo apt update
sudo apt install samba krb5-user winbind dnsutils -y
sudo systemctl stop smbd nmbd winbind
sudo systemctl disable smbd nmbd winbind
sudo samba-tool domain provision \
--realm HOMELAB.LOCAL \
--domain HOMELAB \
--server-role dc \
--dns-backend SAMBA_INTERNAL \
--dns-forwarder 1.1.1.1
sudo cp -f /var/lib/samba/private/krb5.conf /etc/krb5.conf
sudo systemctl unmask samba-ad-dc
sudo systemctl enable samba-ad-dc
sudo systemctl start samba-ad-dc
# Verify
samba-tool domain level showCreate RFC1918 Alias:
Web UI → Firewall → Aliases → IP → Add
Name: RFC1918
Description: Private IPv4 networks
Type: Network(s)
Networks:
10.0.0.0/8
172.16.0.0/12
192.168.0.0/16
VLAN 40 (DMZ) Rules:
Web UI → Firewall → Rules → OPT4(LAN_DMZ)
- Allow DNS outbound
- Allow HTTP/HTTPS outbound
- Block RFC1918 (all internal networks)
- Allow intra-DMZ communication
VM: 192.168.40.50 (VLAN 40)
Role: Standard Web Server (proxied by Traefik)
# On DMZ VM (.50)
sudo apt update
sudo apt install nginx -y
sudo systemctl start nginx
sudo systemctl enable nginx
# Verify locally
curl http://localhost
# Expected: "Welcome to Nginx!"VM: 192.168.40.40 (VLAN 40 - DMZ)
Role: Central Entry Point & Reverse Proxy for all DMZ services
- ✅ Automatic SSL with self-signed certs (Let's Encrypt ready)
- ✅ Dynamic routing to multiple backend services
- ✅ Dashboard for monitoring routes & services
- ✅ Single entry point from WAN (simplifies NAT)
Important: Redirect WAN traffic to Traefik (not Nginx directly anymore).
Firewall → NAT → Port Forward:
HTTP (Port 80):
Interface: WAN
Protocol: TCP
Destination: WAN address
Dest. Port: 80
Redirect Target IP: 192.168.40.40 (Traefik)
Redirect Target Port: 80
Add Filter Rule: ✓
Description: NAT HTTP → Traefik Proxy
HTTPS (Port 443):
Interface: WAN
Protocol: TCP
Destination: WAN address
Dest. Port: 443
Redirect Target IP: 192.168.40.40 (Traefik)
Redirect Target Port: 443
Add Filter Rule: ✓
Description: NAT HTTPS → Traefik Proxy
On VM 192.168.40.40:
mkdir -p ~/traefik/dynamic
cd ~/traefik
touch docker-compose.yml traefik.yml dynamic/external_services.yml acme.json
chmod 600 acme.jsonFile: ~/traefik/docker-compose.yml
services:
traefik:
image: traefik:v3.6 # v3.6+ required for Docker API v1.44 compatibility
container_name: traefik
restart: unless-stopped
security_opt:
- no-new-privileges:true
ports:
- "80:80"
- "443:443"
# - "8080:8080" # Uncomment for dashboard (insecure, local only)
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/traefik.yml:ro
- ./dynamic:/dynamic:ro
- ./acme.json:/acme.json
networks:
- proxy
networks:
proxy:
name: proxy_networkFile: ~/traefik/traefik.yml
api:
dashboard: true
insecure: false # Set to true ONLY for local debugging
entryPoints:
web:
address: ":80"
http:
redirections:
entryPoint:
to: websecure
scheme: https # Auto-redirect HTTP → HTTPS
websecure:
address: ":443"
providers:
docker:
endpoint: "unix:///var/run/docker.sock"
exposedByDefault: false # Security: explicit opt-in per container
file:
directory: "/dynamic"
watch: true # Auto-reload dynamic config files
# Optional: Let's Encrypt (for public domains only)
# certificatesResolvers:
# myresolver:
# acme:
# email: your-email@example.com
# storage: acme.json
# httpChallenge:
# entryPoint: webFile: ~/traefik/dynamic/external_services.yml
This file connects Traefik (192.168.40.40) to Nginx (192.168.40.50):
http:
routers:
nginx-router:
# Option 1: Accept all traffic (simple, for lab)
rule: "PathPrefix(`/`)"
# Option 2: Strict by IP/Domain (recommended)
# rule: "Host(`192.168.40.40`) || Host(`192.168.40.50`) || Host(`mysite.homelab.local`)"
service: nginx-service
entryPoints:
- websecure
tls: {} # Self-signed cert by default (Traefik Default Cert)
services:
nginx-service:
loadBalancer:
servers:
- url: "http://192.168.40.50:80"cd ~/traefik
docker compose up -d
# Verify logs
docker compose logs -fTest from DMZ VM (192.168.40.50):
curl -k https://192.168.40.40
# Expected output: "Welcome to Nginx!" (HTML)Test from external network (if WAN forwarding is active):
curl -k https://YOUR_PUBLIC_IP
# Expected output: "Welcome to Nginx!"Traffic Flow:
Internet → pfSense (NAT) → Traefik (.40) → Nginx (.50) → Response
To add a new backend service (e.g., n8n, API, dashboard), simply add a new router in dynamic/external_services.yml:
http:
routers:
nginx-router:
rule: "Host(`192.168.40.40`)"
service: nginx-service
entryPoints:
- websecure
tls: {}
n8n-router:
rule: "Host(`n8n.homelab.local`)"
service: n8n-service
entryPoints:
- websecure
tls: {}
services:
nginx-service:
loadBalancer:
servers:
- url: "http://192.168.40.50:80"
n8n-service:
loadBalancer:
servers:
- url: "http://192.168.20.10:5678" # Example: n8n in VLAN 20Error: client version 1.24 is too old. Minimum supported API version is 1.44
Cause: Docker daemon v29+ requires API v1.44, but Traefik v3.0–v3.5 negotiates with older API.
Fix: Upgrade Traefik image to v3.6 or higher in docker-compose.yml:
image: traefik:v3.6Then:
docker compose pull
docker compose up -d --force-recreateError: 404 page not found
Cause: Host() rule in dynamic config doesn't match the request's Host header.
Debugging:
-
Check what Host header you're sending:
curl -v https://192.168.40.40 # Look for: > Host: 192.168.40.40 -
Update
ruleinexternal_services.ymlto match:rule: "Host(`192.168.40.40`)" # OR accept everything: rule: "PathPrefix(`/`)"
-
Traefik auto-reloads dynamic configs (check logs to confirm).
Error: unable to generate a certificate for domains [192.168.40.50]: IP address is in reserved address block [RFC1918]
Cause: Let's Encrypt refuses to issue certificates for private IPs or .local domains.
Fix for Lab Environment:
Remove certResolver: myresolver from your router config and use Traefik's default self-signed certificate:
tls: {} # No certResolverFix for Production (Public Domain Required):
- Own a public domain (e.g.,
mylab.com) - Create DNS A record pointing to your public IP
- Ensure ports 80/443 are forwarded through your ISP router → pfSense → Traefik
- Use
certResolver: myresolverin router config
Verify Traefik can reach Nginx:
docker exec traefik ping -c 3 192.168.40.50
# Expected: 3 packets received, 0% lossCheck if Traefik is loading dynamic config:
docker compose logs -f | grep -i "dynamic\|nginx"
# Should show no errors about external_services.ymlDNS not resolving:
# On DC
sudo systemctl status samba-ad-dc
dig @127.0.0.1 dc1.homelab.local
# On client
nslookup dc1.homelab.local 192.168.10.10Backup domain:
sudo samba-tool domain backup online --targetdir=/backup- Traefik Dashboard secured with authentication
- Let's Encrypt integration for public domain
- Secondary DC for redundancy
- WireGuard VPN for remote access
- Automated backups (VM snapshots + Samba domain)
- Additional services behind Traefik (n8n, Uptime Kuma, Grafana)
- Log aggregation (ELK stack)
- Monitoring (Prometheus + Grafana)
- Container orchestration (Docker Swarm / K3s)
- Kubernetes cluster (k3s) in VLAN 20
- IDS/IPS (Suricata) on pfSense
- Advanced threat simulation lab
- Multi-site VPN mesh
Detailed technical guides provided:
| File | Topic |
|---|---|
| Docs_01_pfsense_HyperV.txt | pfSense initial setup & architecture overview |
| Docs_02_pfsense_HyperV.txt | Network design & VLAN strategy |
| Docs_03_pfsense_HyperV.txt | Address plan & VLAN configuration |
| Docs_04_Set_HyperV_Trunk.txt | Hyper-V trunk mode setup (PowerShell) |
| Docs_05_Set_pfSense_FW_Rules.txt | Firewall rules for Infra VLAN |
| Docs_06_Set_pfSense_FW_Rules_DMZ.txt | DMZ rules & RFC1918 alias |
| Docs_07_Set_pfSense_FW_Rules_DMZ.txt | Port forwarding & NAT config |
| Docs_08_Set_Nginx_WebServer.txt | Nginx installation & basic config |
| Docs_09_Rename_dc_Server.txt | Hostname management for AD DC |
| Docs_10_Deploy_Samba_DC.txt | Complete Samba AD DC deployment |
| Docs_11_Deploy_Samba_DC_OU_Archi.txt | AD organizational unit design |
- pfSense: https://docs.netgate.com/
- Traefik: https://doc.traefik.io/traefik/
- Samba: https://www.samba.org/samba/docs/
- Hyper-V: https://docs.microsoft.com/windows-server/virtualization/hyper-v/
- Docker: https://docs.docker.com/
- NIST Cybersecurity Framework: https://www.nist.gov/cyberframework
- CIS Benchmarks: https://www.cisecurity.org/benchmarks
- RFC 1918 (Private Addresses): https://tools.ietf.org/html/rfc1918
- pfSense Forums: https://forum.netgate.com/
- Traefik Community: https://community.traefik.io/
- Homelab Reddit: https://www.reddit.com/r/homelab/
This documentation and configuration examples are provided as-is for educational and personal use.
Use at your own discretion and risk.
| Component | Status | Notes |
|---|---|---|
| pfSense Setup | ✅ Complete | Stable, VLAN-configured |
| AD DC (Samba) | ✅ Complete | Functional, OUs created |
| Firewall Rules | ✅ Complete | Default-deny, all VLANs |
| DMZ Isolation | ✅ Complete | Tested & verified |
| DNS & DHCP | ✅ Complete | Conditional forwarding active |
| Nginx (HTTP) | ✅ Complete | Backend service running |
| Traefik (Reverse Proxy) | ✅ Complete | Centralized routing active |
| NAT | ✅ Complete | WAN → Traefik → Nginx functional |
| Monitoring | ⏳ Planned | Prometheus/Grafana |
| HA/Replication | ⏳ Planned | Secondary DC, redundancy |
| VPN | ⏳ Planned | WireGuard/IPsec |
System Engineer
🍜 Noodle Enthusiast | ⛰️ Mountain Lover | ⛩️ Shinto Sanctuary Visitor | 🍫 Chocolate Aficionado
Location: Brussels, Belgium
Last Updated: December 31, 2025
Version: 2.0 (with Traefik integration)
Enjoy your homelab! 🚀