elfatih.net infrastructure · api.elfatih.net · originally 2026-07-20 · updated 2026-07-22

API Gateway Deployment Plan // APISIX

VPS  ·  Caddy edge  ·  Authelia SSO  ·  Public internet  ·  Browser users
Status — 2026-07-22: This was the original proposal. Phase 1 is now done and live in production — real containers, real TLS, real bugs found and fixed along the way. This page is kept as-is for the original reasoning and phase template; for what was actually built (and where it diverged from this plan), see the Implementation Guide and the Testing & Deployment Guide.

Tool Recommendation: APISIX

ReasonDetail
Dashboard UIBuilt-in APISIX Dashboard — covers the UI requirement
Authelia integrationNative OIDC via openid-connect plugin
LightweightRuns well on a single VPS, less overhead than Kong DB mode
Greenfield fitDeclarative config + Admin API — easy to automate
Coraza WAFOfficial APISIX plugin — drops in when you're ready
WazuhConsume APISIX JSON logs via filebeat — zero redesign
GovernanceApache foundation, no enterprise-gated features

Architecture

Traffic Flow

Browser
  │
  │  HTTPS :443
  ▼
Cloudflare
  ├─ DDoS protection
  ├─ DNS-01 cert
  └─ Proxied — hides VPS origin IP
  │
  │  HTTPS (full strict mode)
  ▼
Caddy on VPS :443
  ├─ TLS termination
  ├─ api.elfatih.net        → APISIX :9080
  └─ dashboard.elfatih.net  → APISIX Dashboard :9000 (behind Authelia)
  │
  │  HTTP (internal, localhost)
  ▼
APISIX :9080
  ├─ OIDC plugin → validates session against Authelia
  ├─ Rate limiting · routing · transformations · health checks
  └─ Routes to upstream services
  │
  │  HTTP (internal only)
  ▼
Upstream Services  (bind to 127.0.0.1:PORT — never exposed directly)

Component Responsibilities

ComponentOwnsDoes NOT do
CloudflareDDoS, CDN, DNS, origin IP hidingAuthN, routing logic
CaddyTLS, virtual hosting, forward-authBusiness routing, rate limiting
AutheliaSSO, OIDC provider, MFAPer-route policies
APISIXRouting, AuthN enforcement, policiesTLS (Caddy handles it)
UpstreamsBusiness logicAuth, rate limiting

Network Boundaries

ZoneConnections
PublicCloudflare → Caddy :443 only
InternalCaddy → APISIX :9080, Authelia :9091, Dashboard :9000
UpstreamAPISIX → Services on localhost:PORT
Admin (locked)APISIX Admin API :9180 — 127.0.0.1 ONLY, never routed
Critical: APISIX Admin API must never be routed through Caddy. It has no auth by default. One misconfigured Caddy block exposes full gateway control to the internet. Access only via SSH tunnel if needed remotely.

Auth Flow — End User

1. Browser → api.elfatih.net/some-endpoint
2. Caddy receives, passes to APISIX
3. APISIX openid-connect plugin checks for valid session / Bearer token
4. No valid session → redirect to Authelia login page
5. User authenticates at Authelia (MFA if configured)
6. Authelia issues OIDC token, redirects back to api.elfatih.net
7. APISIX validates token, extracts identity (sub, email, roles)
8. Request forwarded to upstream with X-User headers injected
9. Upstream trusts headers — does NOT re-authenticate

Dashboard Access Flow

1. Browser → dashboard.elfatih.net
2. Caddy forward-auth check → Authelia
3. Not authenticated → Authelia login
4. Authenticated → Caddy proxies to APISIX Dashboard :9000
5. Dashboard has its own login — change default credentials immediately

Two auth layers: Authelia stops internet noise. Dashboard login stops lateral movement if Authelia is ever bypassed.

Data Store: etcd

Phase Plan

PHASE 1 Foundation — Day 1–2 ✓ Done — Live in production
Goal: APISIX running, dashboard accessible, integrated with Caddy.
  1. Deploy APISIX via Docker Compose (apisix + etcd + apisix-dashboard)
  2. Configure Caddy: api.elfatih.net → APISIX :9080, dashboard.elfatih.net → :9000 behind Authelia
  3. Verify Admin API NOT exposed publicly (127.0.0.1 only)
  4. Test route to placeholder upstream (httpbin) — confirm end-to-end TLS
Deliverable: APISIX live, dashboard behind Authelia, test route responding. Achieved — also grew to include a fourth vhost (learn.elfatih.net), a git repo, and a 25-test automated suite not in the original scope. Details in the guides linked above.
PHASE 2 Auth Layer — Day 3 → Next
Goal: End users authenticate via Authelia before hitting any route.
  1. Enable APISIX openid-connect plugin
  2. Configure against Authelia OIDC (client_id, client_secret, discovery endpoint)
  3. Apply plugin globally — all routes protected by default
  4. Whitelist public routes (health checks, etc.)
  5. Test full OIDC redirect flow end-to-end
Deliverable: No route reachable without a valid Authelia session.
PHASE 3 Core Policies — Day 4–5
Goal: Production-grade policies before any real service is onboarded.
PolicyConfig
Rate limiting1000 req/min per IP globally, per-route override
Request transformationStrip internal headers, add X-Request-ID
CORSGlobal allowed origins, per-route override
Timeout30s upstream default
Retry2 retries on 502/503
Health checksPassive, circuit breaker on 3 consecutive failures
Deliverable: Policy config documented and version-controlled in Git.
PHASE 4 Observability — Day 6
Goal: Logs and metrics ready to feed Wazuh and Grafana when implemented.
  1. Enable prometheus plugin → metrics endpoint for Grafana
  2. Enable http-logger plugin → JSON access logs to local file
  3. Log fields: request_id, upstream, status, latency, consumer (user identity)
  4. Confirm log format is Wazuh filebeat-compatible
Deliverable: Logs flowing, metrics live. Wazuh/Grafana integration = one config step later.
PHASE 5 Onboard First Service — per service, when ready
Goal: Repeatable template for each new microservice.
  1. Define upstream (host:port) in APISIX
  2. Create route (path prefix or subdomain)
  3. Apply auth plugin (inherit global or override)
  4. Apply rate limit override if needed
  5. Add health check for the upstream
  6. Test via dashboard, verify in logs
Time per service: ~30 minutes once gateway is configured.

Security Posture

LayerControl
CloudflareDDoS, DNS-01 certs, origin IP hidden
CaddyTLS termination, no direct upstream exposure
APISIXAuthN (OIDC/Authelia), rate limiting, routing
DashboardBehind Authelia — never public
Admin API127.0.0.1 only — never routed through Caddy
UpstreamsBound to 127.0.0.1 or internal network only
Future: CorazaWAF plugin — drops into APISIX at Phase 3 level
Future: WazuhConsumes APISIX JSON logs — zero redesign needed

Open Questions

  1. Auth scope — entirely private or some public routes (health, webhooks, public read API)?
  2. Identity propagation — do upstreams need user identity (email, roles) or just proof of auth?
  3. Subdomains — single api.elfatih.net with versioned paths (/v1, /v2) or separate subdomains per service?
  4. etcd backup — existing backup strategy on VPS, or design one as part of this?