Skip to content

Security

Layered Security Architecture

Layer 1: Cloudflare (Edge)
  DDoS protection, WAF, bot management, CDN
  SSL/TLS termination (client-facing cert)
  Rate limiting, IP obfuscation

Layer 2: UDM Firewall
  Only ports 80/443 forwarded to 192.168.50.10
  All other ports blocked from internet
  VLAN segmentation (50 gateway, 51 internal)

Layer 3: Traefik (Reverse Proxy)
  Service routing, SSL/TLS (Let's Encrypt)
  HTTP-01 challenge for public domains
  DNS-01 challenge (Cloudflare) for internal-only domains
  Trusted Cloudflare IPs for header forwarding
  Middleware: BasicAuth, rate limiting, security headers
  Access logging

Layer 4: Docker Swarm
  Overlay network isolation (public_net vs data_net)
  Docker secrets (encrypted at rest)
  Resource limits per service
  Health checks and auto-restart

Cloudflare Configuration

Setting Value Status
Proxy mode Orange cloud (proxied) All domains
SSL mode FULL End-to-end HTTPS
DDoS Automatic Active
WAF Enabled Active
Bot management Enabled Active
Real IP hidden Yes Cloudflare IPs visible instead

Traffic flow:

Client --HTTPS--> Cloudflare --HTTPS--> Traefik --HTTP--> App containers

The internal hop (Traefik to app) uses HTTP on isolated overlay networks, which is acceptable since it never leaves the host network.

Network Security

For full details on port exposure, firewall rules, and VLAN segmentation, see Networking.

Network Isolation

  • public_net: Only services needing external access via Traefik
  • data_net: Backend services connecting to databases/cache
  • Databases are never on public_net
  • Inter-service communication restricted to shared networks

Secrets Management

Docker Secrets (Swarm)

All sensitive data stored as Docker secrets (encrypted at rest in Swarm raft log):

# List secrets
docker secret ls

# Create secret
echo "value" | docker secret create my_secret -

# Services access secrets at /run/secrets/{name}

HashiCorp Vault (Centralized)

Vault provides centralized secrets management, accessible at https://vault.apps.jlwaller.com (Traefik) or http://192.168.51.30:8200 (direct, port published on data stack). KV v2 engine at secret/ path with PostgreSQL storage backend.

Key secrets stored in Vault:

  • secret/unifi/udm -- UniFi API key
  • secret/pushover -- Pushover notification credentials
  • secret/recipicity/prod/analytics -- Recipicity GA key (G-9NC4HEHCZ0)
  • secret/generationsoftrust/prod/analytics -- GoT GA key (G-2MSRPL704E)

Auto-unseal: A systemd service on dockerrr (vault-unseal) automatically checks Vault seal status every 30 seconds and unseals with Shamir keys if needed.

Best practices:

  • No hardcoded credentials in code or stack files
  • Use *_FILE environment variables pointing to /run/secrets/
  • Store API keys, tokens, and third-party credentials in Vault
  • Rotate secrets on a 90-day schedule (see Credential Rotation)

Security Score Breakdown

Category Score Notes
Network Security 9/10 Cloudflare + proper firewall
Access Control 7/10 Could add more staging auth
Secrets Management 9/10 Docker secrets throughout
TLS/SSL 8/10 FULL mode, could upgrade to Strict
DDoS Protection 10/10 Cloudflare enterprise-grade
Rate Limiting 8/10 Cloudflare + Traefik middleware
Monitoring 9/10 29 alert rules, Prometheus -> Alertmanager -> Pushover direct, Vault auto-unseal
Port Exposure 9/10 Only 80/443 exposed

Recommendations

  1. Upgrade to Cloudflare Full (Strict) -- Use Cloudflare Origin Certificate for stricter validation
  2. Traefik dashboard auth -- Add BasicAuth even though it's internal-only (defense in depth)
  3. Cloudflare WAF tuning -- Custom rules for admin endpoints, rate limits per path

Verification Commands

# Check what ports are listening
ss -tlnp

# Verify Cloudflare proxy (should show Cloudflare IPs, not yours)
dig +short recipicity.com

# Test SSL chain
openssl s_client -connect recipicity.com:443 -servername recipicity.com </dev/null 2>/dev/null | openssl x509 -noout -issuer

# Check for redirect loops
curl -I https://recipicity.com