← Back to Sanchez Home Network

Security Hardening & Network Segmentation Plan

Sanchez Home Network — Rod-Server Infrastructure

Phase 0 Complete Phase 1 Complete Phase 2 In Progress Phases 3-5 Planned

Version 1.3.1 — 2026-02-18 — Classification: INTERNAL

Executive Summary

This plan transforms the Sanchez Home Network from a flat, trust-all architecture into a segmented, zero-trust infrastructure capable of safely hosting public web services while protecting sensitive internal systems.

0
Inbound Ports
(Cloudflare Tunnel)
2FA
Required for
All Admin Panels
AES-256
Data at Rest
Encryption
4
Network Zones
(DMZ/Internal/Home/IoT)
  • Zero Trust: Every request is authenticated and authorized, regardless of network origin
  • Defense in Depth: Multiple independent security layers — if one fails, others hold
  • Least Privilege: Services get minimum access required; admin panels require MFA
  • Encryption Everywhere: Data encrypted in transit (TLS/WireGuard) and at rest (LUKS)
  • DMZ Isolation: Public traffic never touches the internal network directly

Implementation Status Update (2026-02-18)

Achieved in this review cycle
  • Public Cloudflare subdomain A/CNAME records were removed to reduce direct public naming exposure.
  • Pi-hole wildcard/local DNS remains active for internal resolution to 10.0.1.6.
  • Router-DNS fallback was added via wildcard DNS-only record (*.sanchezfamily.ca -> 10.0.1.6) so clients using router DNS still resolve internal subdomains.
  • DNS behavior validated from router DNS and Pi-hole DNS for known and wildcard subdomains.
Not achieved yet (still open)
  • Authelia deployment + Traefik forwardAuth + full route protection tests.
  • CrowdSec deployment with tuned detection scenarios and active bouncer enforcement.
  • Cloudflare Access admin gating and complete LAN-only ingress hardening on Rod-Server.
  • Disable cloudflared on Rod-Server after full DMZ tunnel cutover to 10.0.1.5.
  • Phase 3-5 controls: WireGuard inter-host, LUKS migration, VLAN segmentation, Suricata, and remaining monitoring work.

Threat Model

Critical Assets

AssetSensitivityLocationImpact if Compromised
Vaultwarden passwordsCRITICALRod-ServerTotal identity compromise
SSH keys (agent mesh)CRITICALRod-Server ~/.ssh/Lateral movement to all hosts
Docker socketCRITICALRod-ServerContainer escape = root on host
MariaDB databasesHIGHRod-Server DockerData breach (Nextcloud, n8n, crypto)
PostgreSQL (LibroSynth)HIGHRod-Server DockerResearch data loss
Cloudflare API keysHIGH_rod/.envDomain hijacking
Omada controllerHIGHRod-Server DockerFull network control
Home AssistantMEDIUMRod-Server DockerPhysical home access (locks, cameras)
Personal filesMEDIUMRod-Server /media/rod/Privacy breach

Threat Actors

ActorMotivationCapabilityLikely Attack Vector
Automated botsCrypto mining, DDoS recruitmentLow-MediumScanning open ports, default creds, known CVEs
Script kiddiesDefacement, braggingLowPublic-facing services, weak passwords
Targeted attackerData theft, ransomwareMedium-HighCloudflare bypass, supply chain, phishing
Insider (compromised IoT)Lateral movementMediumFlat network, no segmentation

Previously Exposed Services (Now Being Fixed)

30+ services were accessible from the internet via *.sanchezfamily.ca, including phpMyAdmin (database admin), Portainer (Docker control), Terminal (shell access), and n8n (arbitrary code execution). This plan eliminates all unprotected public access.

Vulnerability Status

Tracked vulnerabilities with current remediation status as of the 2026-02-15 lockdown.

#VulnerabilitySeverityMitigationStatus
1 Admin panels public (Portainer, phpMyAdmin, Dockge, Terminal) CRITICAL lan-only middleware (immediate) + Authelia 2FA (Phase 1) MITIGATED
2 Flat network — no segmentation HIGH VLANs + WireGuard (Phase 3-4) Open
3 No MFA on any service HIGH Authelia TOTP (Phase 1) Open
4 Dual cloudflared conflict HIGH Consolidate to TinyDesk (Phase 2) Open
5 UFW too permissive (DNS, Omada from anywhere) HIGH UFW hardening (Phase 2) FIXED
6 No IDS/IPS MEDIUM CrowdSec (Phase 1) Open
7 Data at rest unencrypted MEDIUM LUKS encryption (Phase 3) Open
8 Docker socket exposed to containers HIGH Restrict to Traefik + Portainer only Open
9 Hardcoded credentials in compose files MEDIUM Move to .env / Docker secrets (Phase 3) FIXED
10 No centralized logging MEDIUM Grafana + Loki (Phase 4) Open
11 DOCKER-USER chain empty (Docker bypasses UFW) CRITICAL Populate with DROP rules FIXED
12 No HTTP→HTTPS redirect HIGH https-redirect middleware FIXED
13 Missing security headers MEDIUM security-headers middleware FIXED
14 Cloudflare real-IP plugin broken HIGH Populate trustedCIDRs FIXED
15 Database connections unencrypted HIGH Enable TLS on MariaDB/PostgreSQL FIXED — MariaDB: require_secure_transport=ON, TLS_AES_256_GCM_SHA384; PostgreSQL: TLSv1.3, TLS_AES_256_GCM_SHA384
16 IoT DNS pinhole to Infrastructure MEDIUM Rate-limit + restrict to UDP 53 only; consider secondary DNS forwarder Open — see Section 7.5
17 Container images pulled by tag (mutable) MEDIUM Pin images by digest (SHA256) for immutability FIXED — 11 images pinned by SHA256 (8 hosting + 3 LibroSynth)
Phase 0+1 results: 8 of 17 vulnerabilities FIXED, 1 MITIGATED. Remaining 8 items are scheduled across Phases 2–5.

