HTTP Server

TLS

App Suite Proxy can be used for TLS termination of HTTP requests. The Server can be configured to use one certificate for all incoming requests or utilize Server Name Indication (SNI) to choose a different certificate from the configured keystore for each host. Each certificate has to provide the hostname in its alternative name extension. If only one certificate is present in the keystore, this certificate is used without any hostname matching. Wildcard certificates are also supported, from first subdomain level, like *.appsuite.com or *.customer.appsuite.com.

Configuration

Configuration takes place via properties in application.properties.

zuul.ssl.openssl.allow

Optional Offloads TLS termination to OpenSSL via Java JNI. See https://netty.io/wiki/forked-tomcat-native.html for details. App Suite Proxy links and ships the io.netty:netty-tcnative-boringssl-static library for that purpose.

This will also affect outbound connections (Backend Pools::TLS)!

Default: false

Reloadable: true

io.ox.appsuite.proxy.tls.enabled

Optional: Enables TLS

Default: false

Reloadable: false

io.ox.appsuite.proxy.tls.port

Manadatory for TLS: TLS port

Default: 8443

Reloadable: false

io.ox.appsuite.proxy.tls.keyStore.type

Manadatory for TLS: Keystore type. TODO: what are other formats?

Default: PKCS12

Reloadable: false

io.ox.appsuite.proxy.tls.keyStore

Manadatory for TLS: Path to keystore file

Default: <empty>

Reloadable: false

io.ox.appsuite.proxy.tls.keyStore.pass

Manadatory for TLS: Password to open keystore

Default: <empty>

Reloadable: false

io.ox.appsuite.proxy.tls.ciphers

Optional: Set the cipher suites that should be supported

Default:

TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
io.ox.appsuite.proxy.tls.protocols

Optional: Set the protocols that should be supported

Default: TLSv1.2, TLSv1.1, TLSv1

Reloadable: false

Server Name Indication

Since SNI is enabled whenever TLS is enabled, this feature can be used by simply adding new certificates to the keystore and ensuring, that the hostname is provided in the certificates alternative name extension.

Note

So far, OpenSSL is not supported in cooperation with the SNI feature. If OpenSSL is desired, one single certificate should be present in the keystore.

Compression

GZip compression of HTTP response payload is supported and enabled by default. Response payloads are compressed, if the content type is known to be compressible and the HTTP request contained gzip as part of an Accept-Encoding header. In addition the content must exceed a certain size to be compressed.

Origin responses that are already compressed are streamed through as is and not re-compressed.

Configuration

Configuration takes place via properties in application.properties.

zuul.response.gzip.filter.enabled

Optional: En-/disable GZip compression

Default: true

Reloadable: true

zuul.min.gzip.body.size

Optional: Minimum response body size to apply compression in bytes

Default: 860

Reloadable: true

zuul.gzip.contenttypes

Optional: Comma-separated list of content types that apply for compression

Default:

text/html, application/x-javascript, text/css, application/javascript,
text/javascript, text/plain, text/xml, application/json,
application/vnd.ms-fontobject, application/x-font-opentype,
application/x-font-truetype, application/x-font-ttf,
application/xml, font/eot, font/opentype, font/otf, image/svg+xml,
image/vnd.microsoft.icon

Reloadable: true

PROXY Protocol

The PROXY protocol provides a convenient way to safely transport connection information such as a client’s address, client port and protocol across multiple layers of NAT or TCP proxies.

Configuration

The following settings are applicable to application.properties.

io.ox.appsuite.proxy.expectProxyProtocol

Optional: A boolean value to enable/disable PROXY protocol support. If enabled and a request was sent using PROXY protocol:

Default: false

Reloadable: false

Example Setup

Find below an example configuration for an HAProxy docker container that has PROXY protocol enabled.

## Docker Compose
version: '3'

services:
  haproxy:
    image: haproxy:1.9.6
    volumes:
      - ./haproxy.config:/usr/local/etc/haproxy/haproxy.cfg:ro
    ports:
      - 80:80
    expose:
      - "80"
    container_name: 'haproxy'

## Haproxy Config
global
    maxconn 50
    debug

defaults
    mode tcp
    timeout connect 5s
    timeout client 25s
    timeout server 25s
    timeout queue 10s

frontend local.ox
    bind 172.18.0.2:80
    default_backend proxy

