Scenario 04 · Data-sovereignty edge

"Our customers' data may not leave EU jurisdiction. Full stop."

A SaaS serves European customers under GDPR, and post-Schrems II its DPA forbids exposing personal data to non-EU jurisdiction — including the moment of TLS termination, where a provider sees plaintext. But the engineering team's backends, CI, and data stores live wherever it's cheapest. They need the edge — termination and request processing — provably inside the EU, while the rest of the stack stays portable.

Architecture

TLS dies in the EU; backends stay portable

EU JURISDICTION · Falkenstein, DE data plane & TLS termination stay in-EU Client (EU) PQ-capable ZenoIngress Edge TLS terminate PQC · prefer-pq :443 / :7844 plaintext only here Origin proxy mode: tunnel outbound only any region no inbound ports Backends services TLS1.3+PQC requests → yamux · mTLS

The origin opens the tunnel outbound, so the backend network needs no inbound firewall holes. TLS terminates only at the EU edge — no third party, and no US entity, ever sees plaintext.

The setup

An EU edge, and an origin that dials out

Stand up the edge on EU infrastructure (here, a Hetzner VM in Falkenstein). It runs the data plane on :443 and the tunnel control plane on :7844:

deploy-edge.sh EU region · Hetzner
# Edge VM in Germany — terminates TLS inside EU jurisdiction
hcloud server create \
  --name edge-de-1 \
  --type cx22 \
  --image zenoingress-edge \
  --location fsn1            # Falkenstein, DE

# Edge exposes:  :443 data plane (TLS terminate, PQC)
#                :7844 control plane (tunnel registration)

Then point the in-cluster proxy at the edge in tunnel mode. The origin connects outbound, authenticating with a token and a client certificate (mutual TLS) — so the edge only ever accepts a tunnel from your own proxy:

values.yaml helm · zenoingress proxy
tunnel:
  enabled: true
  edge_address: "edge-de-1.example.eu:7844"
  auth_token: "sk_prod_…"          # from a Secret
  hostnames:
    - "app.example.eu"
    - "api.example.eu"
  tls:
    enabled: true
    client_cert: /etc/zeno/tunnel/tls.crt   # mutual TLS to the edge
    client_key:  /etc/zeno/tunnel/tls.key
  reconnect_backoff: "1s..30s"        # exponential, auto-reconnect

See docs/eu_only_edge_ingress.md for a full 100%-EU stack (DNS, registrar, CDN/WAF, ACME).

What happens

Where the plaintext lives

  1. DNS resolves app.example.eu to the EU edge VM. The client opens TLS 1.3 with post-quantum key exchange directly to it.
  2. TLS terminates at the edge, inside EU jurisdiction — that's the only place plaintext ever exists. No CDN, no foreign PoP, no US entity in the path.
  3. The edge matches the request to a registered hostname and hands it to the yamux tunnel the origin already opened.
  4. That tunnel runs outbound from the origin and is authenticated by token + client certificate, so the backend cluster opens no inbound ports at all. NAT-friendly
  5. The origin proxy delivers the request to backends in any region; the response returns up the same tunnel. If the link drops it auto-reconnects with backoff.

Outcome

TLS and processing provably in-EU

EU-onlytermination & processing
0 inboundports on the backend network
portablebackends run in any region
Why ZenoIngress

You own the edge that terminates TLS, so plaintext and processing stay pinned to EU jurisdiction — with an outbound, mTLS-authenticated tunnel that keeps backends portable and the origin network sealed.

Run this yourself

Confirm the edge is yours, in the EU

Once the tunnel is up, the certificate the client sees is issued for your domain by the EU edge — not a third party's — and the edge resolves to an EU address:

terminal — verify jurisdiction at the edge
$ # the tunnel is registered and serving
$ curl -sI https://app.example.eu | head -1
HTTP/2 200

$ # TLS terminates at YOUR EU edge — check the issuer + the IP
$ echo | openssl s_client -connect app.example.eu:443 \
      -servername app.example.eu 2>/dev/null | openssl x509 -noout -issuer
issuer=C=IT, O=Actalis S.p.A., CN=Actalis Domain Validation CA

$ dig +short app.example.eu
5.75.xxx.xxx   # Hetzner, Falkenstein (DE)

Keep the plaintext in the EU.

An edge you own, a tunnel that dials out. Free for one production cluster.

Deploy Free