Phase 0: Completed Hardening

Vaultwarden has been fully isolated — the most sensitive service is now protected with 7 layers of defense.

Vaultwarden Isolation (Pre-Lockdown)

ItemStatusDetails
ER605 firmwareCURRENTv2.3.3 — patches CVE-2025-7850 (CVSS 9.3), CVE-2025-7851 (CVSS 8.7)
Vaultwarden signupsFIXEDSIGNUPS_ALLOWED=false, INVITATIONS_ALLOWED=false
Vaultwarden networkISOLATEDDedicated vault_isolated network (172.30.0.0/28) — only 2 containers
Vaultwarden filesystemHARDENEDread_only: true, no-new-privileges:true
Admin panelLAN ONLY/admin blocked from internet via Traefik ipAllowList
Brute force protectionACTIVELogin: 3 attempts/60s, Admin: 3 attempts/60s
Security headersAPPLIEDCSP, HSTS (1 year), Permissions-Policy, X-Frame DENY

2026-02-15 Lockdown (Platform-Wide)

ItemStatusDetails
lan-only middlewareAPPLIED19 admin routers — Portainer, phpMyAdmin, Dockge, Terminal, Traefik dashboard, Pi-hole, Omada, MCP, Filebrowser, Frigate, go2rtc, Ollama, Grafana, qBittorrent, Dashboard
cloudflare-only middlewareAPPLIED18 public routers — Nextcloud, n8n, Home Assistant, Forgejo, Kavita, Audiobooks, Plex, etc.
https-redirect middlewareAPPLIEDAll 47 HTTP routers redirect 301 to HTTPS
security-headers middlewareAPPLIEDAll 36+ HTTPS routers — HSTS, XSS, nosniff, frame options, referrer, permissions
cloudflare-real-ip fixFIXEDPopulated trustedCIDRs with 15 Cloudflare IP ranges
UFW DNS restrictionFIXEDPort 53 restricted to LAN-only (10.0.1.0/24)
UFW Omada restrictionFIXEDPorts 29810-29814 restricted to LAN-only (10.0.1.0/24)
DOCKER-USER iptablesAPPLIEDDROP rules for ports 5433, 5434, 15672, 9002, 9003, 9091, 8089, 8053, 1984
DOCKER-USER persistenceACTIVEsystemd service docker-user-rules.service — rules survive reboot
VPN credentialsFIXEDHardcoded VPN creds moved from docker-compose.yml to .env

Phase 1: Infrastructure Hardening (2026-02-15) COMPLETE

All Phase 1 items completed on 2026-02-15 — Traefik hardening, database TLS, container scanning, DNS sinkholing, and image digest pinning are now active.
ItemStatusDetails
Traefik rate limitingAPPLIEDauth-rate-limit middleware: 5 req/s sustained, burst 10
Traefik body limitAPPLIEDbody-limit middleware: maxRequestBodyBytes 2MB
Traefik circuit breakerAPPLIEDcircuit-breaker middleware: trips at >25% 5xx errors
Secure middleware chainAPPLIEDsecure-chain compositions combining security-headers, rate-limit, body-limit, circuit-breaker
TLS hardeningAPPLIEDsniStrict: true, ECDSA cipher suites: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
serversTransport timeoutsAPPLIEDdialTimeout: 5s, responseHeaderTimeout: 30s, idleConnTimeout: 30s (Slowloris defense)
MariaDB TLSACTIVErequire_secure_transport=ON, cipher: TLS_AES_256_GCM_SHA384
PostgreSQL TLSACTIVETLSv1.3, cipher: TLS_AES_256_GCM_SHA384, certs in persistent volume
Trivy container scanningACTIVEv0.69.1 installed, weekly cron scan Sundays 3AM
Pi-hole blocklistsACTIVE1,442,496 gravity domains — 6 new C2/malware/phishing feeds from abuse.ch, NoTracking, RPiList
Image digest pinningAPPLIED11 images pinned by SHA256 (8 hosting + 3 LibroSynth) — prevents supply chain substitution

Target Architecture

