<p>I'm trying to move from running some services in docker-compose to kubernetes, and struggling with the move from nginx reverse proxy to ingress nginx. The service uses <a href="https://www.h2o.ai/products/h2o/" rel="nofollow noreferrer">h2o ai</a> which has a web interface. I'm failing to bring up the web interface in the k8s version.</p>
<p>I think that I need to amend the spec in the ingress file to route appropriately, grateful for any pointers on how to do this.</p>
<p>In the docker solution with nginx as reverse proxy, when I access <code>http://k8s-master:3002</code> it redirects to <code>http://k8s-master:3002/flow/index.html</code> and displays correctly</p>
<p>For k8s,(I have the <code>ingress-nginx-controller</code> running as <code>NodePort</code> on <code>32000</code>) , I try to access <code>https://k8s-master:32000/h2otest</code> and get an error message as follows:</p>
<pre><code>{&quot;__meta&quot;:{&quot;schema_version&quot;:3,&quot;schema_name&quot;:&quot;H2OErrorV3&quot;,&quot;schema_type&quot;:&quot;H2OError&quot;},&quot;timestamp&quot;:1602674406013,&quot;error_url&quot;:&quot;Resource /h2otest&quot;,&quot;msg&quot;:&quot;\n\nERROR MESSAGE:\n\nResource /h2otest not found\n\n&quot;,&quot;dev_msg&quot;:&quot;\n\nERROR MESSAGE:\n\nResource /h2otest not found\n\n&quot;,&quot;http_status&quot;:404,&quot;values&quot;:{},&quot;exception_type&quot;:&quot;water.exceptions.H2ONotFoundArgumentException&quot;,&quot;exception_msg&quot;:&quot;\n\nERROR MESSAGE:\n\nResource /h2otest not found\n\n&quot;,&quot;stacktrace&quot;:[&quot;water.exceptions.H2ONotFoundArgumentException: Resource /h2otest not found&quot;,&quot;    water.api.RequestServer.response404(RequestServer.java:743)&quot;,&quot;    water.api.RequestServer.getResource(RequestServer.java:846)&quot;,&quot;    water.api.RequestServer.serve(RequestServer.java:465)&quot;,&quot;    water.api.RequestServer.doGeneric(RequestServer.java:301)&quot;,&quot;    water.api.RequestServer.doGet(RequestServer.java:225)&quot;,&quot;    javax.servlet.http.HttpServlet.service(HttpServlet.java:687)&quot;,&quot;    javax.servlet.http.HttpServlet.service(HttpServlet.java:790)&quot;,&quot;    org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865)&quot;,&quot;    org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535)&quot;,&quot;    org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255)&quot;,&quot;    org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1317)&quot;,&quot;    org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203)&quot;,&quot;    org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473)&quot;,&quot;    org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201)&quot;,&quot;    org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1219)&quot;,&quot;    org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144)&quot;,&quot;    org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)&quot;,&quot;    org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)&quot;,&quot;    water.webserver.jetty9.Jetty9ServerAdapter$LoginHandler.handle(Jetty9ServerAdapter.java:130)&quot;,&quot;    org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:126)&quot;,&quot;    org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132)&quot;,&quot;    org.eclipse.jetty.server.Server.handle(Server.java:531)&quot;,&quot;    org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352)&quot;,&quot;    org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)&quot;,&quot;    org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)&quot;,&quot;    org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)&quot;,&quot;    org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)&quot;,&quot;    org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)&quot;,&quot;    org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)&quot;,&quot;    java.lang.Thread.run(Thread.java:748)&quot;]}
</code></pre>
<hr />
<p><strong>UPDATE: based on Ken Chen's comment</strong></p>
<p>I've changed the ingress below to use <code>nginx.ingress.kubernetes.io/rewrite-target: /$2</code></p>
<p>Now when I type <code>https://k8s-master:32000/h2otest</code> it redirects to: <code>https://k8s-master:32000/flow/index.html</code></p>
<p>Typing <code>https://k8s-master:32000/h2otest/flow/index.html</code> directly works. <strong>How do I amend the rule so that</strong> <code>https://k8s-master:32000/h2otest</code> <strong>goes directly to</strong>  <code>https://k8s-master:32000/h2otest/flow/index.html</code> ?</p>
<hr />
<p>The following contains the files for each version:</p>
docker version
<p><code>docker-compose.yml</code></p>
<pre class="lang-yaml prettyprint-override"><code>services :
  test-h2o-svc:
    build:
      context: h2o
      dockerfile: Dockerfile
    image: test-h2o:3.30.1.1
    restart: always
    networks:
      - testnet
#    ports:
#      - 54323:54321

  test-reverse-proxy:
    image: nginx:alpine
    hostname: reverse-proxy
    restart: always
    ports:
      - 3002:3002
    volumes:
      - &quot;./nginx_files/nginx.conf:/etc/nginx/nginx.conf:rw&quot;
      - &quot;./nginx_files/sites-available/test.conf:/etc/nginx/conf.d/sites-available/test.conf:rw&quot;
      - &quot;./nginx_files/sites-available/test.conf:/etc/nginx/conf.d/sites-enabled/test.conf:rw&quot;
    networks:
      - testnet

