Networking on Zerops
Keywords
networking, vxlan, l7 balancer, load balancer, ssl termination, 502, bad gateway, internal access, service discovery, hostname, proxy headers, x-forwarded-for, x-real-ip, bind, 0.0.0.0, localhost, round robin, health check, keepalive, nginx, connection timeout, websocket, rate limiting, access policy, basic auth, internal port, http, https
TL;DR
Zerops networking has two layers: a private VXLAN network per project (service-to-service via hostname, plain HTTP) and an L7 balancer for public traffic (SSL termination, round-robin, health checks). Apps must bind 0.0.0.0 — binding localhost causes 502. The L7 balancer is nginx-based with configurable timeouts, buffers, rate limiting, and access policies.
Architecture Overview
Per-project infrastructure:
- Private VXLAN network — isolated overlay network shared by all services
- L7 HTTP Balancer — 2 HA containers, auto-scales, domain routing + SSL
- L3 Core Balancer — IP addresses and direct port access (TCP/UDP)
Internal Networking (VXLAN)
Services in the same project communicate by hostname and internal port:
Rules:
- Always
http://— neverhttps://for internal traffic - Isolated per project — no cross-project private networking
- Service discovery is automatic — no manual network config
- VPN uses same hostnames:
http://api:3000from local machine (bothapiandapi.zeropsresolve — VPN sets up DNS search domain)
Cross-service env vars: prefix with hostname — e.g., app_API_TOKEN. Zerops auto-generates connection vars for managed services.
DO NOT use https:// for service-to-service calls — SSL terminates at the L7 balancer, internal network is already isolated.
L7 Balancer (HTTP/HTTPS)
The L7 balancer is nginx-based, deployed as 2 HA containers per project. It handles SSL/TLS termination (Let's Encrypt, auto-renewed), domain routing, round-robin load balancing with health checks, and connection pooling.
Proxy Headers
The balancer forwards client info via standard headers:
X-Forwarded-For/X-Real-IP— original client IPX-Forwarded-Proto—https(original protocol)
Your app receives plain HTTP but can inspect these headers for the real client info.
Key Default Settings
| Parameter | Default | Range | Notes |
|---|---|---|---|
worker_connections | 4000 | 1024-65535 | Simultaneous connections per worker |
keepalive_timeout | 30s | 1s-300s | Idle connection lifetime |
keepalive_requests | 100000 | 1-1000000 | Max requests per connection |
client_max_body_size | 512m | 1k-2048m | Max upload size (custom domain) |
client_header_timeout | 10s | 1s-300s | Header receive timeout |
client_body_timeout | 10s | 1s-300s | Body receive timeout |
send_timeout | 2s | 1s-300s | Response transmission timeout |
proxy_buffering | on | on/off | Buffer backend responses |
Zerops subdomain balancer: fixed 50 MB upload limit (not configurable).
Advanced Routing Features (GUI)
| Feature | Description |
|---|---|
| Redirects | 301/302/307/308 with preservePath and preserveQuery options |
| Access Policy | CIDR-based IP allow/deny lists, returns 403 on denied request |
| Rate Limiting | Per-IP or per-domain, configurable burst queue, returns 503 when exceeded |
| Basic Auth | HTTP Basic Authentication per location |
| Custom Content | Return static content with custom status code and MIME type |
502 Bad Gateway Diagnostic Checklist
Work through these steps in order:
- Binding address — App bound to
0.0.0.0? Binding127.0.0.1/localhostis the #1 cause - Port match — App listening on the port declared in
zerops.ymlports[]? - App running — Check runtime logs (
zerops_logs) for crash/startup errors - Health check — If configured, returning 2xx / exit 0? 5-minute retry window
- Readiness check — If configured, traffic only routes after it passes
- Service status — Is the service ACTIVE? (check
zerops_discover) - Timeout settings — For slow responses, increase
send_timeout(default 2s)
Common framework fixes:
Shared vs Dedicated IPv4
| Feature | Shared IPv4 | Dedicated IPv4 |
|---|---|---|
| Cost | Free | $3 / 30 days |
| Protocol support | HTTP/HTTPS only | All (TCP/UDP/HTTP) |
| Connections | Limited, shorter timeouts | Full capacity |
| Blacklist risk | Shared with other users | Isolated |
| DNS requirement | A + AAAA (both mandatory) | A only (AAAA optional) |
| SNI routing | AAAA record used for verification | Not needed |
| Production use | No | Yes |
Shared IPv4 SNI mechanism: Zerops reverse-looks-up the domain's AAAA record to verify project ownership. Without it, routing fails silently.
Cloudflare Integration Summary
- SSL mode: Always Full (strict) — "Flexible" causes redirect loops
- Shared IPv4 + proxy: DO NOT — reverse AAAA lookup breaks with Cloudflare proxy
- Best setup: IPv6-only AAAA record, Cloudflare proxied (handles IPv4 translation)
- ACME challenge: WAF skip rule for
/.well-known/acme-challenge/ - Wildcard SSL:
_acme-challenge.<domain>CNAME to<domain>.zerops.zone
Gotchas
- Binding localhost = 502: The L7 balancer connects via VXLAN IP, not localhost — always bind
0.0.0.0 - Internal HTTPS breaks things: Service-to-service must use
http://— the VXLAN network is already isolated - Subdomain 50MB cap: zerops.app subdomains have a hard 50MB upload limit — use custom domain for larger files
- send_timeout default is 2s: Slow API responses may be cut off — increase for long-running endpoints
- Cross-project networking impossible: Each project is an isolated VXLAN — use public access to bridge projects
- Shared IPv4 needs AAAA: Missing AAAA record = silent routing failure on shared IPv4
See Also
- zerops://themes/core — Traffic Flow, Binding & Networking, Port Rules
- zerops://guides/public-access — IP types, DNS setup, domain configuration
- zerops://guides/cloudflare — Cloudflare-specific DNS and SSL setup
- zerops://guides/firewall — port restrictions and outbound rules
- zerops://guides/vpn — VPN access to private network