INTERNET | [Cloudflare Edge] WAF + DDoS + Bot management Access policies (SSO) | Cloudflare Tunnel (QUIC, encrypted) | ====================================================== | DMZ - TinyDesk (10.0.10.2) | | VLAN 10 - 10.0.10.0/24 | | | | [cloudflared] --> [Traefik DMZ] | | | | | PUBLIC SERVICES ONLY | | nginx, vaultwarden, kavita, nextcloud, | | forgejo, plex, audiobooks, client sites | | | | UFW: DENY ALL IN (except WireGuard) | | | | =========|============================================ | WireGuard Tunnel (10.0.99.0/30) | ChaCha20-Poly1305 encrypted | Only DB ports traverse | =========|============================================ | v INTERNAL - Rod-Server (10.0.20.2) | | VLAN 20 - 10.0.20.0/24 | | | | [Authelia 2FA] <-- [Traefik Internal] | | | | | | TOTP Required *.home services | | | | DATABASES ADMIN (MFA) AI/RESEARCH | | MariaDB(TLS) Portainer LibroSynth | | PostgreSQL phpMyAdmin Ollama | | Redis Dockge n8n | | RabbitMQ Terminal MCP Proxy | | MinIO Pi-hole Grafana | | Traefik(MFA) Prometheus | | | | LUKS: sensitive data encrypted at rest | ====================================================== | =========|============================================ | v HOME - VLAN 1 - 10.0.1.0/24 | | | | Laptops, phones, rod-ml, Mac mini, eero mesh | | Access: *.home via Pi-hole DNS | | Admin panels: Authelia MFA required | ====================================================== | =========|============================================ | v IoT - VLAN 30 - 10.0.30.0/24 | | | | Smart lights, cameras, sensors | | Dedicated SSID: Sanchez_IoT | | AP isolation enabled | | DNS: Pi-hole only (no direct internet DNS) | | Home→IoT: ALLOW IoT→Home: DENY | ======================================================

Why This Architecture?

Cloudflare Tunnel instead of port forwarding: Zero inbound ports on the router eliminates WAN attack surface entirely. The ER605 has had critical CVEs (7850, 7851) — removing it from the attack path is the strongest mitigation.
TinyDesk as DMZ: Physical separation means a compromised DMZ cannot access Rod-Server's memory, disk, or Docker socket. The WireGuard tunnel allows only specific database ports through. Adequate hardware: Ryzen 5 3550H, 8 cores, 20GB RAM, 476GB NVMe.
Authelia over Cloudflare Access alone: Cloudflare Access protects .sanchezfamily.ca but NOT .home routes. Authelia protects both, works offline, and is self-hosted with no external dependency.
Two-factor (TOTP) for all admin services: Even if credentials leak from a .env file, the attacker cannot authenticate without the TOTP device. This is the highest practical authorization level.
WireGuard between DMZ and Internal: Standard Docker networking is unencrypted on the wire. WireGuard encrypts all traffic with ChaCha20-Poly1305. Fine-grained firewall: only ports 3306, 5432, 6379 traverse the tunnel.
LUKS encryption at rest: Protects against physical theft and disk forensics. LUKS2 with AES-256-XTS provides ~3% CPU overhead with AES-NI on the Ryzen 5 4600H.

Cloudflare One Integration Opportunities

Beyond the Tunnel and Access already in the plan, the Cloudflare One platform offers additional components that could replace or complement local tools:

ComponentReplacesPhaseBenefitTrade-off
Tunnel (cloudflared)Port forwardingPhase 2 (active)Zero inbound ports, encrypted QUICCloudflare dependency
Access (Zero Trust)Edge authPhase 2 (active)SSO/MFA at edge, identity-awareDoes not protect .home routes
WARP (device client)Tailscale meshPhase 5 (evaluate)Secure remote access without VPN portsRequires WARP client on devices
Gateway (DNS filtering)Pi-hole (for IoT)Phase 5 (evaluate)Edge-based DNS filtering, works off-networkLoses local DNS cache + ad blocking
Browser-Rendered SSHwetty Terminal containersPhase 2 (evaluate)Eliminates 3 terminal containers, centralizes SSHRequires internet for local SSH
R2 (object storage)Local backup storagePhase 5Off-site encrypted backups, S3-compatible, $0 egressMonthly storage cost
Decision framework: Prefer local tools (Pi-hole, WireGuard, Authelia) as primary, with Cloudflare services as complementary edge layer. This preserves functionality when internet is down and avoids vendor lock-in.

Authentication & Authorization (Authelia)

Authorization Levels

LevelRequirementApplied To
two_factorPassword + TOTP (mandatory)All admin/management panels
one_factorPassword onlyLow-risk services (Kavita, Frigate camera feeds)
bypassNo authenticationServices with own auth (Nextcloud, Plex, Vaultwarden), health endpoints

Services Requiring Two-Factor

