{
    "product": "Cenvero Stratum",
    "generated_at": "2026-08-03T07:18:48+00:00",
    "format": "cenvero-docs-v1",
    "document_count": 1,
    "documents": [
        {
            "slug": "networking/gateway-nat",
            "title": "Gateway NAT & Internet Access",
            "category": "Networking",
            "url": "https://www.stratum.cenvero.com/docs/networking/gateway-nat",
            "headings": [
                {
                    "level": 1,
                    "text": "Gateway NAT & Internet Access"
                },
                {
                    "level": 2,
                    "text": "Which nodes can do this"
                },
                {
                    "level": 2,
                    "text": "The two directions"
                },
                {
                    "level": 3,
                    "text": "Where the firewall fits"
                },
                {
                    "level": 2,
                    "text": "Publishing a service (inbound)"
                },
                {
                    "level": 2,
                    "text": "Masquerade (shared public IP)"
                },
                {
                    "level": 2,
                    "text": "Hairpin NAT (reaching your own public IP)"
                },
                {
                    "level": 3,
                    "text": "Two workloads on the same node stay on that node"
                },
                {
                    "level": 2,
                    "text": "NAT64 (IPv6-only clients)"
                },
                {
                    "level": 2,
                    "text": "ICMP / ping"
                },
                {
                    "level": 2,
                    "text": "Command reference"
                },
                {
                    "level": 2,
                    "text": "See also"
                }
            ],
            "word_count": 1766,
            "markdown": "# Gateway NAT & Internet Access\n\nA node connects your private fabric to the public internet. Tenant workloads sit on a private subnet whose addresses are not routable on the internet, while the node holds an uplink with a public IP. NAT rewrites addresses as traffic crosses that boundary, so a whole tenant subnet can reach the internet over one shared public IP and so you can publish internal services on it.\n\nTranslation happens in the kernel, in the same pass as the firewall and routing decisions, so nothing is proxied and no extra hop is added. Throughput depends on your traffic profile and hardware — measure it for your workload rather than assuming a figure.\n\nGateway NAT is opt-in. With no rules in place, source NAT is off and the data path is unchanged, so you enable internet access one subnet at a time.\n\n## Which nodes can do this\n\nAll of them. There is one kind of node: every node hosts workloads, and every\nnode can sit at the edge, translate addresses and exchange routes with your\nupstream routers.\n\nEarlier versions asked you to pick Compute or Gateway when the node was\ninstalled, and the choice could not be changed afterwards. That is gone —\nsee [Nodes](/docs/nodes). Nodes running an older version are migrated on update\nwith nothing for you to do.\n\nWhat still varies is your topology, not the software: a node needs an uplink to\nthe outside world before it can be an edge for anything, and NAT is opt-in per\nsubnet either way.\n\n## The two directions\n\nEverything on this page is one of two movements, and they use different rules.\n\n**Outbound — many workloads, one public address.** A workload opens a\nconnection to the internet. The Gateway replaces the workload's private source\naddress with its own public one, remembers the conversation, and puts the\noriginal address back on the replies. The internet sees only your public address.\nThis is **masquerade**, below.\n\n**Inbound — one public port, one internal service.** Something on the internet\nconnects to your public address on a chosen port, and the Gateway sends it to a\nspecific workload. This is a **port forward**, and it is the only way traffic\nstarts from outside; masquerade alone does not let anyone in.\n\n```\noutbound   workload ─► Gateway (source becomes public) ─► internet\ninbound    internet ─► Gateway (destination becomes the workload) ─► workload\n```\n\nThey are independent. A subnet with masquerade can reach out without publishing\nanything, and a published service works whether or not that subnet also has\nmasquerade.\n\n### Where the firewall fits\n\nNAT decides *where* a packet goes; the firewall decides *whether* it may. Both\napply — publishing a service does not exempt it from firewall policy, so an\ninbound port forward still needs a rule permitting the traffic if your default\naction is deny. Plan the two together: a forward with no matching allow rule is a\nservice that appears configured and answers nothing.\n\n## Publishing a service (inbound)\n\nA port forward maps **one public address and port** to **one workload address and\nport**. It is available through the API:\n\n```bash\ncurl -k -X POST \"$NODE/api/v1/forward\" \\\n  -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n  -d '{\"dest_ip\":\"203.0.113.10\",\"dest_port\":443,\"target_ip\":\"10.20.0.50\",\"target_port\":8443}'\n```\n\n`dest_ip` and `dest_port` are what the outside world connects to; `target_ip` and\n`target_port` are the workload that should receive it. The ports do not have to\nmatch — publishing 443 to an application listening on 8443 is normal.\n\nList and remove them the same way:\n\n```bash\ncurl -k \"$NODE/api/v1/forward\" -H \"Authorization: Bearer $TOKEN\"\ncurl -k -X DELETE \"$NODE/api/v1/forward/<id>\" -H \"Authorization: Bearer $TOKEN\"\n```\n\nOne public port goes to one target. To publish several services, add a forward\nfor each, using a different public port or a different public address.\n\n## Masquerade (shared public IP)\n\nMasquerade (source NAT) lets an entire private LAN subnet reach the internet through a single public IP. When a tenant on the subnet opens an outbound connection, the Gateway rewrites the packet's source address to the WAN interface's IP and tracks the flow; replies arriving at that public IP are translated back to the original tenant. TCP, UDP, and ICMP echo (ping) are all masqueraded.\n\nAdd a rule by giving the LAN subnet as a CIDR and the WAN egress interface:\n\n```bash\nsudo cenvero-str-ctl gateway snat add 10.50.0.0/24 --wan cnv-nic-0\n```\n\nThe public IP is taken from the WAN interface itself, so you name the interface rather than an address. The response confirms the stored rule:\n\n```json\n{\n  \"status\": \"added\",\n  \"id\": 1,\n  \"type\": \"snat\",\n  \"source_cidr\": \"10.50.0.0/24\",\n  \"interface\": \"cnv-nic-0\"\n}\n```\n\nList the NAT rules in place — this shows both masquerade rules and any published port-forwards:\n\n```bash\ncenvero-str-ctl gateway snat list\n```\n\n```json\n{\n  \"nat_rules\": [\n    {\n      \"id\": 1,\n      \"type\": \"snat\",\n      \"source_ip\": \"10.50.0.0/24\",\n      \"interface\": \"cnv-nic-0\"\n    }\n  ]\n}\n```\n\nRemove a rule by its id:\n\n```bash\nsudo cenvero-str-ctl gateway snat remove 1\n```\n\nWith no masquerade rule, outbound tenant traffic is not translated. Add one rule per LAN subnet you want to give internet access.\n\n## Hairpin NAT (reaching your own public IP)\n\nHairpin NAT (also called NAT loopback) handles the case where a tenant on the LAN reaches one of your own published services by its public address. Suppose you publish an internal service on the Gateway's public IP, and a client on the same LAN connects to that public IP instead of the internal address. Without hairpin, the server's reply would return straight to the client without passing back through the Gateway, and the connection would break.\n\nWith hairpin, the Gateway rewrites both ends of the forward packet: the destination is translated to the internal host (as with any published service), and the source is translated to the Gateway's own LAN address. The reply then comes back to the Gateway, which reverses both translations, so the client sees a consistent, working conversation.\n\nHairpin is automatic — there is no separate command. For IPv4 it engages when:\n\n- a masquerade rule covers the LAN subnet (this is what tells the Gateway its own address on that subnet), and\n- the client and the published service's target host are both on that subnet.\n\nIf there is no masquerade rule for the subnet, a published service still works normally from outside; only the same-subnet loopback case relies on hairpin. Hairpin NAT is IPv4 only. See the [API reference](/docs/api) for publishing a service with a port-forward rule.\n\n### Two workloads on the same node stay on that node\n\nThis is the case worth knowing about if you host several customers on one server.\n\nOne workload calls another's **public** address — a VPS calling an API next door,\nsay. Both addresses are on your node. That traffic is turned around **inside the\nnode**. It does not go out to your provider's router and come back.\n\nWhat that buys you:\n\n| | |\n|---|---|\n| Latency | a local hop instead of a round trip off the box |\n| Your uplink | untouched, so it stays free for traffic that genuinely leaves |\n| Provider bandwidth | not consumed — the packets never reach the provider |\n\n**It is still fully accounted.** Usage is measured in the packet path, not at the\nuplink, so both workloads are metered exactly as they would be for external\ntraffic. Bandwidth limits, shared pools, monthly quotas and the node's licensed\nspeed ceiling all apply to it. Keeping traffic local speeds it up; it does not\nmake it invisible or free.\n\nThis is not a mode you turn on — it is what happens when both addresses are on\nthe same node.\n\n> **Private addresses behave differently, on purpose.** Traffic between the\n> private networks of two *different* tenants is refused, because private\n> addresses are not reachable from outside and blocking them is real separation.\n> Public addresses are reachable from the internet by definition, so refusing the\n> local shortcut between two of them would not separate anything — it would only\n> make the same conversation slower.\n\n## NAT64 (IPv6-only clients)\n\nNAT64 lets an IPv6-only tenant reach an IPv4-only service on the internet. The client sends traffic to an IPv4 destination embedded in the well-known NAT64 prefix `64:ff9b::/96`; the Gateway translates the IPv6 packet to IPv4 (sourced from a shared IPv4 pool address) and translates the reply back to IPv6. This covers TCP and UDP.\n\nNAT64 is off by default. Turn it on by first configuring an IPv4 pool address, then enabling it:\n\n```bash\nsudo cenvero-str-ctl nat64 configure 203.0.113.10\nsudo cenvero-str-ctl nat64 enable\n```\n\nThe pool address is the public IPv4 address that translated flows are sourced from. To use a prefix other than the well-known one, pass it as a second argument:\n\n```bash\nsudo cenvero-str-ctl nat64 configure 203.0.113.10 64:ff9b::/96\n```\n\nCheck the current state and the number of active flows:\n\n```bash\ncenvero-str-ctl nat64 status\n```\n\n```json\n{\n  \"enabled\": true,\n  \"prefix\": \"64:ff9b::/96\",\n  \"v4_pool\": \"203.0.113.10\",\n  \"active_bindings\": 0,\n  \"scope\": \"TCP/UDP (ICMP + fragmentation not translated)\"\n}\n```\n\nDisable it to return the Gateway to its previous behavior:\n\n```bash\nsudo cenvero-str-ctl nat64 disable\n```\n\nNAT64 translates TCP and UDP. ICMP and fragmented datagrams are passed through untranslated rather than dropped. IPv6-only clients typically rely on a DNS64 resolver to synthesize `64:ff9b::` addresses for IPv4-only names; DNS64 is a resolver function and is configured separately from the Gateway.\n\n## ICMP / ping\n\nTenants behind a masquerade rule can ping IPv4 hosts on the internet. ICMP echo requests are source-NATed to the WAN IP alongside TCP and UDP, and the matching echo replies are translated back to the originating tenant, so ordinary `ping` connectivity checks work through the Gateway.\n\nThis covers ICMP echo (ping) only. It rides on the same masquerade rule — there is no separate command to enable it — so as soon as a subnet has a masquerade rule, its tenants can ping out. ICMP error messages are not translated.\n\n## Command reference\n\nMutating commands require root, so prefix them with `sudo`; the read-only `list` and `status` commands do not.\n\n| Command | Action |\n|---------|--------|\n| `gateway snat add <lan-cidr> --wan <iface>` | Masquerade a private LAN subnet out the WAN interface's public IP |\n| `gateway snat list` | List NAT rules (masquerade and published port-forwards) |\n| `gateway snat remove <id>` | Remove a NAT rule by id |\n| `nat64 configure <v4-pool> [prefix]` | Set the IPv4 pool address (and optional `/96` prefix) |\n| `nat64 enable` | Enable NAT64 (requires a configured pool) |\n| `nat64 disable` | Disable NAT64 (the Gateway path reverts to unchanged) |\n| `nat64 status` | Show NAT64 state, prefix, pool, and active flow count |\n\n## See also\n\n- [Networking Overview](/docs/networking/overview) — where the Gateway sits in the data plane.\n- [BGP Edge Routing](/docs/networking/bgp) — announce your fabric prefixes to upstream routers.\n- [Zero-Trust Firewall](/docs/networking/firewall) — outbound and published traffic still passes the ACL.\n- [Gateway High Availability](/docs/clustering/high-availability) — redundant Gateways and VIP failover.\n- [API Reference](/docs/api) — publish internal services with the port-forward endpoint.\n"
        }
    ]
}