monorepo/cloud/infrastructure/production/setup/00-network-architecture.md

11 KiB

Network Architecture Overview

This document explains the network strategy for Maple Open Technologies production infrastructure.

See Also: 00-multi-app-architecture.md for application naming conventions and multi-app strategy.

Network Segmentation Strategy

We use a multi-network architecture following industry best practices for security and isolation. This infrastructure supports multiple independent applications (MaplePress, MapleFile) sharing common infrastructure.

Network Topology

┌─────────────────────────────────────────────────────────────────┐
│                    Docker Swarm Cluster                          │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │  maple-private-prod (Overlay Network)                      │ │
│  │  No Internet Access | Internal Services Only               │ │
│  │  SHARED by ALL applications                                │ │
│  ├────────────────────────────────────────────────────────────┤ │
│  │  Infrastructure Services:                                  │ │
│  │    ├── Cassandra (3 nodes) - Shared database cluster      │ │
│  │    ├── Redis - Shared cache                               │ │
│  │    └── Meilisearch - Shared search                        │ │
│  │                                                            │ │
│  │  Application Backends (Join BOTH Networks):               │ │
│  │    ├── maplepress-backend:8000                            │ │
│  │    ├── maplefile-backend:8000 (future)                    │ │
│  │    └── mapleopentech-backend:8000 (future)                    │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                  │
│  ┌────────────────────────────────────────────────────────────┐ │
│  │  maple-public-prod (Overlay Network)                       │ │
│  │  Internet-Facing | Public Services                         │ │
│  ├────────────────────────────────────────────────────────────┤ │
│  │  Reverse Proxies (Caddy - ports 80/443):                  │ │
│  │    ├── maplepress-backend-caddy (getmaplepress.ca)        │ │
│  │    ├── maplepress-frontend-caddy (getmaplepress.com)      │ │
│  │    ├── maplefile-backend-caddy (maplefile.ca)             │ │
│  │    ├── maplefile-frontend-caddy (maplefile.com)           │ │
│  │    └── ... (future apps)                                  │ │
│  │                                                            │ │
│  │  Application Backends (Join BOTH Networks):               │ │
│  │    ├── maplepress-backend:8000                            │ │
│  │    ├── maplefile-backend:8000 (future)                    │ │
│  │    └── mapleopentech-backend:8000 (future)                    │ │
│  └────────────────────────────────────────────────────────────┘ │
│                                                                  │
│  Note: Application backends join BOTH networks:                 │
│  - Receive requests from Caddy on maple-public-prod             │
│  - Access databases/cache on maple-private-prod                 │
└─────────────────────────────────────────────────────────────────┘

Networks Explained

1. maple-private-prod (Current)

Purpose: Backend services that should NEVER be exposed to the internet.

Characteristics:

  • Overlay network (Docker Swarm managed)
  • No ingress ports exposed
  • No public IP access
  • Service-to-service communication only

Services:

  • Cassandra cluster (3 nodes - shared database) - databases never touch internet
  • Redis (shared cache layer)
  • Meilisearch (shared search engine)
  • All application backends (maplepress-backend, maplefile-backend, mapleopentech-backend)

Security Benefits:

  • Attack surface minimization
  • No direct internet access to databases
  • Compliance with data protection regulations (PCI-DSS, HIPAA, SOC2)
  • Defense in depth architecture

Service Discovery:

# Services can reach each other by hostname
redis:6379
cassandra-1:9042
cassandra-2:9042
cassandra-3:9042

2. maple-public-prod (Current - In Use)

Purpose: Internet-facing services that handle external traffic.

Characteristics:

  • Overlay network with ingress
  • Ports 80/443 exposed to internet
  • TLS/SSL termination via Caddy
  • Automatic Let's Encrypt certificates
  • Rate limiting and security headers

Services:

  • Caddy reverse proxies (one per app component):
    • maplepress-backend-caddy → serves getmaplepress.ca → proxies to maplepress-backend:8000
    • maplepress-frontend-caddy → serves getmaplepress.com → static React files
    • maplefile-backend-caddy (future) → serves maplefile.ca → proxies to maplefile-backend:8000
    • maplefile-frontend-caddy (future) → serves maplefile.com → static React files
  • All application backends (join both networks):
    • maplepress-backend
    • maplefile-backend (future)
    • mapleopentech-backend (future)

Routing Flow:

Internet → Caddy Reverse Proxy (maple-public-prod)
         → Application Backend (maple-public-prod + maple-private-prod)
         → Databases/Cache (maple-private-prod only)

