Skip to content

Enable SmartApp (and other nginx apps) to be deployed in other contexts #2

@justb4

Description

@justb4

Currently the SmartApp and other nginx apps like WaalKade are proxied on path prefixes like https://pdok.smartemission.nl/smartapp. As to still allow local resources (javascript, css, media) to be served, the prefix-path /smartapp is rewritten in Kubernetes Ingress to /smartapp/ (trailing slash). This does not work nicely in all deployment contexts, in particular Traefik. Also it is a different method as used with (Flask) Python Apps. There the HTTP Header X_SCRIPT_NAME is set in the related Ingress and handled internally within the Flask app.

It appears to be possible to use the same X_SCRIPT_NAME mechanism to work for nginx backend apps. Thus the rewrite is not required anymore.

This can be effected by a simple addition to the nginx config, using the sub_filter feature on HTML (by default) and JavaScript (sub_filter_types application/javascript) content:

server {
    listen       80;
    server_name  localhost;

    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;

    location / {
        # rewrite ^([^.]*[^/])$ $uri/ permanent;
        root   /usr/share/nginx/html/smartapp;

        # substitute /SCRIPT_NAME so if proxied the proper URLs are set
        sub_filter_once off;
        sub_filter_types application/javascript;
        sub_filter "/X_SCRIPT_NAME" $http_x_script_name;
        index  index.html;
    }


    #error_page  404              /404.html;

    # redirect server error pages to the static page /50x.html
    #
    error_page  500 502 503 504 /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

The HTML and JavaScript content will need to have /X_SCRIPT_NAME in the content e.g.

<!DOCTYPE html>
<html>
<head>
    <title>SmartApp</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css"
       integrity="sha512-M2wvCLH6DSRazYeZRIm1JnYyh22purTM+FDB5CsyxtQJYeKq83arPe5wgbNmcFXGqiSH2XR8dT/fJISVA1r/zQ=="
       crossorigin=""/>
    <link rel="stylesheet" href="/X_SCRIPT_NAME/lib/markercluster/1.1.0/MarkerCluster.css" />
   	<link rel="stylesheet" href="/X_SCRIPT_NAME/lib/markercluster/1.1.0/MarkerCluster.Default.css" />

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/>

This replaces href="/X_SCRIPT_NAME/... with e.g. href="/smartapp/... when the X_SCRIPT_NAME header is set. If not set, e.g. when accessed directly this substitutes to href="/... and resolves as well. A very basic form of templating.

The SmartApp Ingress needs to be adapted to:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: smartapp
  namespace: smartemission
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/add-base-url: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_set_header X-Script-Name /smartapp;
spec:
  rules:
  - host: pdok.smartemission.nl
    http:
      paths:
      - path: /smartapp
        backend:
          serviceName: smartapp-service
          servicePort: 80

The nice thing is that we have a single method within the Ingress-es (proxy_set_header X-Script-Name) and getting rid of the sometimes problematic rewrite.

In docker-compose this becomes

version: "3"

services:

  smartapp:

    image: smartemission/se-smartapp:latest

    container_name: smartapp

    restart: unless-stopped

    labels:
      - "traefik.backend=smartapp"
      - "traefik.enable=true"
      - "traefik.frontend.priority=500"
      - "traefik.frontend.rule=HostRegexp:{subdomain:[a-z]+}.smartemission.nl;PathPrefixStrip:/smartapp"
      - "traefik.frontend.headers.customRequestHeaders=X-Script-Name:/smartapp"
      - "traefik.docker.network=se_back"

    networks:
      - se_back

#    ports:
#      - 80:80

networks:
  se_back:
    external: true

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions