Caddy Reverse Proxy & Security
Relevant source files
The following files were used as context for generating this wiki page:
Caddy serves as the primary entry point for the Nyansa stack, providing reverse proxy services and automatic HTTPS termination. It routes external traffic to the internal nyansa-open-webui and nyansa-n8n services while keeping other components like PostgreSQL, Qdrant, and the memory-api isolated from the public internet.
Sources: README.md:16-17, README.md:46-52
Access Profiles
The system implements two distinct access modes via Docker Compose profiles. Only one profile should be active at a time to manage how users reach the services.
Public Profile
The public profile configures the nyansa-caddy-public container to listen on standard HTTP (80) and HTTPS (443) ports. It utilizes Let's Encrypt for automatic certificate management and applies HTTP Basic Authentication in front of the n8n editor.
Tailscale Profile
The tailscale profile provides private access without publishing any ports on the host. It uses a nyansa-tailscale sidecar container to join a Tailnet. The nyansa-caddy-tailscale container shares the network namespace of the Tailscale container and fetches certificates for the Tailnet domain.
Sources: docker-compose.yml:256-318, README.md:111-113
This diagram illustrates the separation of access methods and the routing to internal services.
Sources: README.md:46-77, docker-compose.yml:256-318
Network Isolation and Port Exposure
Nyansa enforces strict network isolation to minimize the attack surface. Only Caddy is reachable from outside the Docker environment in a default public deployment.
- Loopback Binding:
nyansa-n8nandnyansa-open-webuibind their ports to127.0.0.1. This prevents direct external access, forcing all traffic through Caddy or SSH tunnels. - Internal Services: PostgreSQL, Qdrant, Ollama, and
memory-apido not publish any ports. They reside exclusively on the internalnyansaDocker network. - Validation: The
scripts/check-exposure.shutility verifies these rules across all 9 possible profile combinations.
| Service | Host Port | Internal Port | Access Method |
|---|---|---|---|
| Caddy (Public) | 80, 443 | 80, 443 | Public Internet |
| Open WebUI | 127.0.0.1:3000 | 8080 | Proxy / Local Only |
| n8n Editor | 127.0.0.1:5678 | 5678 | Proxy / Local Only |
| Qdrant | None | 6333 | Internal Only |
| memory-api | None | 8080 | Internal Only |
| PostgreSQL | None | 5432 | Internal Only |
Sources: README.md:104-110, docker-compose.yml:138-140, docker-compose.yml:190-192, scripts/check-exposure.sh:35-51
Internal Service Authentication
Beyond network isolation, internal services use additional security layers to prevent unauthorized lateral movement within the Docker network.
Memory API Security
The memory-api requires a Bearer token for all requests except /health. It validates tokens using constant-time comparison via timingSafeEqual to prevent timing attacks.
Sources: services/memory-api/src/app.ts:54-66, services/memory-api/README.md:12-13
Qdrant and n8n
Qdrant is protected by an API key. To ensure n8n can communicate with it securely, the key is injected at runtime into n8n credentials using the CREDENTIALS_OVERWRITE_DATA environment variable. This avoids storing the secret within n8n's persisted database or Git.
Sources: README.md:118-119, docker-compose.yml:61-62
Internal request flow demonstrating layered authentication between the reverse proxy and backend services.
Sources: services/memory-api/src/app.ts:54-66, services/memory-api/README.md:65-74
Security Hardening Measures
The stack implements several container-level hardening techniques to restrict the impact of potential vulnerabilities:
- Non-Root Execution: Services like
memory-apirun as non-root users. - Read-Only Filesystems: The
nyansa-memory-apicontainer has its root filesystem mounted asread_only: true. - Capability Dropping: All Linux capabilities are dropped for the
memory-api(cap_drop: [ALL]), andno-new-privilegesis set to true. - Volume Constraints: The Obsidian vault is mounted as a read-only volume (
:ro) to thememory-apito prevent accidental or malicious modifications.
Sources: README.md:106-107, docker-compose.yml:228-231, docker-compose.yml:241-242
Summary
The Nyansa security architecture relies on a multi-layered approach: Caddy provides a secure HTTPS entry point with managed access profiles, Docker network isolation prevents direct exposure of backend services, and service-level authentication ensures that even internal communication is authorized. Hardening measures like read-only filesystems and capability dropping provide a final layer of defense-in-depth.