ServiceAuth LevelWhy
Portainertwo_factorFull Docker control = root equivalent access
phpMyAdmintwo_factorDirect SQL access to all databases
Dockgetwo_factorDocker compose editor = arbitrary container deployment
Terminal (wetty)two_factorShell access to the server
Traefik dashboardtwo_factorReveals entire routing topology and internal IPs
Pi-hole admintwo_factorDNS manipulation enables phishing attacks
n8ntwo_factorWorkflow automation = arbitrary code execution
Grafanatwo_factorMay expose internal metrics and secrets
Home Assistanttwo_factorPhysical home control (locks, lights, cameras)
Omada controllertwo_factorFull network management and configuration
MCP Proxytwo_factorDatabase, Docker, and LLM access proxy
Filebrowsertwo_factorFilesystem read/write access
Ollamatwo_factorLLM API — resource abuse and data exfiltration
Prometheustwo_factorInternal metrics exposure

Configuration Design

SettingValue
User StoreFile-based (users_database.yml)
Session BackendFile-based (no external Redis)
Storage BackendSQLite (encrypted at rest via LUKS)
Second FactorTOTP (RFC 6238)
Session Duration12 hours active, 30 days remember-me
Session CookieEncrypted, Secure, SameSite=Lax
Password HashingArgon2id (64MB, 3 iterations, 4 parallelism)
Argon2id password hashing (64MB, 3 iterations): Memory-hard, GPU-resistant. Same algorithm used by Vaultwarden — consistent security standard across the stack.
File-based user store: Only 1 user (rodchemist) — LDAP/database is unnecessary complexity. Single YAML file is trivial to backup and restore.
12-hour sessions, 30-day remember-me: Balances security with convenience. Inactive sessions expire, but trusted devices persist. Revocable by deleting session store.

Cloudflare Access + Authelia Dual-Layer Architecture

Cloudflare Access and Authelia serve complementary roles and can coexist without conflict:

LayerToolFunctionScope
Edge (internet)Cloudflare AccessAuthentication — Who are you?*.sanchezfamily.ca only
Ingress (local)AutheliaAuthorization + 2FA — What can you do?Both *.sanchezfamily.ca and *.home

Request Flow (Public Access)

User Cloudflare Access (identity check, signed JWT) Tunnel Traefik Authelia forwardAuth (2FA) Service

Request Flow (LAN Access)

User Pi-hole DNS Traefik Authelia forwardAuth (2FA) Service

Key Design Points

Encryption Strategy

In Transit (All Connections Encrypted)

