<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Han Vigo</title>
    <description>The latest articles on DEV Community by Han Vigo (@han_vigo_7aecf96f08a23b63).</description>
    <link>https://dev.to/han_vigo_7aecf96f08a23b63</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4171485%2F3911f926-f680-461f-9c82-7246c103e8c8.png</url>
      <title>DEV Community: Han Vigo</title>
      <link>https://dev.to/han_vigo_7aecf96f08a23b63</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/han_vigo_7aecf96f08a23b63"/>
    <language>en</language>
    <item>
      <title>The 12 Ingress-NGINX annotations with no Gateway API equivalent (and what to do about each)</title>
      <dc:creator>Han Vigo</dc:creator>
      <pubDate>Thu, 08 Oct 2026 13:57:41 +0000</pubDate>
      <link>https://dev.to/han_vigo_7aecf96f08a23b63/the-12-ingress-nginx-annotations-with-no-gateway-api-equivalent-and-what-to-do-about-each-57a3</link>
      <guid>https://dev.to/han_vigo_7aecf96f08a23b63/the-12-ingress-nginx-annotations-with-no-gateway-api-equivalent-and-what-to-do-about-each-57a3</guid>
      <description>&lt;p&gt;Ingress-NGINX was retired in March 2026: no more releases, no more security patches, repository archived. By the Kubernetes project's own account, about half of cloud-native environments were still running it. Most migration guides stop at "run &lt;code&gt;ingress2gateway&lt;/code&gt;". That tool does the routing part well. The migration is everything it &lt;em&gt;cannot&lt;/em&gt; convert.&lt;/p&gt;

&lt;p&gt;I went through every Ingress-NGINX annotation and checked, against the October 2026 documentation of each Gateway API implementation, what happens to it. Roughly 80% convert or map to a policy. The remaining 20% have &lt;strong&gt;no Gateway API equivalent&lt;/strong&gt;, and each of them needs a decision. This article is that 20%.&lt;/p&gt;

&lt;p&gt;Everything below was verified against the official docs of Gateway API v1.6, NGINX Gateway Fabric (NGF) 2.7 and Envoy Gateway 1.9 on 7 October 2026. Where a vendor's documentation does not describe a capability, I say "not documented" rather than guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. &lt;code&gt;configuration-snippet&lt;/code&gt; / &lt;code&gt;server-snippet&lt;/code&gt; / &lt;code&gt;location-snippet&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Gone by design. Gateway API deliberately has no "paste raw config here" escape hatch, and the implementations do not add one. Before migrating, inventory what your snippets actually do; in most fleets it is one of five things: header manipulation, redirects, rate limits, auth, or custom error pages. Each of those has a policy below. Anything else moves into the application or a sidecar.&lt;/p&gt;

&lt;p&gt;Inventory in one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.items[] | select(.metadata.annotations | keys[]? | test("snippet")) | "\(.metadata.namespace)/\(.metadata.name)"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. &lt;code&gt;limit-rps&lt;/code&gt; / &lt;code&gt;limit-rpm&lt;/code&gt; / &lt;code&gt;limit-connections&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;BackendTrafficPolicy.spec.rateLimit&lt;/code&gt; with &lt;code&gt;type: Local&lt;/code&gt; (per-proxy) or &lt;code&gt;type: Global&lt;/code&gt; (shared counter via the rate-limit service). Global needs the Redis-backed rate limit deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; no documented rate limiting in the open-source edition as of 2.7.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. &lt;code&gt;auth-url&lt;/code&gt; / &lt;code&gt;auth-signin&lt;/code&gt; (external auth)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;SecurityPolicy.spec.extAuth&lt;/code&gt; with an HTTP or gRPC auth service; &lt;code&gt;headersToBackend&lt;/code&gt; forwards identity headers. Attach to the HTTPRoute or the Gateway.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; not documented. Put an auth proxy (oauth2-proxy) in front of the backend Service and route to it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. &lt;code&gt;affinity: cookie&lt;/code&gt; (sticky sessions)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; only via the experimental &lt;code&gt;sessionPersistence&lt;/code&gt; field on the route, and it requires NGINX Plus.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;BackendTrafficPolicy.spec.loadBalancer.consistentHash&lt;/code&gt; with &lt;code&gt;type: Cookie&lt;/code&gt;; set the cookie name and TTL there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. &lt;code&gt;custom-http-errors&lt;/code&gt; / &lt;code&gt;default-backend&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;BackendTrafficPolicy.spec.responseOverride&lt;/code&gt; matches status codes and returns an inline body or a ConfigMap-backed one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; not documented.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  6. &lt;code&gt;proxy-body-size&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;BackendTrafficPolicy.spec.requestBuffer.limit&lt;/code&gt; (exceeding it returns 413).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; &lt;code&gt;ClientSettingsPolicy.spec.body.maxSize&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  7. &lt;code&gt;proxy-read-timeout&lt;/code&gt; / &lt;code&gt;proxy-send-timeout&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;HTTPRoute has a standard &lt;code&gt;timeouts&lt;/code&gt; field (&lt;code&gt;request&lt;/code&gt; and &lt;code&gt;backendRequest&lt;/code&gt;). The catch is who implements it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; yes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF 2.7:&lt;/strong&gt; does &lt;strong&gt;not&lt;/strong&gt; implement HTTPRoute &lt;code&gt;timeouts&lt;/code&gt; or &lt;code&gt;retry&lt;/code&gt;. Use &lt;code&gt;ClientSettingsPolicy&lt;/code&gt; / &lt;code&gt;UpstreamSettingsPolicy&lt;/code&gt; where they cover your case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Load Balancer Controller and GKE:&lt;/strong&gt; no HTTPRoute &lt;code&gt;timeouts&lt;/code&gt; either; timeouts are configured on the load balancer resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  8. &lt;code&gt;rewrite-target&lt;/code&gt; with capture groups
&lt;/h2&gt;