networks:
 testnet:
version: &quot;3.5&quot;

</code></pre>
<p><code>nginx.conf</code></p>
<pre><code>user  nginx;
worker_processes  4;

error_log  /var/log/nginx/error.log warn;
pid        /var/run/nginx.pid;


events {
    worker_connections  1024;
}



http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] &quot;$request&quot; '
                      '$status $body_bytes_sent &quot;$http_referer&quot; '
                      '&quot;$http_user_agent&quot; &quot;$http_x_forwarded_for&quot;';

    access_log  /var/log/nginx/access.log  main;

    sendfile        on;
    #tcp_nopush     on;
    keepalive_timeout  180;
    #gzip  on;

    include /etc/nginx/conf.d/sites-enabled/*.conf;
    client_body_buffer_size     50M;
    client_max_body_size 2000M;
}


</code></pre>
<p><code>test.conf</code></p>
<pre><code>upstream link_h2o-svc {
  server        test-h2o-svc:54321;
}

server {
  listen        3002;
  location / {
    proxy_pass  http://link_h2o-svc;
   }
}

</code></pre>
<p><code>Dockerfile</code> for container: <code>test-h2o:3.30.1.1</code></p>
<pre><code>FROM ubuntu:latest

ARG H2O_VERSION=3.30.1.1

RUN apt-get update \
    &amp;&amp; apt-get install default-jdk unzip wget -y

RUN wget https://h2o-release.s3.amazonaws.com/h2o/rel-zeno/1/h2o-${H2O_VERSION}.zip \
    &amp;&amp; unzip h2o-${H2O_VERSION}.zip

ENV H2O_VERSION ${H2O_VERSION}
CMD java -jar h2o-${H2O_VERSION}/h2o.jar
</code></pre>
<hr />
k8s version
<pre class="lang-yaml prettyprint-override"><code>kind: Namespace
apiVersion: v1
metadata:
  name: ns-test
  labels:
    name: ns-test
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    kompose.cmd: /snap/kompose/19/kompose-linux-amd64 convert
    kompose.version: 1.21.0 (992df58d8)
  creationTimestamp: null
  labels:
    app: test-h2o
  name: test-h2o
  namespace: ns-test
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-h2o
  
  strategy: {}
  template:
    metadata:
      annotations:
        kompose.cmd: /snap/kompose/19/kompose-linux-amd64 convert
        kompose.version: 1.21.0 (992df58d8)
      creationTimestamp: null
      labels:
        app: test-h2o
    spec:
      containers:
      - image: test-h2o:3.30.1.1
        imagePullPolicy: &quot;&quot;
        name: test-h2o
        resources: {}
      restartPolicy: Always
      serviceAccountName: &quot;&quot;
      volumes: null
status: {}
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    kompose.cmd: /snap/kompose/19/kompose-linux-amd64 convert
    kompose.version: 1.21.0 (992df58d8)
  creationTimestamp: null

  name: test-h2o-svc
  namespace: ns-test
spec:
  ports:
  - name: &quot;54321&quot;
    port: 54321
    targetPort: 54321
  selector:
    app: test-h2o
status:
  loadBalancer: {}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
  namespace: ns-test
  annotations:
    #ingress.kubernetes.io/rewrite-target: /
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - http:
      paths:
        - path: /h2otest(/|$)(.*)
          pathType: Prefix
          backend:
            service:
              name: test-h2o-svc
              port: 
                number: 54321
</code></pre>

<blockquote>
<p>How do I amend the rule so that https://k8s-master:30439/h2otest goes directly to https://k8s-master:30439/h2otest/flow/index.html</p>
</blockquote>
<p>That is not an nginx-ingress question. Like most of the other ingresses nginx-ingress is there to do name based virtual hosting and SNI (or SSL Name based virtual hosting) with SSL offloading. Out of the box it's limited in any more.</p>
<p>While nginx-ingress can do some basic re-writing, it's limited to rewriting <code>/path/(.*)</code> to <code>/(.*)</code> and passing it to the next container to handle the traffic from there. If you're wanting it to do more you're into writing config maps for nginx-ingress.
Yes you'll want to set annotations for client body size etc, but the app itself (not the ingress) needs to be handling the <code>/h2otest</code> -&gt; <code>/h2otest/flow/index.html</code> rewriting (or <code>/</code> -&gt; <code>/flow/index.html</code>).</p>
<p>From what you're describing your layout looks like
<code>(nginx)ingress</code> -&gt; <code>app</code></p>
<p>You may need to change the layout to <code>(nginx)ingress</code> -&gt; <code>nginx</code> -&gt;<code>app</code> with the middle nginx doing the <code>/</code> -&gt; <code>/flow/index.html</code> rewrite</p>
<p>A word of advice. If you have any chance use name based virtual hosting rather than path virtual hosting (unless you have a good reason eg cors) for path based. Alot of apps these days just assume they are on <code>/</code> an the config gets &quot;interesting&quot; if you're elsewhere</p>