ConnectionProtocolStatus
Internet → CloudflareTLS 1.3ACTIVE
Cloudflare → TinyDeskCloudflare Tunnel (QUIC+TLS)ACTIVE
TinyDesk → Rod-ServerWireGuard (ChaCha20-Poly1305)PHASE 3
Browser → *.sanchezfamily.caTLS 1.2+ (Let's Encrypt)ACTIVE
Browser → *.homeTLS 1.2+ (Local CA)ACTIVE
Apps → MariaDBTLS 1.2+ (self-signed, TLS_AES_256_GCM_SHA384)ACTIVE
Apps → PostgreSQLTLSv1.3 (self-signed, TLS_AES_256_GCM_SHA384)ACTIVE
SSH between hostsSSH (Ed25519)ACTIVE

At Rest (Sensitive Data Encrypted)

DataMethodStatus
Vaultwarden DB (passwords)LUKS2 + AES-256-XTSPHASE 3
MariaDB data directoryLUKS2 + AES-256-XTSPHASE 3
TLS certificates & private keysLUKS2 + AES-256-XTSPHASE 3
.env credentials fileLUKS2 (same volume)PHASE 3
BackupsGPG symmetric (AES-256)PHASE 4

LUKS Implementation

Target: Create an encrypted volume at /home/rod/_rod/_hosting/encrypted/ holding Vaultwarden DB, MariaDB data, Traefik certs, and .env credentials. Auto-unlock via systemd + TPM or passphrase keyslot at boot.

LUKS2 over eCryptfs/fscrypt: Block-level encryption is filesystem-agnostic, supports multiple keyslots (daily key + recovery key), and performs better for database workloads than file-level encryption. AES-NI hardware acceleration on Ryzen provides ~3% overhead.
AES-256-XTS over ChaCha20: Hardware-accelerated via AES-NI on x86_64. XTS mode designed specifically for disk encryption. NIST-approved.
GPG for backups: Portable — encrypted backups can be decrypted on any machine with GPG. Passphrase-based symmetric encryption requires no key management.

Network Segmentation

VLAN Design

VLANNameSubnetGatewayPurpose
1Home10.0.1.0/2410.0.1.1Personal devices (laptops, phones)
10DMZ10.0.10.0/2410.0.10.1TinyDesk (public-facing)
20Infrastructure10.0.20.0/2410.0.20.1Rod-Server (internal)
30IoT10.0.30.0/2410.0.30.1Smart home devices (lights, cameras, sensors)
Dedicated IoT VLAN: IoT devices are frequently insecure by design, lack updates, and are common botnet targets (Mirai, etc.). Placing IoT on VLAN 1 alongside laptops enables lateral movement via ARP spoofing. A dedicated IoT VLAN allows Home→IoT connections (control) but blocks IoT→Home initiation.

ER605 ACL Rules (10 total, within 50-entry limit)

#DirectionActionRationale
1VLAN 10 → VLAN 20DENYDMZ cannot reach internal (WireGuard bypasses at L3)
2VLAN 10 → VLAN 1DENYDMZ cannot reach home devices
3VLAN 1 → VLAN 20ALLOWHome devices access *.home services
4VLAN 20 → VLAN 1ALLOWRod-Server provides DNS, monitoring
5VLAN 1 → VLAN 10DENYHome devices don't need DMZ access
6ALL → WANALLOWAll VLANs can reach internet
7VLAN 1 → VLAN 30ALLOWHome can control IoT devices
8VLAN 30 → VLAN 1DENYIoT cannot initiate to Home (lateral movement prevention)
9VLAN 30 → VLAN 20DENYIoT cannot reach Infrastructure
10VLAN 20 → VLAN 30ALLOWInfrastructure can monitor IoT (HA, DNS)
ER605 ACLs as defense-in-depth only: The ER605's stateless ACLs cannot track connection state (unlike UniFi/pfSense). Host-level firewalls (UFW) with stateful tracking are the actual enforcement layer. VLANs provide an additional physical barrier — they prevent accidental exposure, not sophisticated attacks. WireGuard operates at Layer 3 and bypasses inter-VLAN routing.

Host Firewall Rules

TinyDesk (DMZ) UFW

Default: DENY incoming, ALLOW outgoing
ALLOW 51820/udp FROM 10.0.20.2    # WireGuard from Rod-Server
ALLOW 22/tcp FROM 10.0.1.0/24      # SSH from Home LAN
DENY everything else inbound

Rod-Server (Internal) UFW

Default: DENY incoming, ALLOW outgoing
# WireGuard
ALLOW 51820/udp FROM 10.0.10.2           # WireGuard from TinyDesk
# Database access via WireGuard tunnel ONLY
ALLOW 3306/tcp FROM 10.0.99.1            # MariaDB
ALLOW 5432/tcp FROM 10.0.99.1            # PostgreSQL
ALLOW 6379/tcp FROM 10.0.99.1            # Redis
# LAN services
ALLOW 80,443/tcp FROM 10.0.1.0/24        # Traefik (*.home)
ALLOW 53 FROM 10.0.1.0/24                # Pi-hole DNS
ALLOW 22/tcp FROM 10.0.1.0/24            # SSH
ALLOW 8043 FROM 10.0.1.0/24              # Omada controller
# Docker internal
ALLOW FROM 172.16.0.0/12                  # Docker subnet (internal)
DENY everything else

IoT DNS Pinhole Risk

Critique (v1.1.0 review): IoT devices (VLAN 30) are forced to use Pi-hole (on Rod-Server, VLAN 20) for DNS. This requires an ACL allowing VLAN 30 → VLAN 20 port 53, creating a path from the "Hostile" IoT zone into the "Trusted" Infrastructure zone. DNS tunneling or dnsmasq exploits could pivot from a compromised camera to Rod-Server.
OptionApproachComplexityRisk Reduction
A (Best)Secondary Pi-hole instance on DMZ (TinyDesk) for IoT DNS; Rod-Server Pi-hole for VLAN 1/20 onlyMediumHigh — no IoT→Infra path
B (Acceptable)Strict ACL: IoT → Rod-Server UDP 53 only (no TCP, no other ports) + Pi-hole rate limiting (100 queries/min per IP)LowMedium — limits but doesn't eliminate path
C (Best effort)Use Cloudflare Gateway as upstream DNS for IoT VLAN (no local Pi-hole dependency)LowMedium — moves trust to Cloudflare
Current plan: Option B for initial deployment (Phase 4), with Option A as Phase 5 enhancement if IoT device count grows. The ACL in Section 7.2 rule #9 (VLAN 30 → VLAN 20: DENY) must include an exception for UDP 53 only.

Docker Isolation

Network Segmentation (Target)

NetworkSubnetTypeContainers
vault_isolated172.30.0.0/28BridgeTraefik + Vaultwarden ONLY DONE
web_public172.25.0.0/24BridgeTraefik + public-facing services
web_admin172.25.1.0/24BridgeTraefik + Authelia + admin services
db_backend172.26.0.0/24InternalMariaDB, Redis (no external access)
librosynth172.28.0.0/24InternalLibroSynth microservices

Docker Socket Protection

The Docker socket (/var/run/docker.sock) grants root-equivalent access. Currently exposed to Traefik, Portainer, and Dockge.

Mitigation: Dual Docker socket proxy architecture (tecnativa/docker-socket-proxy):

ProxyForCONTAINERSIMAGESNETWORKSSERVICESVOLUMESPOSTEXEC
Read-only proxyTraefik1011000
Management proxyPortainer + Dockge1111111*

* Portainer requires EXEC=1; Dockge does not. Management proxy restricted to web_admin network only.

# Read-only proxy (Traefik)
docker-socket-proxy-ro:
  image: tecnativa/docker-socket-proxy
  environment:
    CONTAINERS: 1
    IMAGES: 0
    NETWORKS: 1
    SERVICES: 1
    POST: 0          # Read-only
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
  networks:
    - socket_proxy

# Management proxy (Portainer + Dockge)
docker-socket-proxy-mgmt:
  image: tecnativa/docker-socket-proxy
  environment:
    CONTAINERS: 1
    IMAGES: 1
    NETWORKS: 1
    SERVICES: 1
    VOLUMES: 1
    POST: 1          # Write access for management
  volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
  networks:
    - web_admin      # Only accessible from admin network
Alternative: Portainer Agent (considered but deferred): Portainer can use an Agent instead of direct socket access, creating a restricted API tunnel. The Agent blocks raw exec and events endpoints by design. However, for single-host deployment the agent adds complexity without significant benefit over the dual-proxy approach. Revisit if deploying Portainer to manage multiple Docker hosts.

Known Limitations

  • Does not filter by container name — any allowed operation applies to all containers
  • POST=1 still allows container creation/deletion (Portainer needs this)
  • No per-endpoint granularity (e.g., cannot allow POST /containers/start but deny POST /containers/create)
  • Bypass vector: if an attacker compromises Portainer, they have full Docker API access through the management proxy
  • Mitigation: Authelia 2FA on Portainer + lan-only middleware (already applied) reduces risk to authenticated, local attackers only

Container Security Standards

Intrusion Detection (CrowdSec)

Why CrowdSec

Kill Chain Detection (Mapped to Traefik Logs)

Kill Chain PhaseTraefik Log PatternCrowdSec Action
Reconnaissance
(scanning)
High 403/404 volume from single ClientAddr; scanner User-Agent strings (Nmap, Nikto, sqlmap); sequential requests to /admin, /wp-login, /.env, /api/v1/debug Ban IP for 4 hours
Weaponization/Delivery
(exploitation)
Spike in 500 errors; RequestPath containing UNION SELECT, <script>, ../; ResponseCodeRatio(500,600,0,600) > 0.25 Ban IP for 24 hours; Circuit Breaker trips
Installation
(persistence)
POST requests to admin endpoints from unknown IPs; new User-Agent strings on authenticated sessions Ban IP for 7 days
C2
(command & control)
"Low and slow" beaconing: regular-interval requests to same endpoint; consistent small RequestContentSize/DownstreamContentSize; connections at odd hours Alert + ban IP for 7 days
Exfiltration Unusually large DownstreamContentSize responses; sustained high Duration connections to external IPs Alert + immediate ban
Known malicious IP
(crowdsourced)
N/A — preemptive block Block preemptively

Traefik Hardening Middleware COMPLETE

All Traefik hardening middleware has been applied to dynamic.yml and traefik.yml as of 2026-02-15:

Rate Limiting (DoS / Brute Force)

auth-rate-limit:
  rateLimit:
    average: 5        # 5 requests/second sustained
    burst: 10         # allow spike of 10
    # Apply to login/auth endpoints

Request Size Limits (Buffer Overflow / DoS)

body-limit:
  buffering:
    maxRequestBodyBytes: 2097152    # 2MB max request body
    maxResponseBodyBytes: 10485760  # 10MB max response body
    memRequestBodyBytes: 1048576    # 1MB in-memory buffer
    memResponseBodyBytes: 1048576

Circuit Breaker (Exploitation Detection)

circuit-breaker:
  circuitBreaker:
    expression: "ResponseCodeRatio(500, 600, 0, 600) > 0.25"
    # Trips when >25% of responses are 5xx errors

Timeout Hardening (Slowloris Defense)

In traefik.yml static config:

serversTransport:
  forwardingTimeouts:
    dialTimeout: 5s
    responseHeaderTimeout: 30s
    idleConnTimeout: 30s

Secure Middleware Chain

secure-chain:
  chain:
    middlewares:
      - security-headers
      - auth-rate-limit
      - body-limit
      - circuit-breaker

TLS Hardening

tls:
  options:
    default:
      minVersion: VersionTLS12
      cipherSuites:
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
        - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
      sniStrict: true
Circuit Breaker: High 5xx error ratios indicate active exploitation. The circuit breaker halts traffic to protect the backend and triggers CrowdSec investigation. Expression ResponseCodeRatio(500, 600, 0, 600) > 0.25 trips when more than 25% of responses are server errors.

Implementation Phases

Phase 0: Emergency Fixes COMPLETE

Phase 1: Infrastructure Hardening COMPLETE

All Phase 1 infrastructure hardening completed 2026-02-15. Authelia (2FA), CrowdSec (IDS), and Grafana monitoring remain as Phase 1b items to be addressed next.

Traefik hardening middleware:

Database TLS (moved from Phase 3):

Supply chain & DNS:

Authelia (2FA) — remaining:

CrowdSec (IDS) — remaining:

Monitoring (Grafana) — remaining:

Key Prometheus queries for security monitoring:

# DDoS / scanning spike detection
rate(traefik_entrypoint_requests_total[5m])

# Backend crash detection (exploitation indicator)
rate(http_requests_total{status="500"}[5m])

# Resource abuse (crypto-miner detection)
process_resident_memory_bytes
rate(node_cpu_seconds_total[5m])

Key Loki queries:

# Authelia brute force detection
{compose_service="authelia"} | logfmt | level="error"

# Traefik 4xx/5xx by source IP
{compose_service="traefik"} | json | DownstreamStatus >= 400

Phase 2: Cloudflare & Firewall IN PROGRESS

10.0.1.5 cleanup (IN PROGRESS): Stripping Bosgame Ecolite mini PC (AMD Ryzen 5 3550H, 20GB RAM) from 32 duplicate containers down to cloudflared-only DMZ endpoint. Tunnel ID: f49ac13d-2108-4170-8052-457167417bae

Phase 3: Encryption & Tunnels PLANNED

Phase 4: Network Segmentation & Monitoring PLANNED

VLANs:

IoT VLAN 30 implementation:

Monitoring:

Docker isolation:

Phase 5: Ongoing Hardening PLANNED

Service Classification Matrix

CRITICAL (Highest Isolation)

ServiceAuthNetworkEncryption
VaultwardenOwn auth + isolatedvault_isolated /28LUKS at rest, TLS in transit

HIGH (Two-Factor Required)

ServiceAuth LevelPublic?Network
PortainerAuthelia 2FANo — LAN onlyweb_admin
phpMyAdminAuthelia 2FANo — LAN onlyweb_admin
DockgeAuthelia 2FANo — LAN onlyweb_admin
Terminal (wetty)Authelia 2FANo — LAN onlyweb_admin
Traefik DashboardAuthelia 2FANo — LAN onlyweb_admin
Pi-holeAuthelia 2FANo — LAN onlyweb_admin
n8nAuthelia 2FACF Access onlyweb_admin
GrafanaAuthelia 2FANoweb_admin
Home AssistantAuthelia 2FACF Accessweb_admin
OmadaAuthelia 2FANo — LAN onlyweb_admin
MCP ProxyAuthelia 2FANo — LAN onlyweb_admin
FilebrowserAuthelia 2FANo — LAN onlyweb_admin

MEDIUM (One-Factor or Own Auth)

ServiceAuth LevelPublic?Network
NextcloudOwn authYes (via CF)web_public
ForgejoOwn authYes (via CF)web_public
FrigateAuthelia 1FANoweb_admin
KavitaAuthelia 1FAYesweb_public
AudiobookshelfOwn authYesweb_public

LOW (Public or Bypass)

ServiceAuth LevelPublic?Network
nginx (landing page)NoneYesweb_public
PlexOwn authYesweb_public
Ollama APIAuthelia 2FANoweb_admin
Health endpointsNoneAPI onlyvaries

Decision Log

#DecisionAlternativeRationale
1AutheliaAuthentikLighter (~40MB vs ~500MB), sufficient for 1 user, lower complexity
2TOTPWebAuthnWorks on any phone, no hardware purchase. WebAuthn addable later
3Cloudflare TunnelPort forwardingZero inbound ports, free WAF, DDoS protection, IP hiding
4WireGuardTailscaleSimpler for 2-host P2P, no external dependency
5TinyDesk DMZSame-host isolationPhysical separation = strongest isolation
6LUKS volumesFull-disk encryptionNon-disruptive, targets highest-value data
7CrowdSecFail2banNative Traefik integration, crowdsourced intelligence
8File-based AutheliaDB-backed1 user doesn't need a database
9ER605 VLANs (defense-in-depth)Replace with OPNsenseAlready deployed, host firewalls are primary
10Separate Docker networks per tierSingle network + policiesDocker doesn't support network policies (that's Kubernetes). Separate bridge networks are Docker's isolation mechanism
11Dedicated IoT VLAN (30)IoT on Home VLAN (1)IoT devices lack updates, are botnet targets (Mirai). Shared broadcast domain enables ARP spoofing. Home→IoT allowed, IoT→Home denied
12Trivy scanning in Phase 1Defer to Phase 5Supply chain attacks in container images are a rising threat. Weekly scans catch newly disclosed CVEs before exploitation
13Suricata NIDS (Phase 5)CrowdSec aloneCrowdSec is log-based (reactive). Suricata analyzes packet traffic in real-time, detecting exfiltration patterns log parsers miss
14Pi-hole aggressive blocklistsDefault blocklists onlyDNS sinkholing prevents compromised devices from contacting C2 servers. Covers insider threat / negligent user vector
15Dual Docker socket proxySingle proxy for allTraefik only needs read; Portainer needs write. Separate proxies enforce least privilege and limit blast radius
16CF Access + Authelia dual-layerSingle layer authCloudflare protects edge (.sanchezfamily.ca) but not .home; Authelia protects both. Independent layers
17Circuit Breaker middlewareNo backend error detectionHigh 5xx ratios indicate exploitation. Circuit breaker halts traffic and triggers CrowdSec investigation
18Grafana monitoring in Phase 1Defer to Phase 4Already deployed but unconfigured. Adding Prometheus/Loki in Phase 1 provides immediate visibility into security events
19MQTT broker for IoT ↔ HADirect device-to-deviceER605 stateless ACLs make bidirectional IoT traffic unreliable. MQTT on Rod-Server bridges HA↔IoT without direct network paths
20Database TLS in Phase 1 (not Phase 3)Wait for WireGuard tunnelOnce WireGuard decapsulates, traffic hits Docker network unencrypted. Application-layer TLS provides defense-in-depth if VPN layer is bypassed or Docker network is compromised
21IoT DNS rate-limiting (Option B)Secondary Pi-hole (Option A)Option B is lower complexity for initial deployment. VLAN 30→VLAN 20 ACL must be UDP 53 only with rate limiting. Option A deferred to Phase 5
22Suricata on WireGuard interfaceSuricata on all interfaceswg0 is the DMZ↔Internal choke point — captures all cross-zone traffic with minimal performance impact. CrowdSec handles HTTP (L7); Suricata handles packets (L3/4)
23Image digest pinningTag-based pulls:latest is mutable — a compromised registry can substitute a malicious image. Pinning by @sha256:... ensures immutability. Added to Phase 2
24Local-first, Cloudflare-complementaryFull Cloudflare dependencyPi-hole, WireGuard, Authelia work offline. Cloudflare Tunnel/Access/WARP are edge enhancements, not replacements. Preserves functionality during internet outages

