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.
This commit is contained in:
191
README.md
Normal file
191
README.md
Normal file
@@ -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
|
||||||
68
pfsense.home.arpa/BACKUP-QUICKSTART.md
Normal file
68
pfsense.home.arpa/BACKUP-QUICKSTART.md
Normal file
@@ -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
|
||||||
150
pfsense.home.arpa/INDEX.md
Normal file
150
pfsense.home.arpa/INDEX.md
Normal file
@@ -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
|
||||||
296
pfsense.home.arpa/README.md
Normal file
296
pfsense.home.arpa/README.md
Normal file
@@ -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
|
||||||
173
pfsense.home.arpa/VLAN-CONFIG.md
Normal file
173
pfsense.home.arpa/VLAN-CONFIG.md
Normal file
@@ -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
|
||||||
291
pfsense.home.arpa/VLAN-QUICKSTART.md
Normal file
291
pfsense.home.arpa/VLAN-QUICKSTART.md
Normal file
@@ -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
|
||||||
262
pfsense.home.arpa/VLAN-TOPOLOGY.md
Normal file
262
pfsense.home.arpa/VLAN-TOPOLOGY.md
Normal file
@@ -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
|
||||||
11
pfsense.home.arpa/backups/.gitkeep
Normal file
11
pfsense.home.arpa/backups/.gitkeep
Normal file
@@ -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)
|
||||||
226
pfsense.home.arpa/scripts/README.md
Normal file
226
pfsense.home.arpa/scripts/README.md
Normal file
@@ -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
|
||||||
388
pfsense.home.arpa/scripts/backup-pfsense-config.sh
Executable file
388
pfsense.home.arpa/scripts/backup-pfsense-config.sh
Executable file
@@ -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 '<?xml' "${BACKUP_FILE}"; then
|
||||||
|
log_error "Backup file does not appear to be valid XML"
|
||||||
|
log_warning "Removing invalid backup: ${BACKUP_FILE}"
|
||||||
|
rm -f "${BACKUP_FILE}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for pfSense-specific markers
|
||||||
|
if ! grep -q '<pfsense' "${BACKUP_FILE}"; then
|
||||||
|
log_warning "Backup file may not be a valid pfSense configuration"
|
||||||
|
log_info "File contents (first 20 lines):"
|
||||||
|
head -20 "${BACKUP_FILE}"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_success "Backup file is valid XML with pfSense markers"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
commit_to_git() {
|
||||||
|
log_info "Committing backup to git repository..."
|
||||||
|
|
||||||
|
local relative_path
|
||||||
|
relative_path=$(git -C "${REPO_ROOT}" ls-files --full-name "${BACKUP_FILE}" 2>/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 '<vlan>' "${BACKUP_FILE}" 2>/dev/null || echo "unknown")
|
||||||
|
local rule_count
|
||||||
|
rule_count=$(grep -c '<rule>' "${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 "$@"
|
||||||
66
zet.home.arpa/PROXY-SETUP.md
Normal file
66
zet.home.arpa/PROXY-SETUP.md
Normal file
@@ -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 <child_ip> and port 80) to confirm redirection.
|
||||||
|
- On `zet`: `sudo tcpdump -n -i any host <child_ip> 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 <child_ip> 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
|
||||||
Reference in New Issue
Block a user