Example (MaplePress):
https://getmaplepress.ca → maplepress-backend-caddy
                         → maplepress-backend:8000
                         → cassandra/redis/meilisearch

Why This Architecture?

Industry Standard

This pattern is used by:

  • Netflix: backend-network + edge-network
  • Spotify: data-plane + control-plane
  • AWS: VPC with private-subnet + public-subnet
  • Google Cloud: VPC with internal + external networks

Security Benefits

  1. Defense in Depth: Multiple security layers
  2. Least Privilege: Services only access what they need
  3. Attack Surface Reduction: Databases never exposed to internet
  4. Network Segmentation: Compliance requirement for SOC2, PCI-DSS
  5. Blast Radius Containment: Breach of public network doesn't compromise data layer

Operational Benefits

  1. Clear Boundaries: Easy to understand what's exposed
  2. Independent Scaling: Scale public/private networks separately
  3. Flexible Firewall Rules: Different rules for different networks
  4. Service Discovery: DNS-based discovery within each network
  5. Testing: Can test private services without public exposure

Network Creation

Current Setup

Both networks are created and in use:

# Create private network (done in 02_cassandra.md - shared by ALL apps)
docker network create \
  --driver overlay \
  --attachable \
  maple-private-prod

# Create public network (done in 06_caddy.md - used by reverse proxies)
docker network create \
  --driver overlay \
  --attachable \
  maple-public-prod

# Verify both exist
docker network ls | grep maple
# Should show:
# maple-private-prod
# maple-public-prod

Multi-App Pattern

  • All application backends join BOTH networks
  • Each app gets its own Caddy reverse proxy instances
  • Infrastructure services (Cassandra, Redis, Meilisearch) only on private network
  • Shared efficiently: 5 infrastructure workers serve unlimited apps

Service Connection Examples

Go Backend Connecting to Services

On maple-private-prod network:

// Redis connection
redisClient := redis.NewClient(&redis.Options{
    Addr: "redis:6379",  // Resolves via Docker DNS
    Password: os.Getenv("REDIS_PASSWORD"),
})

// Cassandra connection
cluster := gocql.NewCluster("cassandra-1", "cassandra-2", "cassandra-3")
cluster.Port = 9042

Docker Stack File for Backend:

version: '3.8'

services:
  backend:
    image: your-backend:latest
    networks:
      - maple-private-prod  # Access to databases
      - maple-public-prod   # Receive HTTP requests (when deployed)
    environment:
      - REDIS_HOST=redis
      - CASSANDRA_HOSTS=cassandra-1,cassandra-2,cassandra-3

networks:
  maple-private-prod:
    external: true
  maple-public-prod:
    external: true

Firewall Rules

Private Network

# On worker nodes
# Only allow traffic from other swarm nodes (10.116.0.0/16)
sudo ufw allow from 10.116.0.0/16 to any port 2377 proto tcp  # Swarm
sudo ufw allow from 10.116.0.0/16 to any port 7946           # Gossip
sudo ufw allow from 10.116.0.0/16 to any port 4789 proto udp  # Overlay
sudo ufw allow from 10.116.0.0/16 to any port 6379 proto tcp  # Redis
sudo ufw allow from 10.116.0.0/16 to any port 9042 proto tcp  # Cassandra

Public Network (Caddy Nodes)

# On workers running Caddy (worker-6, worker-7, worker-8, worker-9, etc.)
sudo ufw allow 80/tcp   # HTTP (Let's Encrypt challenge + redirect to HTTPS)
sudo ufw allow 443/tcp  # HTTPS (TLS/SSL traffic)

Troubleshooting

Check Which Networks a Service Uses

# Inspect service networks
docker service inspect your_service --format '{{.Spec.TaskTemplate.Networks}}'

# Should show network IDs
# Compare with: docker network ls

Test Connectivity Between Networks

# From a container on maple-private-prod
docker exec -it <container> ping redis
docker exec -it <container> nc -zv cassandra-1 9042

# Should work if on same network

View All Services on a Network

docker network inspect maple-private-prod --format '{{range .Containers}}{{.Name}} {{end}}'

Migration Path

Current Status

  • maple-private-prod created
  • Cassandra on maple-private-prod
  • Redis on maple-private-prod
  • Backend deployment (next)
  • Public network + NGINX (future)

When to Create maple-public-prod

Create the public network when you're ready to:

  1. Deploy NGINX reverse proxy
  2. Set up SSL/TLS certificates
  3. Expose your application to the internet

Until then, all services run on the private network only.


Last Updated: November 3, 2025 Status: Active Architecture Maintained By: Infrastructure Team