Appendix A: Incident Response Playbook

Aligned with NIST SP 800-61 (Computer Security Incident Handling Guide) adapted for single-admin home infrastructure.

A.1 Preparation (Pre-Incident)

A.2 Identification (Is This an Incident?)

Indicators of Compromise (IoCs) to check:

CategoryWhat to Look ForCommand
Unauthorized containersUnknown images runningdocker ps --format "{{.Names}} {{.Image}}"
Unusual processesUnexpected listeners, minersss -tlnp, top -bn1 | head -20
SSH compromiseUnknown authorized_keyscat ~/.ssh/authorized_keys
Persistence mechanismsUnknown cron jobs, servicescrontab -l, systemctl list-units --type=service
Modified system filesChanged binariesdebsums -c 2>/dev/null | head -20
Network anomaliesOutbound to unknown IPsss -tnp | grep ESTABLISHED
CrowdSec alertsRecent bans/alertscscli alerts list
Authelia logsFailed/unusual loginsdocker logs authelia --since 24h

A.3 Containment (Stop the Bleeding)

Immediate (< 5 minutes):

Short-term (< 1 hour):

A.4 Eradication (Remove the Threat)

A.5 Recovery (Restore Normal Operations)

A.6 Lessons Learned & Notification (Post-Incident)

A.7 Authelia Lockout Recovery