backend proxy
   balance roundrobin
   server server1 host.docker.internal:8080 send-proxy


## IP's and Ports
172.18.0.2:80 -> Container IP : Port

host.docker.internal:8080 -> appsuite-proxy IP : Port

Enable proxy protocol in configfile with send-proxy or send-proxy-v2. Disable by deleting the keywords.

For a local setup replace container- and appsuite-proxy IP with localhost. Finally start the HAProxy with haproxy -f cfgfile

Management Endpoint

App Suite Proxy comes with an additional management endpoint which allows administrators and third party systems to get access to runtime environment. Following topics are currently covered:

  • Prometheus Metrics

  • Microprofile Health Check

  • Configuration Reload

To enable management endpoint on startup set configuration property io.ox.appsuite.proxy.admin.port.enabled to true. For a complete reference to all possible configuration properties and their defaults see section Settings.

Hint

To get an overview of all exposed endpoints open root entry at http://<server>:<port>

Settings

Note

All properties can be found in application.properties. If a property is missing, not set or the value is not in range the default value will be used.

io.ox.appsuite.proxy.admin.port.enabled

Enables Management Endpoint

Default: false

Reloadable: false

io.ox.appsuite.proxy.admin.port

The Management Endpoint Port. Supported port range 8081-9999

Default: 8888

Reloadable: false

io.ox.appsuite.proxy.admin.enable-http-error-response

Get a detailed error message in case of any HTTP Error (4xx, 5xx). This property can be changed on runtime.

Default: false

Reloadable: true

io.ox.appsuite.proxy.mp.health.disable-default-procedures

Register default health check procedures. See Developers Guide for prerequisites.

Default: true

Reloadable: false

io.ox.appsuite.proxy.mp.health.default-package

Classes within this package will be registered on server startup. See Developers Guide for prerequisites.

Default: io.ox.proxy.health.impl.checks

Reloadable: false

io.ox.appsuite.proxy.mp.health.jvm.threadcount.max

Health Check Threads- After exceeding this value the health check change to DOWN. Supported range 1 - Integer.MAX_VALUE. This property can be changed on runtime.

Default: 50

Reloadable: true

io.ox.appsuite.proxy.mp.health.jvm.heapmemory.maxpercentage

Health Check Memory - After exceeding this value the health check change to DOWN. 0.01 -> 1%, 0.99 -> 99% of max heap. Supported range 0.01 - 0.99. This property can be changed on runtime.

Default: 0.9

Reloadable: true

io.ox.appsuite.proxy.mp.health.http

Health Check HTTP - If Endpoint is not available health check change to DOWN. If no value is present health check will be skipped. This property can be changed on runtime.

Default: <empty>

Reloadable: true

io.ox.appsuite.proxy.admin.enable-open-api

Creates an additional Open API Endpoint when enabled. Endpoint is then available under {{baseUrl}}/openapi, {{baseUrl}}/openapi.json, {{baseUrl}}/openapi.yaml. Must be set before Server Startup.

Default: false

Reloadable: false

Sample

A sample configuration may look like this:

##################################################
##Management Tooling 
##################################################
io.ox.appsuite.proxy.admin.port.enabled=true
io.ox.appsuite.proxy.admin.port=
io.ox.appsuite.proxy.admin.enable-http-error-response=
io.ox.appsuite.proxy.admin.enable-open-api=

###################################################
##Microprofile - Health Checks
###################################################
io.ox.appsuite.proxy.mp.health.disable-default-procedures=false
io.ox.appsuite.proxy.mp.health.default-package=io.ox.proxy.health.impl.checks
io.ox.appsuite.proxy.mp.health.jvm.threadcount.max=
io.ox.appsuite.proxy.mp.health.jvm.heapmemory.maxpercentage=
io.ox.appsuite.proxy.mp.health.http=

Note

This configuration will start the management listener on port 8888 and register all default health checks. Empty parameters will fall back to their default.

Microprofile Health Check

App Suite Proxy comes with an implementation of Microprofile Health API. Some basic health checks are available by default and will be registered when enabled (see Settings). According to the API specification these health checks will be exposed to /health /health/live /health/ready.

Payload from http://<server>:<port>/health looks like the following example:

{
    "status": "DOWN",
    "checks": [
      {
        "name": "threads",
        "state": "UP",
        "data": {
          "max thread count": 50,
          "daemon thread count": 7,
          "monitor deadlocked thread count": 0,
          "thread count": 13,
          "deadlocked thread count": 0,
          "started thread count": 13,
          "peak thread count": 13
        }
      },
      {
        "name": "http-check",
        "state": "DOWN",
        "data": {
          "error": "java.net.ConnectException: Connection refused (Connection refused)",
          "URI": "http://localhost:9999/ping"
        }
      },
      {
        "name": "heap-memory",
        "state": "UP",
        "data": {
          "max %": "0.9",
          "max": 3817865216,
          "used": 69881976
        }
      }
    ],
    "service": {
      "name": "App Suite Proxy",
      "version": "dev",
      "date": "2019-10-31T11:58:18,745+0100",
      "timeZone": "Europe/Berlin",
      "locale": "de_DE",
      "charset": "UTF-8"
    }
  }

Prometheus Metrics

Monitoring Metrics from server runtime will be exposed under /metrics. The format follows the Prometheus Format specification .

Payload from http://<server>:<port>/metrics looks like the following example:

# HELP zuul_filter_concurrency_current Current amount of concurrent requests for a filter
# TYPE zuul_filter_concurrency_current gauge
zuul_filter_concurrency_current{id="InitOidcSso.end",} 0.0
zuul_filter_concurrency_current{id="HttpRedirectFilter.end",} 0.0
zuul_filter_concurrency_current{id="GZipResponseCustomFilter.out",} 0.0
zuul_filter_concurrency_current{id="ProxyPassFilter.in",} 0.0
zuul_filter_concurrency_current{id="HttpSimpleResponseFilter.end",} 0.0
zuul_filter_concurrency_current{id="HeaderHandlingFilter.in",} 0.0
zuul_filter_concurrency_current{id="ZuulResponseFilter.out",} 0.0

Open API

Management Endpoint comes with an integrated Open API documentation which can be created while server startup, see section Settings. Once enabled the documentation is available at /openapi, /openapi.yaml and /openapi.json. /metrics. Use this endpoint to import the payload in a tool of your choise e.g. Postman, or use /application.wadl to help with client generation.

Payload from /openapi looks like the following example:

openapi: 3.0.1
info:
  title: Appsuite-Proxy Management API
  description: Description
  termsOfService: http://swagger.io/terms/
  contact:
    email: devs@open-xchange.com
  license:
    name: Apache 2.0
    url: http://www.apache.org/licenses/LICENSE-2.0.html
  version: dev
paths:
  /healthcheck:
    get:
      operationId: doHealthCheck
      responses:
        default:
          description: default response
          content:
            '*/*': {}
  /health:
    get:
      tags:
      - Health Checks
      summary: Health Check
      description: Health Check according to microprofile Health API
      operationId: getHealthResponse
      responses:
        default:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiErrorModel'
        "200":
          description: All Health Checks are UP
        "503":
          description: At least one Health Check failed with state DOWN
        "500":
          description: Health Check call could not be processed in backend. If property
            enable API response errors is set to true see payload for futher details.

Command Line Tool

Appsuite Proxy comes with a command line tool which basically gives access to Proxy`s management API Endpoints. The command line tool can be installed as additional docker image or locally using gradle a task. For more information see project`s readme. Once you have installed command line tool run appsuite-proxy --help to get a list with possible actions

root@2a1f20a3b3d7:/usr/local/bin# appsuite-proxy
Usage: appsuite-proxy [OPTIONS] COMMAND [ARGS]...

  Command line tool can be used to perform management tasks from shell which
  basically invoke Appsuite Proxy`s REST API Endpoints.

Options:
  -u, --baseurl TEXT  Base URL to proxy`s management API  [default:
                      (http://127.0.0.1:8888)]
  -v, --verbose       Verbose output  [default: (False)]
  -p, --payload       Print full response to console output  [default:
                      (False)]
  --version           Show the version and exit.
  -h, --help          Show this message and exit.

Commands:
  config  Actions calling Appsuite Proxy`s configuration endpoint
  health  Actions calling Appsuite Proxy`s health endpoint

  Run 'appsuite-proxy COMMAND --help' for more information

CLI Docker Image

Alternatively you can use appsuite-proxy-cli docker image which includes the clt. To use it you need just to run the image, e.g. docker run ImageId. This will show you the help text and you can just add options or commands on your next docker run call, e.g. docker run ImageId -v config get.