&lt;p&gt;Simple prefix rewrites convert (&lt;code&gt;URLRewrite&lt;/code&gt; filter with &lt;code&gt;ReplacePrefixMatch&lt;/code&gt;). Regex rewrites with &lt;code&gt;$1&lt;/code&gt;/&lt;code&gt;$2&lt;/code&gt; captures do not; Gateway API has no regex rewrite. Options: restructure the paths, or use the implementation's extension (Envoy Gateway &lt;code&gt;HTTPRouteFilter&lt;/code&gt; with &lt;code&gt;regex&lt;/code&gt; rewrite).&lt;/p&gt;

&lt;h2&gt;
  
  
  9. Regex paths shared across hosts
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;use-regex: "true"&lt;/code&gt; combined with several hosts on one Ingress is the single most common cause of broken cutovers. Gateway API has &lt;code&gt;RegularExpression&lt;/code&gt; path matching, but the implementations differ in the regex dialect and in how they order overlapping matches. Find these before you start:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get ingress &lt;span class="nt"&gt;-A&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; json | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.items[] | select(.metadata.annotations["nginx.ingress.kubernetes.io/use-regex"]=="true") | select((.spec.rules|length)&amp;gt;1) | "\(.metadata.namespace)/\(.metadata.name)"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  10. &lt;code&gt;ssl-redirect&lt;/code&gt; / &lt;code&gt;force-ssl-redirect&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Converts: an HTTP listener with a &lt;code&gt;RequestRedirect&lt;/code&gt; filter to &lt;code&gt;https&lt;/code&gt;, status 301. Do not forget the HTTP listener itself, which many people drop when they only migrate the HTTPS one.&lt;/p&gt;

&lt;h2&gt;
  
  
  11. &lt;code&gt;whitelist-source-range&lt;/code&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Envoy Gateway:&lt;/strong&gt; &lt;code&gt;SecurityPolicy.spec.authorization&lt;/code&gt; with client CIDR rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;NGF:&lt;/strong&gt; not documented at the route level.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  12. L4 (&lt;code&gt;tcp-services&lt;/code&gt; / &lt;code&gt;udp-services&lt;/code&gt; ConfigMaps)
&lt;/h2&gt;

&lt;p&gt;Not annotations, but they ride along with Ingress-NGINX and are forgotten. Gateway API has &lt;code&gt;TCPRoute&lt;/code&gt; and &lt;code&gt;UDPRoute&lt;/code&gt; (experimental channel). Check that your implementation ships the experimental CRDs before you depend on them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two things that bit me
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;AWS WAF&lt;/strong&gt; attaches through &lt;code&gt;LoadBalancerConfiguration.wafV2&lt;/code&gt; on the Gateway, not through an annotation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-namespace Gateways&lt;/strong&gt; need a &lt;code&gt;ReferenceGrant&lt;/code&gt;, and the failure mode is silent: the route simply never attaches. &lt;code&gt;kubectl get httproute -o yaml&lt;/code&gt; shows &lt;code&gt;Accepted=False&lt;/code&gt; in the conditions, but nothing else complains.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I did with all this
&lt;/h2&gt;

&lt;p&gt;I turned the full table (9 implementations, including GKE, AWS LBC and Azure AGC), the inventory scripts, twelve before/after manifest pairs validated against the real CRD schemas, and the zero-downtime cutover and rollback runbooks into a book: &lt;a href="https://leanpub.com/gateway-api-migration-playbook" rel="noopener noreferrer"&gt;Off Ingress-NGINX: The Gateway API Migration Playbook&lt;/a&gt;. The list above is the part most teams need first; questions in the comments are welcome.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: the book was drafted with AI assistance under my direction and then technically edited claim by claim against the official documentation; the editing log ships with it.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>networking</category>
      <category>cloudnative</category>
    </item>
  </channel>
</rss>
