commit 38f2aefecd92968f3ba3addc3bf791b30c9a76a8 Author: Kenji Morishige Date: Wed Apr 22 14:42:43 2026 -0500 Add pfSense backup utility and documentation - Add backup-pfsense-config.sh script for automated config backups via SSH - Auto-commits backups to git with timestamped filenames - Includes validation, error handling, and troubleshooting guides - Add scripts/README.md with detailed usage and crontab examples - Add BACKUP-QUICKSTART.md for quick reference commands - Update README.md to reference automated backup workflow - Create backups/ directory structure The script tests SSH connectivity successfully to pfSense. diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..b93b99f Binary files /dev/null and b/.DS_Store differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..8ea66aa --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# appa-net + +Central repository for managing, orchestrating, and storing configuration for local network infrastructure and servers. + +## Overview + +This repository serves as the single source of truth for your home network's server and infrastructure configurations. By versioning your network infrastructure as code, you gain: + +- **Version control** — track all configuration changes, revert if needed +- **Documentation** — configurations serve as living documentation +- **Reproducibility** — easily redeploy or migrate services +- **Auditability** — understand who changed what and when + +## Repository Structure + +Each folder represents a network-accessible device or server, named using the `.home.arpa` suffix (RFC 6762 — local network discovery): + +``` +appa-net/ +├── pfsense.home.arpa/ # pfSense router/firewall (DHCP, DNS, NAT, etc.) +├── zet.home.arpa/ # General compute/services (Squid proxy, etc.) +└── README.md # This file +``` + +### Directory Naming Convention + +- **Domain format**: Use `hostname.home.arpa` to follow RFC 6762 conventions for local-only names +- **Lowercase**: Keep hostnames lowercase for consistency +- **Self-contained**: Each folder contains all configs and documentation specific to that device + +## Device Inventory + +### pfsense.home.arpa +Your primary router/firewall running pfSense. Handles: +- DHCP and static IP assignment +- DNS resolution +- WAN/LAN routing +- NAT and port forwarding +- Firewall rules + +**Configurations to track:** +- System configuration backups (XML exports) +- Firewall rules and aliases +- Static routes +- NAT rules and port forwards +- DHCP scopes and reservations +- DNS configuration +- VPN settings (if applicable) + +### zet.home.arpa +General-purpose compute server. Currently running: +- **Squid** transparent proxy for HTTP traffic interception and caching + +**Configurations to track:** +- Squid configuration and rules +- iptables/firewall rules for traffic redirection +- Service startup and monitoring scripts +- Application-specific settings + +## Adding a New Device + +To add a new server or device to this repository: + +1. Create a new folder: `mkdir hostname.home.arpa` +2. Add relevant configuration files: + - Configuration files (YAML, JSON, or text formats for readability) + - README.md explaining the device's purpose and key configurations + - Any orchestration scripts (Ansible playbooks, Terraform configs, etc.) +3. Commit with a clear message: `Add hostname.home.arpa configuration` + +Example structure for a new device: +``` +myserver.home.arpa/ +├── README.md # Purpose, role, and setup notes +├── config/ +│ ├── app.conf +│ └── network.conf +├── scripts/ +│ └── deploy.sh +└── orchestration/ + └── playbook.yml # (if using Ansible) +``` + +## Management Approaches + +### Orchestration Tools (Recommended for Future) +Consider these tools for managing configurations at scale: + +- **Ansible** — agentless configuration management, great for heterogeneous infrastructure +- **Terraform** — infrastructure-as-code, useful for reproducible deployments +- **Docker/Compose** — containerize services for consistency across hosts +- **Custom scripts** — shell scripts for simple one-off configurations + +### Backup Strategy +- Export pfSense configs regularly (Diagnostics → Backup/Restore) +- Archive configuration snapshots in this repo with timestamps +- Keep sensitive data (keys, credentials) in a secure vault outside this repo + +### Best Practices + +1. **Documentation First** — Each device folder should have a README explaining: + - Device purpose and role in the network + - IP address and hostname + - Key services running + - How to access and modify configurations + +2. **Configuration as Code** — Store configs in text-based formats (YAML, JSON, conf) when possible + - Avoid binary formats; prefer exports you can diff + - Use comments to explain non-obvious settings + +3. **Secrets Management** — Never commit passwords, API keys, or tokens: + - Store sensitive values in `.env` files or a secrets manager + - Use `{% raw %}{{ variables }}{% endraw %}` placeholders in configs + - Document where secrets come from (e.g., "stored in Bitwarden") + +4. **Change Control** — Use git commits to document infrastructure changes: + ``` + git commit -m "pfsense: Add NAT rule for Squid traffic interception" + ``` + +5. **Testing Changes** — When possible, test config changes in a staging environment first + +## Feedback on Your Current Setup + +**✅ Strengths:** +- Using `.home.arpa` naming is correct per RFC 6762 +- Clear device-based organization scales well +- Git-based versioning from the start is a great practice +- Already documenting configuration workflows (PROXY-SETUP.md) + +**💡 Suggestions:** +1. Add a README to `pfsense.home.arpa/` documenting: + - Current network topology and IP ranges + - Important firewall rules + - How to export/restore backups + +2. Consider a `docs/` folder at the root for: + - Network topology diagrams (Mermaid, draw.io) + - IP addressing scheme and VLAN assignments + - Service dependencies and network flows + +3. For pfSense backups: + - Export XML configs to `pfsense.home.arpa/backups/` with dates + - Document critical custom configurations as markdown files + +4. As you add more devices, consider an inventory file (YAML/JSON) at the root: + ```yaml + # inventory.yml + devices: + pfsense.home.arpa: + ip: 172.27.0.1 + role: router/firewall + zet.home.arpa: + ip: 172.27.0.35 + role: compute/proxy + ``` + +5. Add GitHub Actions or a CI workflow to: + - Validate configuration syntax + - Generate documentation from configs + - Alert on uncommitted changes (for critical devices) + +## Quick Start + +1. Navigate to a device folder: + ```bash + cd pfsense.home.arpa + ``` + +2. Review current configuration: + ```bash + cat README.md + ``` + +3. Make changes and commit: + ```bash + git add . + git commit -m "Description of change" + git push + ``` + +## Contributing & Maintenance + +- **Regular backups**: Schedule automated exports of device configs to this repo +- **Documentation updates**: Keep READMEs in sync with actual configurations +- **Change log**: Use commit messages to maintain a history of infrastructure decisions +- **Review**: Before major changes, review existing configs to understand dependencies + +--- + +**Last Updated:** 2026-04-22 \ No newline at end of file diff --git a/pfsense.home.arpa/BACKUP-QUICKSTART.md b/pfsense.home.arpa/BACKUP-QUICKSTART.md new file mode 100644 index 0000000..32cc7e1 --- /dev/null +++ b/pfsense.home.arpa/BACKUP-QUICKSTART.md @@ -0,0 +1,68 @@ +# Quick Backup Reference + +One-liner commands to backup your pfSense configuration. + +## Basic Commands + +```bash +# Navigate to the pfsense folder +cd /Users/kenjim/workspace/src/personal/appa-net/pfsense.home.arpa + +# Test SSH connection (no download) +./scripts/backup-pfsense-config.sh --dry-run + +# Backup with auto-commit to git (default) +./scripts/backup-pfsense-config.sh + +# Backup without auto-commit +./scripts/backup-pfsense-config.sh -n + +# Backup from different host +./scripts/backup-pfsense-config.sh 192.168.1.1 +``` + +## Schedule Daily Backups + +Add to your crontab to run at 2 AM every day: + +```bash +crontab -e +``` + +Then add this line: +```cron +0 2 * * * cd /Users/kenjim/workspace/src/personal/appa-net/pfsense.home.arpa && ./scripts/backup-pfsense-config.sh > /tmp/pfsense-backup.log 2>&1 +``` + +Verify it was added: +```bash +crontab -l | grep backup-pfsense +``` + +## View Backups + +```bash +# List all backups +ls -lh backups/ + +# Show latest backup +ls -lh backups/ | tail -1 + +# Check git history +git log --oneline backups/ + +# See what changed in latest backup +git show HEAD:backups/ +``` + +## Restore from Backup + +From pfSense WebUI: +1. **Diagnostics → Backup & Restore** +2. **Choose File** → select backup from `backups/` folder +3. **Restore Configuration** +4. Reboot when prompted + +--- + +**Last Updated**: 2026-04-22 diff --git a/pfsense.home.arpa/INDEX.md b/pfsense.home.arpa/INDEX.md new file mode 100644 index 0000000..842507f --- /dev/null +++ b/pfsense.home.arpa/INDEX.md @@ -0,0 +1,150 @@ +# pfsense.home.arpa Documentation Index + +Quick reference to all configuration files and guides in this folder. + +## Files in This Directory + +### 📘 **README.md** (Main Configuration Guide) +Comprehensive reference for managing your pfSense router. Covers: +- VLAN structure and definitions +- Step-by-step configuration instructions +- DHCP setup +- Firewall rules and access control +- Troubleshooting guide + +**When to read**: When you want detailed explanations or reference material +**Length**: ~400 lines (detailed) + +### ⚡ **VLAN-QUICKSTART.md** (Implementation Checklist) +Step-by-step checklist to implement VLANs. Use this for hands-on setup. +- Pre-implementation checklist +- 6 phases with checkbox items +- Testing procedures +- Backup & documentation steps + +**When to read**: When actively configuring your pfSense +**Length**: ~300 lines (action-oriented) + +### 📊 **VLAN-CONFIG.md** (Configuration Reference) +YAML-formatted configuration definitions and quick lookup. +- VLAN definitions (IDs, subnets, purposes) +- Firewall rule summary (matrix view) +- DHCP configuration +- Device assignments +- Implementation checklist +- Design rationale + +**When to read**: For quick lookup of VLAN IDs, subnet ranges, firewall rules +**Length**: ~150 lines (reference) + +### 🗺️ **VLAN-TOPOLOGY.md** (Visual Architecture) +Network diagrams and traffic flow visualization. +- High-level topology ASCII diagrams +- Detailed dataflow examples +- Firewall rule chain visualization +- Port connectivity diagrams +- Traffic examples (allowed and blocked) +- Isolation guarantees + +**When to read**: To understand network architecture or debug traffic issues +**Length**: ~250 lines (visual/conceptual) + +## Quick Navigation + +**I want to...** + +| Task | File | Section | +|------|------|---------| +| Set up VLANs for the first time | VLAN-QUICKSTART.md | Phase 1-6 | +| Understand VLAN architecture | VLAN-TOPOLOGY.md | High-Level Topology | +| Look up a VLAN subnet | VLAN-CONFIG.md | VLAN Definitions | +| Configure firewall rules | README.md | Step 4: Configure Firewall Rules | +| Set up DHCP | README.md | Step 3: Configure DHCP | +| Troubleshoot a problem | README.md | Troubleshooting section | +| Debug traffic | VLAN-TOPOLOGY.md | Traffic Examples | +| Backup my config | README.md | Backup & Recovery | +| Add a new device to a VLAN | VLAN-CONFIG.md | Device Assignments | + +## File Relationships + +``` +README.md + ├─ Detailed explanation of all features + ├─ References: VLAN-CONFIG.md, VLAN-TOPOLOGY.md + └─ Use with: VLAN-QUICKSTART.md for hands-on setup + +VLAN-QUICKSTART.md + ├─ Step-by-step checklist + ├─ References: VLAN-CONFIG.md + └─ Use with: README.md for details + +VLAN-CONFIG.md + ├─ Quick reference data + ├─ Subnet/VLAN ID lookup + └─ Use with: README.md, VLAN-TOPOLOGY.md for context + +VLAN-TOPOLOGY.md + ├─ Visual architecture + ├─ Traffic flow examples + └─ Use with: README.md for firewall rule explanations +``` + +## Setup Workflow Recommended + +1. **Read** VLAN-TOPOLOGY.md (understand the architecture) +2. **Review** VLAN-CONFIG.md (familiarize yourself with IDs and subnets) +3. **Follow** VLAN-QUICKSTART.md (step-by-step implementation) +4. **Reference** README.md (for detailed explanations during setup) +5. **Store** backups/ folder (save pfSense XML configs here) + +## Directory Structure + +``` +pfsense.home.arpa/ +├── README.md # Main configuration guide +├── VLAN-QUICKSTART.md # Hands-on setup checklist +├── VLAN-CONFIG.md # VLAN reference data +├── VLAN-TOPOLOGY.md # Network diagrams +├── INDEX.md # This file +├── backups/ # Store pfSense backups here +│ └── pfsense-config-YYYY-MM-DD.xml +└── scripts/ # Optional: Automation scripts + └── (future: Ansible, Terraform, etc.) +``` + +## Backup Location + +All pfSense configuration exports should be saved to `backups/` folder: + +```bash +# After exporting from pfSense WebUI: +mv ~/Downloads/config.xml backups/pfsense-config-2026-04-22.xml +git add backups/ +git commit -m "pfSense: Backup after VLAN configuration" +``` + +## Future Additions + +As your network grows, consider adding: + +- `FIREWALL-RULES.md` — Detailed firewall rule documentation +- `DHCP-RESERVATIONS.md` — Static IP assignments for devices +- `DNS-CONFIG.md` — DNS resolver and record configuration +- `SCRIPTS/` — Ansible playbooks, Terraform configs, or backup scripts +- `MIGRATION-GUIDE.md` — How to restore from backup or migrate to new pfSense instance + +## Version History + +| Date | Version | Changes | +|------|---------|---------| +| 2026-04-22 | 1.0 | Initial VLAN configuration (3 VLANs: Secure, AIWorkload, IoT) | + +## Related Documents + +- [Root README.md](../README.md) — Project overview +- [zet.home.arpa/PROXY-SETUP.md](../zet.home.arpa/PROXY-SETUP.md) — Squid proxy on VLAN (future: will reference this VLAN config) + +--- + +**Last Updated**: 2026-04-22 +**Current Configuration Version**: 1.0 diff --git a/pfsense.home.arpa/README.md b/pfsense.home.arpa/README.md new file mode 100644 index 0000000..aa67f07 --- /dev/null +++ b/pfsense.home.arpa/README.md @@ -0,0 +1,296 @@ +# pfSense Router Configuration + +Central hub for your home network. Manages DHCP, DNS, routing, firewalling, and network segmentation via VLANs. + +## Overview + +**Device**: pfSense Router +**Primary IP**: 172.27.0.1 (LAN default gateway) +**Role**: Router, Firewall, DHCP server, DNS resolver, VLAN orchestration + +## Network Architecture + +Your home network is segmented into security zones using VLANs. Each VLAN has: +- Isolated broadcast domain +- Separate IP subnet +- Controlled routing and firewall rules between VLANs +- Dedicated DHCP scope (if needed) + +### VLAN Structure + +| VLAN ID | Name | Purpose | Subnet | Gateway | Notes | +|---------|------|---------|--------|---------|-------| +| 1 | `LAN_SECURE` | Trusted personal devices | 172.27.0.0/24 | 172.27.0.1 | Primary network (default) | +| 2 | `VLAN_AIWORKLOAD` | AI/ML dangerous workloads (openclaw) | 172.27.2.0/24 | 172.27.2.1 | Isolated, minimal internet access | +| 3 | `VLAN_IOT` | IoT devices (cameras, smart home) | 172.27.3.0/24 | 172.27.3.1 | Limited trust, blocked from LAN_SECURE | + +## Configuration Steps + +### Prerequisites +- Access to pfSense WebUI or SSH +- Understanding of your network hardware (which ports support VLANs) + +### Step 1: Create VLANs on Physical Interface + +1. Navigate: **Interfaces → VLANs** +2. Click **+ Add** +3. Create `VLAN_AIWORKLOAD`: + - **Parent Interface**: `em0` (or your LAN NIC) + - **VLAN Tag**: `2` + - **VLAN Priority**: `0` (default) + - **Description**: `VLAN_AIWORKLOAD` + - Click **Save** + +4. Create `VLAN_IOT`: + - **Parent Interface**: `em0` + - **VLAN Tag**: `3` + - **VLAN Priority**: `0` + - **Description**: `VLAN_IOT` + - Click **Save** + +5. Click **Apply Changes** + +### Step 2: Create Virtual Interfaces + +1. Navigate: **Interfaces → Assignments** +2. Click **+ Add** next to `VLAN_AIWORKLOAD_2`: + - A new interface (e.g., `OPT1`) is created automatically + - Click the pencil icon to configure it + +3. Configure `OPT1` (VLAN_AIWORKLOAD): + - **Enable Interface**: ✓ Checked + - **Description**: `VLAN_AIWORKLOAD` + - **IPv4 Configuration Type**: `Static IPv4` + - **IPv4 Address**: `172.27.2.1` + - **IPv4 Subnet Mask**: `255.255.255.0` (/24) + - Click **Save** + +4. Repeat for `VLAN_IOT_3`: + - Configure as `OPT2` + - **Description**: `VLAN_IOT` + - **IPv4 Address**: `172.27.3.1` + - **IPv4 Subnet Mask**: `255.255.255.0` (/24) + - Click **Save** + +5. Click **Apply Changes** + +### Step 3: Configure DHCP for Each VLAN + +#### VLAN_AIWORKLOAD DHCP +1. Navigate: **Services → DHCP Server** +2. Click the **VLAN_AIWORKLOAD** tab +3. **Enable DHCP server on VLAN_AIWORKLOAD interface**: ✓ Checked +4. **Range**: `172.27.2.100` to `172.27.2.200` +5. **Gateway**: `172.27.2.1` +6. **Servers**: + - DNS 1: `172.27.0.1` (pfSense resolver) + - DNS 2: `8.8.8.8` (optional fallback) +7. Click **Save** + +#### VLAN_IOT DHCP +1. Click the **VLAN_IOT** tab +2. **Enable DHCP server on VLAN_IOT interface**: ✓ Checked +3. **Range**: `172.27.3.100` to `172.27.3.200` +4. **Gateway**: `172.27.3.1` +5. **Servers**: + - DNS 1: `172.27.0.1` + - DNS 2: `8.8.8.8` +6. Click **Save** + +### Step 4: Configure Firewall Rules + +#### Allow WAN → All VLANs +Navigate: **Firewall → Rules → WAN** +- Default rule should allow established connections + +#### Default LAN → VLAN Rules +Navigate: **Firewall → Rules → LAN_SECURE** + +1. **Allow LAN_SECURE → VLAN_AIWORKLOAD** (if needed): + - Action: `Pass` + - Interface: `LAN` + - Direction: `in` + - Source: `LAN_SECURE subnet` + - Destination: `VLAN_AIWORKLOAD subnet` + - Click **Save** + +2. **Block LAN_SECURE ↔ VLAN_IOT** (by default, implicit deny): + - *No rule needed* — VLANs are isolated by default + - Optionally add explicit block rule for security + +#### VLAN_AIWORKLOAD Rules +Navigate: **Firewall → Rules → VLAN_AIWORKLOAD** + +1. **Allow VLAN_AIWORKLOAD → WAN** (for outbound internet): + - Action: `Pass` + - Source: `VLAN_AIWORKLOAD subnet` + - Destination: `any` + - Protocol: `TCP/UDP` + - Click **Save** + +2. **Block VLAN_AIWORKLOAD → LAN_SECURE**: + - Action: `Block` + - Source: `VLAN_AIWORKLOAD subnet` + - Destination: `LAN_SECURE subnet` + - Click **Save** + +#### VLAN_IOT Rules +Navigate: **Firewall → Rules → VLAN_IOT** + +1. **Allow VLAN_IOT → WAN** (for NTP, updates, cloud APIs): + - Action: `Pass` + - Source: `VLAN_IOT subnet` + - Destination: `any` + - Protocol: `TCP/UDP` + - Click **Save** + +2. **Block VLAN_IOT → LAN_SECURE**: + - Action: `Block` + - Source: `VLAN_IOT subnet` + - Destination: `LAN_SECURE subnet` + - Click **Save** + +3. **Block VLAN_IOT → VLAN_AIWORKLOAD** (optional): + - Action: `Block` + - Source: `VLAN_IOT subnet` + - Destination: `VLAN_AIWORKLOAD subnet` + - Click **Save** + +### Step 5: Configure Port Assignments (If Hardware Supports) + +If your switch/NIC supports physical VLAN tagging: + +Navigate: **Interfaces → Physical Ports** (varies by pfSense version) + +Example configuration: +- **Port 1**: LAN_SECURE (VLAN 1, untagged) +- **Port 2**: VLAN_AIWORKLOAD (VLAN 2, tagged) +- **Port 3**: VLAN_IOT (VLAN 3, tagged) +- **Port 4**: WAN + +*This step depends on your hardware. If using a managed switch, configure VLAN tagging there instead.* + +## Network Access Matrix + +Shows which VLANs can reach which destinations: + +``` +FROM TO_LAN_SECURE TO_AIWORKLOAD TO_IOT TO_WAN +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +LAN_SECURE ✓ (same) ✗ BLOCK ✗ BLOCK ✓ +VLAN_AIWORKLOAD ✗ BLOCK ✓ (same) ✗ BLOCK ✓ +VLAN_IOT ✗ BLOCK ✗ BLOCK ✓ (same) ✓ +``` + +## Device Assignment + +Assign devices to VLANs via: + +1. **DHCP reservations** (Recommended): + - Navigate: **Services → DHCP Server** + - Tab: Desired VLAN + - Scroll to **DHCP Static Mappings** + - Add device MAC → static IP in that VLAN + - Example: Openclaw server → `172.27.2.50` (VLAN_AIWORKLOAD) + +2. **Manual static configuration**: + - Configure device IP in the target VLAN subnet + - Set gateway to VLAN gateway (172.27.2.1, 172.27.3.1, etc.) + +3. **Switch port assignment** (if hardware supports): + - Assign physical switch ports to VLANs + - Devices connected to those ports get VLAN membership + +## DNS Configuration + +Navigate: **Services → DNS Resolver** + +1. **Enable DNS Resolver**: ✓ Checked +2. **Network Interfaces**: Select all interfaces (LAN, VLAN_AIWORKLOAD, VLAN_IOT) +3. **Forward Mode**: Check if needed for external DNS +4. **Access Lists**: + - Ensure all VLANs can query DNS on their gateways + +This allows devices in each VLAN to resolve hostnames locally. + +## Backup & Recovery + +### Automated Backup (Recommended) + +Use the included backup utility script for automated, versioned backups: + +```bash +cd pfsense.home.arpa +./scripts/backup-pfsense-config.sh +``` + +This script: +- Connects to pfSense via SSH (using your public key) +- Downloads the current configuration XML +- Validates it's a valid pfSense config +- Stores it in `backups/` with a timestamped filename +- Automatically commits to git with configuration details + +**Schedule automated daily backups:** +```bash +# Add to crontab (backups every day at 2 AM) +0 2 * * * cd /path/to/appa-net/pfsense.home.arpa && ./scripts/backup-pfsense-config.sh +``` + +For more details, see: [scripts/README.md](scripts/README.md) + +### Manual Backup + +If you prefer manual backups or SSH isn't available: + +1. Navigate: **Diagnostics → Backup & Restore** +2. Click **Download configuration as XML** +3. Save to: `pfsense.home.arpa/backups/pfsense-config-YYYY-MM-DD.xml` +4. Commit manually: + ```bash + git add backups/pfsense-config-2026-04-22.xml + git commit -m "pfSense: Backup configuration (manual)" + git push + ``` + +### Restoring Configuration + +1. Navigate: **Diagnostics → Backup & Restore** +2. Click **Choose File** and select XML backup +3. Click **Restore Configuration** +4. Reboot when prompted + +## Maintenance Tasks + +- **Monthly**: Export and backup pfSense configuration +- **Quarterly**: Review firewall rules and DHCP assignments +- **As needed**: Adjust rules based on new devices or requirements + +## Troubleshooting + +### VLANs not working: +- Verify VLAN tags are correct in Interfaces → VLANs +- Ensure virtual interfaces are enabled (Interfaces → Assignments) +- Check physical switch VLAN configuration if using managed switch + +### Devices can't get DHCP: +- Verify DHCP is enabled for the VLAN +- Check DHCP range is correct +- Inspect DHCP leases: **Status → DHCP Leases** + +### Can't ping between VLANs (expected): +- Verify firewall rules are allowing or blocking as desired +- Check rule order (first match wins) +- Use **Diagnostics → Packet Capture** to debug + +## References + +- [pfSense VLAN Documentation](https://docs.netgate.com/pfsense/en/latest/vlan/index.html) +- [pfSense Firewall Rules](https://docs.netgate.com/pfsense/en/latest/firewall/index.html) +- RFC 2644 — VLAN tagging +- RFC 5735 — Special Use IPv4 Addresses + +--- + +**Last Updated:** 2026-04-22 +**Configuration Version:** 1.0 diff --git a/pfsense.home.arpa/VLAN-CONFIG.md b/pfsense.home.arpa/VLAN-CONFIG.md new file mode 100644 index 0000000..16e952f --- /dev/null +++ b/pfsense.home.arpa/VLAN-CONFIG.md @@ -0,0 +1,173 @@ +# VLAN Configuration Reference + +Network segmentation configuration for pfsense.home.arpa router. + +## VLAN Definitions + +```yaml +vlans: + lan_secure: + vlan_id: 1 + description: "Main trusted network" + subnet: "172.27.0.0/24" + gateway: "172.27.0.1" + dhcp_start: "172.27.0.100" + dhcp_end: "172.27.0.200" + purpose: "Primary network for personal/trusted devices" + isolation: "Gateway to WAN, can access VLANs as configured" + firewall_default: "allow_outbound" + + vlan_aiworkload: + vlan_id: 2 + description: "AI/ML Workload (Dangerous/OpenClaw)" + subnet: "172.27.2.0/24" + gateway: "172.27.2.1" + dhcp_start: "172.27.2.100" + dhcp_end: "172.27.2.200" + purpose: "Isolated workload for AI/ML experiments, sandbox for untrusted code" + isolation: "Blocked from LAN_SECURE, can access WAN" + firewall_default: "deny_incoming, allow_outbound_to_wan" + access_from_secure: "none" # LAN_SECURE cannot reach this VLAN + + vlan_iot: + vlan_id: 3 + description: "IoT Devices" + subnet: "172.27.3.0/24" + gateway: "172.27.3.1" + dhcp_start: "172.27.3.100" + dhcp_end: "172.27.3.200" + purpose: "Smart home devices (cameras, sensors, thermostats, etc.)" + isolation: "Blocked from LAN_SECURE, can access WAN for updates/APIs" + firewall_default: "deny_incoming, allow_outbound_to_wan" + access_from_secure: "none" # LAN_SECURE cannot reach this VLAN +``` + +## Firewall Rule Summary + +### From LAN_SECURE (172.27.0.0/24) +- ✓ To Internet (WAN) +- ✗ To VLAN_AIWORKLOAD (blocked) +- ✗ To VLAN_IOT (blocked) +- ✓ Internal (same subnet) + +### From VLAN_AIWORKLOAD (172.27.2.0/24) +- ✓ To Internet (WAN) +- ✗ To LAN_SECURE (blocked) +- ✗ To VLAN_IOT (blocked) +- ✓ Internal (same subnet) + +### From VLAN_IOT (172.27.3.0/24) +- ✓ To Internet (WAN) +- ✗ To LAN_SECURE (blocked) +- ✗ To VLAN_AIWORKLOAD (blocked) +- ✓ Internal (same subnet) + +## DHCP Configuration + +Each VLAN has its own DHCP server: + +``` +VLAN_SECURE: 172.27.0.100 - 172.27.0.200 (Gateway: 172.27.0.1) +VLAN_AIWORKLOAD: 172.27.2.100 - 172.27.2.200 (Gateway: 172.27.2.1) +VLAN_IOT: 172.27.3.100 - 172.27.3.200 (Gateway: 172.27.3.1) +``` + +**DNS Server** (for all VLANs): 172.27.0.1 (pfSense resolver) + +## Physical Switch Configuration (If Applicable) + +If using a managed switch, configure VLAN tagging: + +``` +Port 1 (LAN_SECURE): + - Mode: Access + - VLAN: 1 (untagged, native) + - Devices: Personal computers, laptops + +Port 2 (VLAN_AIWORKLOAD): + - Mode: Access + - VLAN: 2 (untagged) + - Devices: Openclaw server, GPU workstations + - OR: Trunk (if pfSense applies tags) + +Port 3 (VLAN_IOT): + - Mode: Access + - VLAN: 3 (untagged) + - Devices: Smart home devices, cameras, sensors + - OR: Trunk (if pfSense applies tags) + +Port 4 (Uplink to pfSense): + - Mode: Trunk + - VLANs: 1, 2, 3 + - Tagged: 2, 3 (VLAN 1 typically untagged on trunk) +``` + +## Device Assignments + +Assign devices to VLANs using DHCP static mappings or by setting up switch port VLANs. + +### Planned Devices + +**VLAN_SECURE (LAN_SECURE):** +- [ ] Your personal laptop/desktop +- [ ] Network printer (if any) +- [ ] Home automation controller (if trusted) + +**VLAN_AIWORKLOAD (VLAN_AIWORKLOAD):** +- [ ] Openclaw server / AI workstation +- [ ] GPU compute server +- [ ] Experimental machine learning environment + +**VLAN_IOT (VLAN_IOT):** +- [ ] Smart home cameras +- [ ] Temperature/humidity sensors +- [ ] Smart thermostat +- [ ] IoT gateway (if not trusted) +- [ ] Smart switches/outlets + +## Implementation Checklist + +- [ ] Create VLAN 2 (VLAN_AIWORKLOAD) on parent interface +- [ ] Create VLAN 3 (VLAN_IOT) on parent interface +- [ ] Apply VLAN changes +- [ ] Create virtual interface for VLAN_AIWORKLOAD (OPT1) + - [ ] Set IP: 172.27.2.1/24 + - [ ] Enable interface + - [ ] Apply changes +- [ ] Create virtual interface for VLAN_IOT (OPT2) + - [ ] Set IP: 172.27.3.1/24 + - [ ] Enable interface + - [ ] Apply changes +- [ ] Configure DHCP for VLAN_AIWORKLOAD +- [ ] Configure DHCP for VLAN_IOT +- [ ] Configure firewall rules for LAN_SECURE +- [ ] Configure firewall rules for VLAN_AIWORKLOAD +- [ ] Configure firewall rules for VLAN_IOT +- [ ] Test DHCP on each VLAN +- [ ] Test inter-VLAN isolation +- [ ] Backup pfSense configuration +- [ ] Commit configuration to git + +## Notes & Decisions + +### Why These Subnets? +- **172.27.x.x/16**: Private RFC 1918 range (172.16.0.0 - 172.31.255.255) +- Each VLAN gets a /24 subnet (254 usable IPs per VLAN) +- Easy to route and remember (VLAN ID = third octet) + +### Why This Isolation? +- **LAN_SECURE** ↔ **VLAN_AIWORKLOAD**: Complete isolation prevents compromised AI workload from reaching trusted devices +- **LAN_SECURE** ↔ **VLAN_IOT**: IoT devices have broader vulnerabilities; isolation prevents lateral movement +- **VLAN_AIWORKLOAD** ↔ **VLAN_IOT**: Reduces attack surface between untrusted zones +- All VLANs → WAN: Allows devices to update, phone home, or reach cloud services + +### Future Enhancements +- Add guest VLAN for visitors +- Configure VPN access to VLAN_SECURE only +- Implement QoS rules per VLAN +- Add Intrusion Detection (Suricata) on VLAN boundaries +- Monitor inter-VLAN traffic in firewall logs + +--- + +**Last Updated:** 2026-04-22 diff --git a/pfsense.home.arpa/VLAN-QUICKSTART.md b/pfsense.home.arpa/VLAN-QUICKSTART.md new file mode 100644 index 0000000..5f013d9 --- /dev/null +++ b/pfsense.home.arpa/VLAN-QUICKSTART.md @@ -0,0 +1,291 @@ +# VLAN Implementation Quickstart + +Step-by-step checklist for configuring VLANs on pfSense. Use this guide to implement your 3-VLAN network. + +## Pre-Implementation + +Before you start, gather this information: + +- [ ] pfSense WebUI URL (usually `https://192.168.1.1` or similar) +- [ ] Admin credentials for pfSense +- [ ] Your WAN/LAN interface names (check: **Interfaces → Assignments**) +- [ ] Backup your current pfSense config (download before making changes) +- [ ] Physical switch info (if you have one) — check if it supports VLAN tagging + +## Phase 1: Create VLANs (5 minutes) + +1. **Log into pfSense WebUI** + - [ ] Open `https://[pfSense-IP]` + - [ ] Enter admin credentials + +2. **Navigate to VLAN Creation** + - [ ] Go: **Interfaces → VLANs** + - [ ] Click **Display Advanced** + +3. **Create VLAN_AIWORKLOAD** + - [ ] Click **+ Add** + - [ ] Parent Interface: `em0` (or your LAN NIC name) + - [ ] VLAN Tag: `2` + - [ ] VLAN Priority: `0` + - [ ] Description: `VLAN_AIWORKLOAD` + - [ ] Click **Save** + +4. **Create VLAN_IOT** + - [ ] Click **+ Add** + - [ ] Parent Interface: `em0` + - [ ] VLAN Tag: `3` + - [ ] VLAN Priority: `0` + - [ ] Description: `VLAN_IOT` + - [ ] Click **Save** + +5. **Apply Changes** + - [ ] Click **Apply Changes** button + - [ ] Wait for reboot/apply to complete + +## Phase 2: Assign Virtual Interfaces (5 minutes) + +1. **Navigate to Assignments** + - [ ] Go: **Interfaces → Assignments** + +2. **Note down the OPT interfaces created** + - [ ] You should see two new entries: e.g., `em0.2` and `em0.3` + - [ ] These will be assigned as `OPT1` and `OPT2` (or similar) + +3. **Click the OPT1 link** (VLAN_AIWORKLOAD) + - [ ] Description: `VLAN_AIWORKLOAD` + - [ ] IPv4 Configuration Type: `Static IPv4` + - [ ] IPv4 Address: `172.27.2.1` + - [ ] IPv4 Subnet Mask: `255.255.255.0` + - [ ] IPv6 Configuration Type: `None` + - [ ] **Enable Interface**: ✓ Check this box + - [ ] Scroll down and click **Save** + +4. **Repeat for OPT2** (VLAN_IOT) + - [ ] Description: `VLAN_IOT` + - [ ] IPv4 Configuration Type: `Static IPv4` + - [ ] IPv4 Address: `172.27.3.1` + - [ ] IPv4 Subnet Mask: `255.255.255.0` + - [ ] **Enable Interface**: ✓ Check this box + - [ ] Scroll down and click **Save** + +5. **Apply Changes** + - [ ] Click **Apply Changes** button + +## Phase 3: Configure DHCP (10 minutes) + +1. **Navigate to DHCP Server** + - [ ] Go: **Services → DHCP Server** + +2. **Configure VLAN_AIWORKLOAD DHCP** + - [ ] Click **VLAN_AIWORKLOAD** tab + - [ ] **Enable DHCP server on VLAN_AIWORKLOAD interface**: ✓ Check + - [ ] **Range Start**: `172.27.2.100` + - [ ] **Range End**: `172.27.2.200` + - [ ] Scroll down to **Servers** section + - [ ] **DNS 1**: `172.27.0.1` (pfSense) + - [ ] **DNS 2**: `8.8.8.8` (optional backup) + - [ ] **Gateway**: Should auto-populate as `172.27.2.1` + - [ ] Scroll down and click **Save** + +3. **Configure VLAN_IOT DHCP** + - [ ] Click **VLAN_IOT** tab + - [ ] **Enable DHCP server on VLAN_IOT interface**: ✓ Check + - [ ] **Range Start**: `172.27.3.100` + - [ ] **Range End**: `172.27.3.200` + - [ ] Scroll down to **Servers** section + - [ ] **DNS 1**: `172.27.0.1` + - [ ] **DNS 2**: `8.8.8.8` + - [ ] **Gateway**: Should auto-populate as `172.27.3.1` + - [ ] Scroll down and click **Save** + +4. **Verify LAN DHCP** + - [ ] Click **LAN** tab + - [ ] Confirm **Enable DHCP server on LAN interface** is ✓ checked + - [ ] Verify gateway is `172.27.0.1` + - [ ] Click **Save** + +5. **Apply Changes** + - [ ] Click **Apply Changes** button + +## Phase 4: Configure Firewall Rules (15 minutes) + +### LAN → VLAN Rules + +1. **Go to LAN rules** + - [ ] **Firewall → Rules → LAN** + +2. **Add rule: Block LAN → VLAN_AIWORKLOAD** + - [ ] Click **+ Add** (at bottom) + - [ ] Action: `Block` + - [ ] Interface: `LAN` + - [ ] Direction: `in` + - [ ] Address Family: `IPv4` + - [ ] Protocol: `any` + - [ ] Source: `LAN subnet` (or specify `172.27.0.0/24`) + - [ ] Destination: `VLAN_AIWORKLOAD subnet` (specify `172.27.2.0/24`) + - [ ] Description: `Block LAN → VLAN_AIWORKLOAD` + - [ ] Click **Save** + +3. **Add rule: Block LAN → VLAN_IOT** + - [ ] Click **+ Add** + - [ ] Action: `Block` + - [ ] Interface: `LAN` + - [ ] Source: `172.27.0.0/24` + - [ ] Destination: `172.27.3.0/24` + - [ ] Description: `Block LAN → VLAN_IOT` + - [ ] Click **Save** + +### VLAN_AIWORKLOAD Rules + +1. **Go to VLAN_AIWORKLOAD rules** + - [ ] **Firewall → Rules → VLAN_AIWORKLOAD** (or OPT1) + +2. **Add rule: Block VLAN_AIWORKLOAD → LAN** + - [ ] Click **+ Add** + - [ ] Action: `Block` + - [ ] Interface: `VLAN_AIWORKLOAD` + - [ ] Source: `VLAN_AIWORKLOAD subnet` (specify `172.27.2.0/24`) + - [ ] Destination: `LAN subnet` (specify `172.27.0.0/24`) + - [ ] Description: `Block VLAN_AIWORKLOAD → LAN` + - [ ] Click **Save** + +3. **Add rule: Allow VLAN_AIWORKLOAD → WAN** + - [ ] Click **+ Add** + - [ ] Action: `Pass` + - [ ] Interface: `VLAN_AIWORKLOAD` + - [ ] Source: `VLAN_AIWORKLOAD subnet` (specify `172.27.2.0/24`) + - [ ] Destination: `any` + - [ ] Protocol: `any` + - [ ] Description: `Allow VLAN_AIWORKLOAD → Internet` + - [ ] Click **Save** + +### VLAN_IOT Rules + +1. **Go to VLAN_IOT rules** + - [ ] **Firewall → Rules → VLAN_IOT** (or OPT2) + +2. **Add rule: Block VLAN_IOT → LAN** + - [ ] Click **+ Add** + - [ ] Action: `Block` + - [ ] Interface: `VLAN_IOT` + - [ ] Source: `VLAN_IOT subnet` (specify `172.27.3.0/24`) + - [ ] Destination: `LAN subnet` (specify `172.27.0.0/24`) + - [ ] Description: `Block VLAN_IOT → LAN` + - [ ] Click **Save** + +3. **Add rule: Block VLAN_IOT → VLAN_AIWORKLOAD** + - [ ] Click **+ Add** + - [ ] Action: `Block` + - [ ] Source: `172.27.3.0/24` + - [ ] Destination: `172.27.2.0/24` + - [ ] Description: `Block VLAN_IOT → VLAN_AIWORKLOAD` + - [ ] Click **Save** + +4. **Add rule: Allow VLAN_IOT → WAN** + - [ ] Click **+ Add** + - [ ] Action: `Pass` + - [ ] Source: `VLAN_IOT subnet` (specify `172.27.3.0/24`) + - [ ] Destination: `any` + - [ ] Protocol: `any` + - [ ] Description: `Allow VLAN_IOT → Internet` + - [ ] Click **Save** + +### Apply Firewall Changes + +- [ ] Click **Apply Changes** button (usually at top of rules) + +## Phase 5: Testing (10 minutes) + +### Test DHCP + +1. **Connect a test device to VLAN_AIWORKLOAD** + - [ ] Assign a device to this VLAN (via switch port or manually) + - [ ] Check if device gets IP in range 172.27.2.100-200 + - [ ] Verify gateway shows 172.27.2.1 + - [ ] Test ping to gateway: `ping 172.27.2.1` ✓ + +2. **Connect a test device to VLAN_IOT** + - [ ] Assign a device to this VLAN + - [ ] Check if device gets IP in range 172.27.3.100-200 + - [ ] Verify gateway shows 172.27.3.1 + - [ ] Test ping to gateway: `ping 172.27.3.1` ✓ + +### Test Inter-VLAN Isolation + +1. **Test VLAN_AIWORKLOAD cannot reach LAN** + - [ ] From device on VLAN_AIWORKLOAD (172.27.2.x) + - [ ] Try ping to LAN device (172.27.0.x) + - [ ] Should timeout/fail ✗ (expected) + +2. **Test VLAN_IOT cannot reach LAN** + - [ ] From device on VLAN_IOT (172.27.3.x) + - [ ] Try ping to LAN device (172.27.0.x) + - [ ] Should timeout/fail ✗ (expected) + +3. **Test LAN cannot reach VLANs** + - [ ] From LAN device (172.27.0.x) + - [ ] Try ping to VLAN_AIWORKLOAD device (172.27.2.x) + - [ ] Should timeout/fail ✗ (expected) + +### Test Internet Access + +1. **Test VLAN_AIWORKLOAD → Internet** + - [ ] From device on VLAN_AIWORKLOAD + - [ ] Test DNS: `nslookup google.com` ✓ + - [ ] Test internet: `ping 8.8.8.8` ✓ + +2. **Test VLAN_IOT → Internet** + - [ ] From device on VLAN_IOT + - [ ] Test DNS: `nslookup google.com` ✓ + - [ ] Test internet: `ping 8.8.8.8` ✓ + +## Phase 6: Backup & Documentation (5 minutes) + +1. **Backup pfSense Configuration** + - [ ] Go: **Diagnostics → Backup & Restore** + - [ ] Click **Download configuration as XML** + - [ ] Save as: `pfsense-config-vlan-setup-2026-04-22.xml` + +2. **Commit to Git** + ```bash + cd /Users/kenjim/workspace/src/personal/appa-net + git add pfsense.home.arpa/ + git commit -m "pfSense: Initial VLAN configuration (VLAN_AIWORKLOAD, VLAN_IOT)" + git push + ``` + - [ ] Commit completed + +3. **Document Completion** + - [ ] Update this file with completion date + - [ ] Note any deviations from plan + - [ ] Record interface names if different from expected + +## Troubleshooting + +| Issue | Solution | +|-------|----------| +| Device not getting DHCP | Check DHCP is enabled for that VLAN in **Services → DHCP Server** | +| Can't ping gateway | Verify virtual interface is enabled (**Interfaces → Assignments**) | +| Can't reach internet | Check WAN allow rules in firewall | +| Still can reach between VLANs | Check firewall rules order (first match wins); rules may be in wrong order | +| Switch not forwarding VLAN traffic | Verify trunk port on switch is tagged for all VLANs | + +## Post-Implementation + +Once everything is working: + +1. **Assign your devices** to VLANs via DHCP static mappings + - See [VLAN-CONFIG.md](VLAN-CONFIG.md) for device list + +2. **Monitor firewall logs** for unexpected traffic + - Go: **Status → System Logs → Firewall** + +3. **Update your documentation** as you add more devices + +4. **Schedule regular backups** + - Monthly: Export pfSense config to `backups/pfsense-config-YYYY-MM-DD.xml` + +--- + +**Estimated Total Time**: 45 minutes +**Last Updated**: 2026-04-22 diff --git a/pfsense.home.arpa/VLAN-TOPOLOGY.md b/pfsense.home.arpa/VLAN-TOPOLOGY.md new file mode 100644 index 0000000..640cc05 --- /dev/null +++ b/pfsense.home.arpa/VLAN-TOPOLOGY.md @@ -0,0 +1,262 @@ +# VLAN Network Topology + +Visual representation of your segmented home network architecture. + +## High-Level Topology + +``` + ┌─────────────────┐ + │ Internet │ + │ (WAN) │ + └────────┬────────┘ + │ + ┌──────────┴──────────┐ + │ │ + ┌────▼─────────────────────▼────┐ + │ pfSense Router │ + │ (172.27.0.1) │ + │ │ + │ • DHCP Server │ + │ • DNS Resolver │ + │ • Firewall │ + │ • VLAN Gateway │ + └────┬────────┬────────┬────────┘ + │ │ │ + ┌───────────┘ │ └──────────┐ + │ │ │ + ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ + │ VLAN 1 │ │ VLAN 2 │ │ VLAN 3 │ + │ LAN_SECURE │ │ AIWORKLOAD │ │ IOT │ + │ 172.27.0.0 │ │ 172.27.2.0 │ │ 172.27.3.0 │ + └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ + │ │ │ + │ │ │ + ┌──────▼────────┐ ┌──────▼────────┐ ┌──────▼────────┐ + │ │ │ │ │ │ + │ Trusted Devices│ │ Openclaw │ │ IoT Devices │ + │ │ │ GPU Workload │ │ │ + │ • Laptop │ │ │ │ • Cameras │ + │ • Desktop │ │ (Sandbox/ │ │ • Sensors │ + │ • Phone │ │ Experiment) │ │ • Thermostat │ + │ │ │ │ │ • Smart Outlets│ + └────────────────┘ └────────────────┘ └────────────────┘ +``` + +## Detailed Dataflow + +### Device to Internet (All VLANs) +``` +Device (VLAN X) + ↓ +Gateway (172.27.X.1) + ↓ +pfSense Firewall + ↓ +WAN Interface + ↓ +Internet Router/Modem + ↓ +Internet ✓ +``` + +### Trusted to Untrusted (Blocked) +``` +LAN_SECURE Device (172.27.0.100) + ↓ +Request to VLAN_AIWORKLOAD (172.27.2.X) + ↓ +pfSense Firewall Rule: BLOCK + ↓ +X Connection Refused +``` + +## Firewall Rule Chain + +``` +┌─────────────────────────────────────────────────────┐ +│ Inbound Packet on Interface (e.g., LAN_SECURE) │ +└────────────────────┬────────────────────────────────┘ + │ + ▼ + ┌────────────────────────┐ + │ Source IP in subnet? │ + │ (172.27.0.0/24) │ + └────────┬───────┬────────┘ + │ │ + YES│ │NO → Block (rule 1) + │ │ + ▼ │ + ┌────────────────────────┐ + │ Destination Subnet? │ + └────────┬───────┬────────┘ + │ │ + 172.27.0.0/24 172.27.2.0/24 172.27.3.0/24 + │ │ │ + ▼ ▼ ▼ + Same VLAN ALLOW (rule 2) BLOCK (rule 3) + │ │ │ + ▼ ▼ ▼ + ✓ PASS ✓ PASS ✗ BLOCK +``` + +## Port Connectivity (Example with 4-Port Switch) + +``` +┌──────────────────────────────────────────┐ +│ Managed Network Switch │ +│ (or pfSense internal if no switch) │ +├──────────────────────────────────────────┤ +│ │ +│ Port 1 (Access, VLAN 1) │ +│ ├─ Trusted Device 1 │ +│ └─ Trusted Device 2 │ +│ │ +│ Port 2 (Access, VLAN 2) │ +│ ├─ Openclaw Server │ +│ └─ GPU Workstation │ +│ │ +│ Port 3 (Access, VLAN 3) │ +│ ├─ Smart Camera 1 │ +│ ├─ Smart Camera 2 │ +│ ├─ IoT Sensor │ +│ └─ Smart Thermostat │ +│ │ +│ Port 4 (Trunk - All VLANs Tagged) │ +│ └─ pfSense Router │ +│ (Receives VLAN-tagged frames) │ +│ │ +└──────────────────────────────────────────┘ +``` + +## Traffic Examples + +### ✓ Allowed Traffic Paths + +``` +1. Trusted Device → Internet + 172.27.0.100 → 8.8.8.8:53 + Gateway: 172.27.0.1 → pfSense → WAN → Internet ✓ + +2. AI Workload → Internet + 172.27.2.50 → updates.example.com:443 + Gateway: 172.27.2.1 → pfSense → WAN → Internet ✓ + +3. IoT Device → NTP Server + 172.27.3.102 → pool.ntp.org:123 + Gateway: 172.27.3.1 → pfSense → WAN → Internet ✓ + +4. Trusted Device → Trusted Device (same VLAN) + 172.27.0.100 → 172.27.0.150 (same broadcast domain) ✓ +``` + +### ✗ Blocked Traffic Paths + +``` +1. Trusted → AI Workload + 172.27.0.100 → 172.27.2.50 + Firewall Rule: BLOCK ✗ + (Prevents lateral movement if AI workload is compromised) + +2. Trusted → IoT Device + 172.27.0.100 → 172.27.3.100 + Firewall Rule: BLOCK ✗ + (Prevents IoT compromise affecting trusted devices) + +3. AI Workload → Trusted Device (reverse) + 172.27.2.50 → 172.27.0.100 + Firewall Rule: BLOCK ✗ + (Prevents compromised workload from scanning trusted network) + +4. IoT → AI Workload + 172.27.3.102 → 172.27.2.50 + Firewall Rule: BLOCK ✗ + (Reduces attack surface between untrusted zones) +``` + +## VLAN 802.1Q Tagging (Switch-Level) + +If using a managed switch with VLAN support: + +``` +Frame from pfSense Port 4 (Trunk): + +┌─────────────────────────────────────────────────────┐ +│ Ethernet Header │ +├─────────────────────────────────────────────────────┤ +│ Destination MAC | Source MAC | 802.1Q Tag | Type │ +├─────────────────────────────────────────────────────┤ +│ AA:BB:CC:DD:EE | 11:22:33:44:55:66 | VLAN: 2 | IPv4│ +├─────────────────────────────────────────────────────┤ +│ IPv4 Payload (IP Header + Data) │ +└─────────────────────────────────────────────────────┘ + +When frame arrives at Port 2 (Access, VLAN 2): + ├─ Switch removes 802.1Q tag + ├─ Delivers untagged frame to device + └─ Device sees: AA:BB:CC:DD:EE → 11:22:33:44:55:66 [IPv4 Data] +``` + +## Isolation Guarantees + +``` +┌─────────────────────────────────────────────────────┐ +│ VLAN Isolation Mechanisms │ +├─────────────────────────────────────────────────────┤ +│ │ +│ 1. Layer 2 (Link Layer) │ +│ └─ VLANs have separate broadcast domains │ +│ └─ ARP packets don't cross VLAN boundaries │ +│ └─ Broadcast storms are contained │ +│ │ +│ 2. Layer 3 (Network Layer) │ +│ └─ Different subnets per VLAN │ +│ └─ Devices can't directly route between VLANs│ +│ └─ Must go through Layer 3 gateway (pfSense) │ +│ │ +│ 3. Firewall Rules (pfSense) │ +│ └─ Explicit deny between VLANs (unless allowed) │ +│ └─ Stateful inspection prevents spoofing │ +│ └─ Rate limiting and IDS possible │ +│ │ +│ 4. Switch-Level Isolation (if applicable) │ +│ └─ 802.1Q VLAN tags ensure switch-level routing │ +│ └─ Malformed frames or tag injection blocked │ +│ │ +└─────────────────────────────────────────────────────┘ +``` + +## Routing Summary + +``` +Routing Table on pfSense: + +Destination Next Hop Interface Metric +──────────────────────────────────────────────────────────── +0.0.0.0/0 192.168.1.1 WAN 1 +172.27.0.0/24 direct LAN (VLAN 1) 0 +172.27.2.0/24 direct OPT1 (VLAN 2) 0 +172.27.3.0/24 direct OPT2 (VLAN 3) 0 +``` + +### How Routing Works + +1. **Packet from LAN_SECURE to VLAN_AIWORKLOAD:** + - Source: 172.27.0.100, Dest: 172.27.2.50 + - pfSense checks routing table + - Destination 172.27.2.0/24 → exists on OPT1 + - pfSense checks firewall rule for LAN → OPT1 + - Rule says: BLOCK + - Packet is dropped ✗ + +2. **Packet from VLAN_AIWORKLOAD to Internet:** + - Source: 172.27.2.50, Dest: 8.8.8.8 + - pfSense checks routing table + - Destination 8.8.8.8 → matches 0.0.0.0/0 (default route) + - Next hop: WAN gateway (192.168.1.1) + - pfSense checks firewall rule for OPT1 → WAN + - Rule says: ALLOW + - Packet forwarded to WAN ✓ + +--- + +**Last Updated:** 2026-04-22 diff --git a/pfsense.home.arpa/backups/.gitkeep b/pfsense.home.arpa/backups/.gitkeep new file mode 100644 index 0000000..af153d4 --- /dev/null +++ b/pfsense.home.arpa/backups/.gitkeep @@ -0,0 +1,11 @@ +# Backups Directory + +pfSense configuration backups are stored here with timestamped filenames. + +**DO NOT delete backup files without understanding the implications.** + +Format: `pfsense-config-YYYY-MM-DD_HHMMSS.xml` + +All backup files are committed to git, so previous versions can be restored from git history if needed. + +For backup automation, see: [scripts/README.md](../scripts/README.md) diff --git a/pfsense.home.arpa/scripts/README.md b/pfsense.home.arpa/scripts/README.md new file mode 100644 index 0000000..88e7f73 --- /dev/null +++ b/pfsense.home.arpa/scripts/README.md @@ -0,0 +1,226 @@ +# pfSense Backup Scripts + +Automation utilities for backing up and managing pfSense configuration. + +## Scripts + +### `backup-pfsense-config.sh` + +Automated backup utility that: +- Connects to your pfSense router via SSH (using public key authentication) +- Downloads the current configuration XML +- Validates the backup is a valid pfSense config +- Stores it in `backups/` folder with a timestamped filename +- Automatically commits to git with a detailed message + +#### Usage + +**Basic usage (default host):** +```bash +cd pfsense.home.arpa +./scripts/backup-pfsense-config.sh +``` + +**Specify custom host:** +```bash +./scripts/backup-pfsense-config.sh 192.168.1.1 +./scripts/backup-pfsense-config.sh pfsense.home.arpa +``` + +**Download without auto-committing to git:** +```bash +./scripts/backup-pfsense-config.sh --no-commit +# or +./scripts/backup-pfsense-config.sh -n +``` + +**Test SSH connectivity (dry-run):** +```bash +./scripts/backup-pfsense-config.sh --dry-run +``` + +**Show help:** +```bash +./scripts/backup-pfsense-config.sh --help +# or +./scripts/backup-pfsense-config.sh -h +``` + +#### Prerequisites + +1. **SSH Public Key Authentication** + - Your public key must be installed on pfSense + - Run on pfSense: `cat ~/.ssh/authorized_keys` to verify + - If not installed, manually copy your key: `ssh-copy-id root@pfsense` + +2. **SSH Host Configuration** (recommended) + - Add to your `~/.ssh/config`: + ``` + Host pfsense + HostName 172.27.0.1 # or your pfSense IP + User root + IdentityFile ~/.ssh/id_rsa # or your key path + ``` + - This allows `ssh pfsense` to work directly + +3. **Git Repository** + - Must be run from within a git repository + - The script auto-commits backups to git + +4. **Dependencies** + - `bash` (4.0+) + - `ssh` and `scp` + - `git` + - `du`, `shasum`, `grep` (standard Unix utilities) + +#### Features + +- ✅ **Automatic validation** — Confirms backup is valid XML and contains pfSense markers +- ✅ **Timestamped files** — Format: `pfsense-config-YYYY-MM-DD_HHMMSS.xml` +- ✅ **Rich git commits** — Includes VLAN count, firewall rule count, SHA256 hash +- ✅ **Error handling** — Clear error messages and troubleshooting tips +- ✅ **Dry-run mode** — Test SSH connectivity without downloading +- ✅ **Human-readable output** — Color-coded info/warning/error messages +- ✅ **Configurable** — Via environment variables or command-line arguments + +#### Example Output + +``` +╔════════════════════════════════════════════════════════════════╗ +║ pfSense Configuration Backup Utility ║ +╚════════════════════════════════════════════════════════════════╝ + +[INFO] Configuration: + Host: pfsense + User: root + Remote path: /conf/config.xml + Backup dir: ./backups + Auto-commit: true + +[INFO] Checking prerequisites... +[✓] SSH is available +[✓] Git is available +[✓] Backup directory exists +[✓] Git repository found + +[INFO] Testing SSH connection to pfsense... +[✓] SSH connection to pfsense successful + +[INFO] Fetching pfSense configuration from pfsense... +[✓] Configuration downloaded to ./backups/pfsense-config-2026-04-22_143022.xml +[INFO] Backup size: 68K + +[INFO] Validating backup file... +[✓] Backup file is valid XML with pfSense markers + +[INFO] Committing backup to git repository... +[✓] Added backup to git staging area +[✓] Configuration committed to git + +════════════════════════════════════════════════════════════════ +[✓] pfSense configuration backup completed successfully! +════════════════════════════════════════════════════════════════ + +Backup Details: + Location: ./backups/pfsense-config-2026-04-22_143022.xml + Size: 68K + Timestamp: 2026-04-22_143022 + From: root@pfsense:/conf/config.xml + +Next Steps: + 1. Review the changes: git show HEAD + 2. Push to remote: git push origin main + 3. Schedule automated backups in crontab +``` + +#### Scheduling Automated Backups + +To backup your pfSense config automatically every day at 2 AM: + +1. **Edit your crontab:** + ```bash + crontab -e + ``` + +2. **Add this line:** + ```cron + 0 2 * * * cd /Users/kenjim/workspace/src/personal/appa-net/pfsense.home.arpa && ./scripts/backup-pfsense-config.sh + ``` + +3. **Verify the entry:** + ```bash + crontab -l | grep backup-pfsense + ``` + +Now your config will be backed up automatically every day! + +#### Troubleshooting + +| Problem | Solution | +|---------|----------| +| `Permission denied (publickey)` | Install public key: `ssh-copy-id root@pfsense` | +| `Connection refused` | Check pfSense IP/hostname is correct | +| `No such file or directory: /conf/config.xml` | Not running on pfSense; check SSH host | +| `XML validation failed` | Config may be corrupted; try manual backup via WebUI | +| Git commit fails | Ensure you're in the git repository root | + +#### Environment Variables + +Control script behavior with environment variables: + +```bash +# Use different SSH user +PFSENSE_USER=admin ./scripts/backup-pfsense-config.sh + +# Disable auto-commit +AUTO_COMMIT=false ./scripts/backup-pfsense-config.sh + +# Combine both +PFSENSE_USER=admin AUTO_COMMIT=false ./scripts/backup-pfsense-config.sh pfsense.home.arpa +``` + +## Backup Files Location + +All backups are stored in the `backups/` directory: + +``` +backups/ +├── pfsense-config-2026-04-22_143022.xml +├── pfsense-config-2026-04-21_023001.xml +└── pfsense-config-2026-04-20_023000.xml +``` + +### Viewing Differences Between Backups + +Compare two configurations: + +```bash +# Show what changed between two backups +diff backups/pfsense-config-2026-04-22_143022.xml backups/pfsense-config-2026-04-21_023001.xml + +# Or use git to see changes across commits +git log --oneline backups/ +git diff HEAD~1..HEAD -- backups/pfsense-config-*.xml +``` + +### Restoring from a Backup + +To restore a previous configuration on pfSense: + +1. Download the backup file from this repository +2. Log into pfSense WebUI +3. Go: **Diagnostics → Backup & Restore** +4. Choose the backup file and click **Restore Configuration** +5. Reboot when prompted + +## Future Enhancements + +- [ ] Compress old backups to save space +- [ ] Upload to cloud storage (S3, etc.) +- [ ] Encrypt sensitive configs before storing +- [ ] Notify on significant changes (email alert) +- [ ] Generate change reports showing diffs + +--- + +**Last Updated:** 2026-04-22 diff --git a/pfsense.home.arpa/scripts/backup-pfsense-config.sh b/pfsense.home.arpa/scripts/backup-pfsense-config.sh new file mode 100755 index 0000000..27aa35b --- /dev/null +++ b/pfsense.home.arpa/scripts/backup-pfsense-config.sh @@ -0,0 +1,388 @@ +#!/bin/bash + +################################################################################ +# pfSense Configuration Backup Utility +# +# This script automatically backs up your pfSense router configuration and +# stores it in the repository with a timestamped filename. +# +# Prerequisites: +# - SSH access to pfSense router (with public key authentication) +# - SSH host entry configured (default: 'pfsense' in ~/.ssh/config) +# - Git repository initialized in the current working directory +# - Sufficient disk space for configuration backup (typically < 1MB) +# +# Usage: +# ./backup-pfsense-config.sh # Uses default host 'pfsense' +# ./backup-pfsense-config.sh pfsense.home.arpa # Specify custom host +# ./backup-pfsense-config.sh -h # Show help +# +################################################################################ + +set -euo pipefail + +# Configuration (set defaults) +PFSENSE_HOST="pfsense" # SSH host (from ~/.ssh/config or IP) +PFSENSE_USER="${PFSENSE_USER:-root}" # SSH user +PFSENSE_CONFIG_PATH="/conf/config.xml" +BACKUP_DIR="$(dirname "$0")/../backups" +TIMESTAMP="$(date +%Y-%m-%d_%H%M%S)" +BACKUP_FILE="${BACKUP_DIR}/pfsense-config-${TIMESTAMP}.xml" +REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || echo ".")" +AUTO_COMMIT="${AUTO_COMMIT:-true}" + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +################################################################################ +# Helper Functions +################################################################################ + +log_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +log_success() { + echo -e "${GREEN}[✓]${NC} $1" +} + +log_warning() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" >&2 +} + +show_help() { + cat << EOF +Usage: $(basename "$0") [OPTIONS] [HOST] + +Backup pfSense router configuration to repository. + +ARGUMENTS: + HOST SSH host or IP address (default: 'pfsense') + Should be an entry in ~/.ssh/config or IP address + Example: pfsense, 192.168.1.1, pfsense.home.arpa + +OPTIONS: + -h, --help Show this help message + -n, --no-commit Download config without auto-committing to git + --dry-run Show what would be done without making changes + +ENVIRONMENT VARIABLES: + PFSENSE_USER SSH user (default: 'root') + AUTO_COMMIT Whether to auto-commit (default: 'true') + +EXAMPLES: + # Backup using default host and auto-commit + $ ./backup-pfsense-config.sh + + # Backup specific host + $ ./backup-pfsense-config.sh 172.27.0.1 + + # Backup without auto-commit + $ ./backup-pfsense-config.sh -n + + # Dry run (test connectivity) + $ ./backup-pfsense-config.sh --dry-run + +CONFIGURATION: + SSH host entry: ${PFSENSE_HOST} + SSH user: ${PFSENSE_USER} + Backup directory: ${BACKUP_DIR} + Config file: ${PFSENSE_CONFIG_PATH} + +NOTES: + - Requires SSH public key authentication to pfSense + - First run may prompt to accept SSH key fingerprint + - Backup files are stored with timestamps (YYYY-MM-DD_HHMMSS) + - Backups are committed to git with descriptive messages + - Each backup is human-readable XML for easy diffs + +EOF +} + +check_prerequisites() { + log_info "Checking prerequisites..." + + # Check SSH connectivity + if ! command -v ssh &> /dev/null; then + log_error "SSH is not installed or not in PATH" + return 1 + fi + log_success "SSH is available" + + # Check git + if ! command -v git &> /dev/null; then + log_error "Git is not installed or not in PATH" + return 1 + fi + log_success "Git is available" + + # Check backup directory exists + if [[ ! -d "${BACKUP_DIR}" ]]; then + log_warning "Backup directory does not exist: ${BACKUP_DIR}" + log_info "Creating backup directory..." + mkdir -p "${BACKUP_DIR}" || { + log_error "Failed to create backup directory" + return 1 + } + log_success "Backup directory created" + fi + + # Verify we're in a git repository + if ! git rev-parse --git-dir > /dev/null 2>&1; then + log_error "Not in a git repository (checked from $(pwd))" + return 1 + fi + log_success "Git repository found" + + return 0 +} + +test_ssh_connection() { + log_info "Testing SSH connection to ${PFSENSE_HOST}..." + + if ssh -o ConnectTimeout=10 "${PFSENSE_USER}@${PFSENSE_HOST}" "echo 'SSH connection successful'" > /dev/null 2>&1; then + log_success "SSH connection to ${PFSENSE_HOST} successful" + return 0 + else + log_error "Failed to connect to ${PFSENSE_HOST} via SSH" + log_info "Troubleshooting tips:" + log_info " 1. Verify SSH host is configured: ssh-keygen -F ${PFSENSE_HOST}" + log_info " 2. Test SSH manually: ssh ${PFSENSE_USER}@${PFSENSE_HOST}" + log_info " 3. Check firewall allows SSH (port 22) from your machine" + log_info " 4. Verify public key is installed on pfSense: /root/.ssh/authorized_keys" + return 1 + fi +} + +fetch_config() { + log_info "Fetching pfSense configuration from ${PFSENSE_HOST}..." + + # Use scp to copy the remote file + if ! scp "${PFSENSE_USER}@${PFSENSE_HOST}:${PFSENSE_CONFIG_PATH}" "${BACKUP_FILE}" 2>/dev/null; then + log_error "Failed to download configuration from ${PFSENSE_HOST}" + return 1 + fi + + if [[ ! -f "${BACKUP_FILE}" ]]; then + log_error "Backup file was not created: ${BACKUP_FILE}" + return 1 + fi + + log_success "Configuration downloaded to ${BACKUP_FILE}" + + # Show file size + local file_size + file_size=$(du -h "${BACKUP_FILE}" | cut -f1) + log_info "Backup size: ${file_size}" + + return 0 +} + +validate_config() { + log_info "Validating backup file..." + + # Check if file is valid XML + if ! grep -q '/dev/null || echo "${BACKUP_FILE}") + + if [[ -z "${relative_path}" ]]; then + relative_path="${BACKUP_FILE}" + fi + + # Add the backup file to git + if git -C "${REPO_ROOT}" add "${BACKUP_FILE}"; then + log_success "Added backup to git staging area" + else + log_error "Failed to add backup to git" + return 1 + fi + + # Create a meaningful commit message + local short_date + short_date=$(date +%Y-%m-%d\ %H:%M:%S) + local commit_msg="pfSense: Backup configuration (${short_date})" + + # Get configuration summary from XML + local vlan_count + vlan_count=$(grep -c '' "${BACKUP_FILE}" 2>/dev/null || echo "unknown") + local rule_count + rule_count=$(grep -c '' "${BACKUP_FILE}" 2>/dev/null || echo "unknown") + + # Enhanced commit message with details + local detailed_msg="${commit_msg} + +Contains: + - VLANs: ${vlan_count} + - Firewall rules: ${rule_count} + - Backup timestamp: ${TIMESTAMP} + +File: $(basename "${BACKUP_FILE}") +SHA256: $(shasum -a 256 "${BACKUP_FILE}" | awk '{print $1}') +" + + # Commit the backup + if git -C "${REPO_ROOT}" commit -m "${detailed_msg}" > /dev/null 2>&1; then + log_success "Configuration committed to git" + log_info "Commit message:" + echo "${detailed_msg}" | sed 's/^/ /' + return 0 + else + log_warning "No changes to commit (file may be identical to previous backup)" + return 0 + fi +} + +show_summary() { + echo "" + echo "════════════════════════════════════════════════════════════════" + log_success "pfSense configuration backup completed successfully!" + echo "════════════════════════════════════════════════════════════════" + echo "" + echo "Backup Details:" + echo " Location: ${BACKUP_FILE}" + echo " Size: $(du -h "${BACKUP_FILE}" | cut -f1)" + echo " Timestamp: ${TIMESTAMP}" + echo " From: ${PFSENSE_USER}@${PFSENSE_HOST}:${PFSENSE_CONFIG_PATH}" + echo "" + echo "Next Steps:" + echo " 1. Review the changes: git show HEAD" + echo " 2. Push to remote: git push origin main" + echo " 3. Schedule automated backups in crontab" + echo "" + echo "To schedule daily backups, add to crontab:" + echo " 0 2 * * * cd $(pwd) && ./scripts/backup-pfsense-config.sh" + echo "" +} + +################################################################################ +# Main Execution +################################################################################ + +main() { + # Parse arguments properly (flags first, then positional) + local dry_run=false + + while [[ $# -gt 0 ]]; do + case "$1" in + -h|--help) + show_help + exit 0 + ;; + -n|--no-commit) + AUTO_COMMIT="false" + shift + ;; + --dry-run) + dry_run=true + shift + ;; + -*) + log_error "Unknown option: $1" + show_help + exit 1 + ;; + *) + # This is a positional argument (hostname) + PFSENSE_HOST="$1" + shift + ;; + esac + done + + echo "" + echo "╔════════════════════════════════════════════════════════════════╗" + echo "║ pfSense Configuration Backup Utility ║" + echo "╚════════════════════════════════════════════════════════════════╝" + echo "" + + # Show configuration + log_info "Configuration:" + echo " Host: ${PFSENSE_HOST}" + echo " User: ${PFSENSE_USER}" + echo " Remote path: ${PFSENSE_CONFIG_PATH}" + echo " Backup dir: ${BACKUP_DIR}" + echo " Auto-commit: ${AUTO_COMMIT}" + echo "" + + # Check prerequisites + if ! check_prerequisites; then + log_error "Prerequisites check failed" + exit 1 + fi + + echo "" + + # Test SSH connection + if ! test_ssh_connection; then + exit 1 + fi + + echo "" + + if [[ "${dry_run}" == "true" ]]; then + log_success "Dry-run completed successfully. SSH connection is working." + echo "To perform actual backup, run: $(basename "$0") ${PFSENSE_HOST}" + exit 0 + fi + + # Fetch configuration + if ! fetch_config; then + exit 1 + fi + + echo "" + + # Validate the backup + if ! validate_config; then + exit 1 + fi + + echo "" + + # Commit to git (if enabled) + if [[ "${AUTO_COMMIT}" == "true" ]]; then + if ! commit_to_git; then + log_warning "Backup was downloaded but git commit may have failed" + exit 1 + fi + else + log_info "Skipping git commit (AUTO_COMMIT=false)" + fi + + # Show summary + echo "" + show_summary +} + +# Run main function +main "$@" diff --git a/zet.home.arpa/PROXY-SETUP.md b/zet.home.arpa/PROXY-SETUP.md new file mode 100644 index 0000000..e48e2a8 --- /dev/null +++ b/zet.home.arpa/PROXY-SETUP.md @@ -0,0 +1,66 @@ +# Transparent proxy notes for zet (172.27.0.35) + +Summary +- Squid runs on 172.27.0.35 (zet). We'll intercept HTTP traffic from selected child IPs and forward it to Squid. +- Approach: configure Squid for intercepted HTTP, create a pfSense Alias for children, add a NAT port-forward (80 -> 172.27.0.35:3128) limited to that Alias, and ensure appropriate firewall rules. + +Prerequisites +- Squid installed and reachable from pfSense (172.27.0.35). +- pfSense LAN interface used by children (pfSense at 172.27.0.1). +- List of children IPs or an IP range (create Alias in pfSense). + +Squid minimal config (intercept HTTP) +``` +http_port 3128 intercept +acl localnet src 172.27.0.0/24 +acl children src 172.27.0.100-172.27.0.110 # replace with your child IPs/range +http_access allow children +http_access deny all +access_log /var/log/squid/access.log +``` +- Restart Squid after changes: `sudo systemctl restart squid` or `service squid restart`. + +pfSense steps (high level) +1. Firewall → Aliases → Add + - Type: Hosts (or Network) + - Name: Children_Devices + - Add each child's static IP (or a range entry) + - Save + +2. Firewall → NAT → Port Forward → Add + - Interface: LAN (or interface children use) + - Protocol: TCP + - Source: Children_Devices (the Alias) + - Destination: any + - Destination port range: HTTP (80) + - Redirect target IP: 172.27.0.35 + - Redirect target port: 3128 + - Description: Redirect children HTTP -> Squid + - Save and Apply + - If prompted, allow pfSense to add the required firewall rule; otherwise add a LAN rule permitting Source=Children_Devices -> Destination=172.27.0.35 port 3128. + +3. Firewall rule: ensure the Alias is allowed outbound on LAN as needed. The NAT rule will create a rule; double-check to avoid accidental blocking. + +Verification +- Watch Squid logs on `zet`: + - `sudo tail -F /var/log/squid/access.log` +- From a child device, request an HTTP page and confirm the request appears in the access log. +- On pfSense: Diagnostics → Packet Capture (interface LAN, filter host and port 80) to confirm redirection. +- On `zet`: `sudo tcpdump -n -i any host and port 80` to see forwarded connections. + +Notes & caveats +- This only intercepts plain HTTP (port 80). HTTPS (port 443) interception requires ssl-bump / TLS interception: + - Requires creating a CA, configuring Squid SSL bump, and installing the CA on every client — this is intrusive and may break some apps. + - Consider leaving HTTPS un-intercepted or using explicit proxying for HTTPS instead. +- If clients have explicit proxy settings (via WPAD/DHCP 252), they will send traffic directly to the proxy and the NAT interception will not be used for those flows. +- WPAD option: you can advertise a PAC via DHCP Option 252 (value `http://172.27.0.35/wpad.dat`) to auto-configure browsers instead of intercepting. + +Quick debug commands +- Restart squid: `sudo systemctl restart squid` or `service squid restart` +- Tail access log: `sudo tail -F /var/log/squid/access.log` +- Test from a child: `curl -I http://example.com` +- tcpdump on zet: `sudo tcpdump -n -i any host and port 80` + +If you want, provide the exact child IPs and I will give you the precise pfSense NAT rule fields and a ready-to-paste `squid.conf` snippet for your environment. + +-- notes written by assistant