If locked out of Authelia (lost TOTP device):
  1. SSH directly to Rod-Server (SSH does not go through Authelia)
  2. Edit docker/authelia/config/users_database.yml to reset password
  3. Delete TOTP registration from Authelia SQLite DB
  4. Restart Authelia container
  5. Re-enroll TOTP

A.8 LUKS Emergency Decryption

sudo cryptsetup luksOpen /dev/mapper/encrypted-data recovery --key-file /path/to/recovery.key

Sanchez Home Network Security Plan v1.3.0 — Generated 2026-02-15

Authoritative reference: /home/rod/_rod/SECURITY_HARDENING_PLAN.md

v1.3.0 changes: Phase 1 marked COMPLETE — Traefik hardening middleware (rate-limit, body-limit, circuit-breaker, secure-chain, sniStrict, ECDSA ciphers, serversTransport timeouts), MariaDB TLS (require_secure_transport=ON, TLS_AES_256_GCM_SHA384), PostgreSQL TLS (TLSv1.3), Trivy v0.69.1 weekly scanning, Pi-hole blocklists expanded to 1,442,496 domains (6 new C2/malware/phishing feeds), 11 container images pinned by SHA256 digest. Phase 2 now IN PROGRESS with 10.0.1.5 DMZ cleanup underway (tunnel ID f49ac13d-2108-4170-8052-457167417bae).

v1.2.0 changes: Database TLS moved to Phase 1 (critique A), IoT DNS pinhole risk documented (critique B), Suricata placement specified on wg0 (critique C), image digest pinning added (critique D), Cloudflare One integration matrix added (Section 4.3), breach notification added to incident response, Portainer Agent alternative documented.

Literature: Cyber Kill Chain (Nagar & Kumar, 2025) • Traefik API Gateway (Sharma & Mathur, 2021) • Serverless Apps on Cloudflare (Peacock, 2024) • End-to-End Observability with Grafana (Yeruva & Ramu, 2023) • What Is Portainer? (Peter, 2023) • AI Applications in Cyber Security (Hewage et al., 2025) • Cyber Risk Management in Practice (Morales, 2026) • NIST SP 800-61 (Computer Security Incident Handling Guide)

Back to Sanchez Home Network