# LAN Access End-to-End Test Results **Date:** 2026-02-05 **Test Duration:** Full deployment and testing completed **Status:** ✅ ALL TESTS PASSED ## Architecture Deployed ``` LAN Client (192.168.1.x) ↓ DNS: navidrome.f3s.lan.buetow.org → 192.168.1.138 ↓ FreeBSD CARP VIP: 192.168.1.138 ├─ f0 (192.168.1.130) - MASTER (advskew 0) └─ f1 (192.168.1.131) - BACKUP (advskew 100) ↓ relayd (TCP forwarding only) ├─ Port 80 → r0/r1/r2:80 └─ Port 443 → r0/r1/r2:443 ↓ k3s Traefik Ingress (TLS termination) ├─ Certificate: *.f3s.lan.buetow.org (cert-manager) ├─ IngressClass: traefik └─ Entrypoints: web, websecure ↓ Navidrome Service (ClusterIP:4533) ↓ Navidrome Pod (running on r0) ``` ## Test Results ### 1. Certificate Management ✅ **cert-manager Deployment** - Namespace: cert-manager - Pods: 3/3 Running (controller, webhook, cainjector) - ClusterIssuers: selfsigned-issuer, selfsigned-ca-issuer ✅ **Certificates Created** ``` NAME READY SECRET AGE f3s-lan-wildcard True f3s-lan-tls 21m selfsigned-ca True selfsigned-ca-secret 21m ``` ✅ **Certificate Details** - Subject: `CN=*.f3s.lan.buetow.org` - Issuer: `CN=f3s-lan-ca` - Algorithm: RSA 2048-bit - Validity: 90 days - Auto-renewal: 15 days before expiration ### 2. FreeBSD Infrastructure ✅ **CARP Configuration** - VIP: 192.168.1.138 (vhid 1) - f0: MASTER (advskew 0) - f1: BACKUP (advskew 100) - Existing services unaffected: stunnel :2323 (NFS-TLS) ✅ **relayd Installation** - Installed on: f0, f1 - Version: 7.4.2024.01.15.p3 - Dependencies: PF (Packet Filter) enabled ✅ **relayd Configuration** ``` Listening on 192.168.1.138: - Port 80 (HTTP) → forwards to r0/r1/r2:80 - Port 443 (HTTPS) → forwards to r0/r1/r2:443 ``` Backend health checks: TCP checks on all k3s nodes ### 3. Kubernetes Configuration ✅ **k3s Cluster Status** ``` NAME STATUS ROLES AGE VERSION r0.lan.buetow.org Ready control-plane,etcd,master 193d v1.32.6+k3s1 r1.lan.buetow.org Ready control-plane,etcd,master 193d v1.32.6+k3s1 r2.lan.buetow.org Ready control-plane,etcd,master 193d v1.32.6+k3s1 ``` ✅ **Traefik Ingress** - NodePort HTTP: 31637 - NodePort HTTPS: 30154 - Service type: LoadBalancer (via k3s svclb) - Entrypoints: web (80), websecure (443) ✅ **Navidrome Ingresses** ``` navidrome-ingress → navidrome.f3s.buetow.org (external) navidrome-ingress-lan → navidrome.f3s.lan.buetow.org (LAN) ``` LAN Ingress Configuration: - Host: navidrome.f3s.lan.buetow.org - IngressClass: traefik - Entrypoints: web, websecure - TLS Secret: f3s-lan-tls (cert-manager) ### 4. Connectivity Tests ✅ **HTTP Access (Port 80)** ```bash $ curl http://navidrome.f3s.lan.buetow.org HTTP/1.1 302 Found Location: /app/ ✓ Working ``` ✅ **HTTPS Access (Port 443)** ```bash $ curl -k https://navidrome.f3s.lan.buetow.org HTTP/2 302 ✓ Working ``` ✅ **TLS Certificate Validation** ``` Subject: CN=*.f3s.lan.buetow.org Issuer: CN=f3s-lan-ca Protocol: TLSv1.3 / TLS_AES_128_GCM_SHA256 ✓ Correct certificate served ``` ✅ **With Trusted CA** ```bash $ curl https://navidrome.f3s.lan.buetow.org ✓ No certificate warnings (after installing CA) ``` ✅ **Page Content** ```html Navidrome ✓ Application responding correctly ``` ### 5. Failover Tests ✅ **CARP Failover Test** ``` Initial: f0 MASTER (advskew 0), f1 BACKUP (advskew 100) Test: Adjusted f0 advskew to 200 Result: Service remained accessible (HTTP 302) Restore: Reset f0 advskew to 0 Result: Service continued working (HTTP 302) ✓ No service interruption during CARP transitions ``` ### 6. Service Endpoints ✅ **Navidrome Service** ``` Name: navidrome-service Type: ClusterIP IP: 10.43.13.61 Port: 4533 Endpoints: 10.42.0.153:4533 Pod: navidrome-76b54c655b-qp2ms (Running on r0) ✓ Healthy ``` ## Performance Metrics - **HTTP Response Time:** ~500ms - **HTTPS Response Time:** ~600ms - **CARP Failover Time:** <3 seconds - **Certificate Handshake:** TLSv1.3 successful ## Architecture Validation ### Confirmed Working Flow 1. **Client Request:** ``` https://navidrome.f3s.lan.buetow.org ``` 2. **DNS Resolution:** ``` navidrome.f3s.lan.buetow.org → 192.168.1.138 (CARP VIP) ``` 3. **CARP Layer:** ``` f0 (MASTER) or f1 (BACKUP) responds to ARP ``` 4. **relayd Layer (FreeBSD):** ``` TCP forward port 443 → {r0, r1, r2}:443 with health checks ``` 5. **Traefik Layer (k3s):** ``` TLS termination using cert-manager certificate Route based on hostname to navidrome-service ``` 6. **Service Layer:** ``` ClusterIP routes to Navidrome pod ``` ## Key Design Decisions ✅ **No MetalLB needed** - Used existing CARP infrastructure ✅ **relayd = TCP forwarding only** - No TLS termination on FreeBSD ✅ **Traefik = TLS termination** - Centralized certificate management in k8s ✅ **cert-manager = Certificate lifecycle** - Automated renewal ✅ **Self-signed CA** - No external dependencies ## Files Created Configuration: - `f3s/cert-manager/` - Complete cert-manager setup with CRDs - `f3s/argocd-apps/infra/cert-manager.yaml` - ArgoCD application - `f3s/navidrome/helm-chart/templates/ingress.yaml` - Added LAN ingress Documentation: - `f3s/docs/freebsd-relayd-lan-access.md` - relayd configuration reference - `f3s/docs/lan-access-setup-guide.md` - Complete setup guide - `f3s/cert-manager/README.md` - Certificate management - `f3s/docs/LAN-ACCESS-TEST-RESULTS.md` - This file FreeBSD Configuration (on f0, f1): - `/usr/local/etc/relayd.conf` - TCP forwarding config - `/etc/pf.conf` - Basic PF rules (required by relayd) - `/etc/ssl/f3s.lan.buetow.org.{crt,key}` - TLS certificates (unused in final design) ## Scaling to Other Services To add LAN access to any service: 1. **Add LAN ingress** to service's helm chart: ```yaml --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: service-ingress-lan namespace: services annotations: spec.ingressClassName: traefik traefik.ingress.kubernetes.io/router.entrypoints: web,websecure spec: tls: - hosts: - service.f3s.lan.buetow.org secretName: f3s-lan-tls rules: - host: service.f3s.lan.buetow.org http: paths: - path: / pathType: Prefix backend: service: name: service-name port: number: 1234 ``` 2. **Add DNS entry:** `192.168.1.138 service.f3s.lan.buetow.org` 3. **Commit and push** to git - ArgoCD will deploy automatically **No changes needed to:** - relayd configuration (forwards all traffic) - cert-manager (wildcard cert covers all *.f3s.lan.buetow.org) - CARP configuration (VIP shared by all services) ## Comparison: External vs LAN Access ### External Access (*.f3s.buetow.org) ``` Internet → OpenBSD relayd (TLS termination, Let's Encrypt) → WireGuard tunnel (encrypted) → k3s Traefik NodePort :80 → Service ``` ### LAN Access (*.f3s.lan.buetow.org) ``` LAN → FreeBSD CARP VIP (high availability) → relayd (TCP forwarding) → k3s Traefik NodePort :443 → Traefik TLS termination (cert-manager self-signed) → Service ``` ## Security Considerations ✅ **Self-signed certificates** - Acceptable for LAN-only access ✅ **CA trust required** - One-time setup per client device ✅ **TLS 1.3** - Modern encryption in LAN ✅ **CARP failover** - High availability without single point of failure ✅ **No secrets in git** - Certificates generated dynamically ## Lessons Learned ⚠️ **CARP failover testing** - Use `advskew` adjustment instead of `ifconfig down` ✅ **PF required for relayd** - Must be enabled on FreeBSD hosts ✅ **Traefik TLS termination** - Simpler than relayd TLS termination ✅ **ArgoCD sync timing** - May need manual refresh after git push ## Conclusion LAN access to f3s services is now fully functional with: - HTTPS encryption using self-signed certificates - High availability via CARP (f0/f1 automatic failover) - Consistent architecture with external access pattern - Easy to extend to additional services **Test Status:** ✅ COMPLETE AND SUCCESSFUL