; Pelagos Blog — a 3-service web stack
;
; Architecture:
;
; frontend (10.88.1.0/24): proxy ←→ app
; backend (10.88.2.0/24): app ←→ redis
;
; The proxy and redis share no network — they cannot communicate
; directly. The app container bridges both, acting as the only
; conduit between the public-facing tier and the data tier.
;
; DNS service discovery lets nginx resolve "app" and lets the
; Python API resolve "redis" — no IP addresses anywhere.
(compose
;; ── Networks ──────────────────────────────────────────────────
;;
;; Two isolated subnets. Only the app service straddles both.
(network frontend (subnet "10.88.1.0/24"))
(network backend (subnet "10.88.2.0/24"))
;; ── Volumes ───────────────────────────────────────────────────
(volume notes-data)
;; ── Services ──────────────────────────────────────────────────
;; Redis — data store, backend only.
;; No port published to the host; reachable only from the
;; backend network as "redis:6379".
(service redis
(image "web-stack-redis:latest")
(network backend)
(memory "64m"))
;; App — Python/Bottle REST API.
;; Bridges both networks: talks to redis on the backend,
;; receives proxied requests from nginx on the frontend.
;; Waits for redis to accept TCP connections before starting.
(service app
(image "web-stack-app:latest")
(network frontend backend)
(depends-on (redis :ready-port 6379))
(env REDIS_HOST "redis")
(env REDIS_PORT "6379")
(memory "128m")
(cpus "0.5"))
;; Proxy — nginx reverse proxy, frontend only.
;; Serves static HTML at / and forwards /api/* and /health
;; to the app service via DNS name "app".
;; Published on host port 8080; waits for app to be ready.
(service proxy
(image "web-stack-proxy:latest")
(network frontend)
(depends-on (app :ready-port 5000))
(port 8080 80)
(memory "32m")))