The reverse proxy setup in this article is only an example. It acts as an intermediate layer between SAP Fiori end-users and SAPUI5 content hosted on AS ABAP system.
The idea is to give you insights on settings and configuration you need to use to go with on any cloud solution or web server (service) of your own choice. For details on the specifics how such reverse proxies can be configured refer to the corresponding provider or vendor.
Introduction
The performance when loading SAPUI5 resources by browsers is one of the most important aspects of the user experience when using SAPUI5 applications. Browser and server caches were used for improving the SAPUI5 bootstrap performance. However, apart from the fact that a browser cache is not always configured for an end user at all, it requires to be prefilled by initial requests before it can be used. A bunch of initial requests may take a lot of time to be served before they are cached by a browser. In such cases the server cache comes in help. The fast cache of the Internet Communication Manager (ICMan) of an ABAP system can save processing time of a resource request if the resource was already cached. But for companies, which are spread across countries and continents, gaining faster loading times for initial requests from the server cache still could be insufficient. It would be better to provide caching hubs closer to the geographical zones of the users. Such network of cache servers is called a Content Delivery Network (CDN). The cache servers are prefilled with contents from the original web server.
In this blog post I want to illustrate a basic reference setup of a CDN with NGINX Open Source (any other could be selected), configured as a proxy cache server for SAPUI5 resources hosted on an SAP ABAP application server (such as SAP Front-End Server). The performance improvement of initial requests may vary depending on the SAPUI5 application and how much close the closest cache server is to the end users. Some measurements show more than 2.5 times faster loading of SAPUI5 applications when using an own CDN for loading the static resources.
Minimal requirements
From SAP_UI 7.53 SP05 there is the option to configure your custom CDN of choice as an external location in the Customizing of your ABAP system (see the documentation here). This is what we need.
The minimal requirements for NGINX Open Source can be found here.
Reference set-up
Next is to show the installation steps for NGINX. NGINX needs to be installed in a virtual host/physical machine, which will act as a reverse proxy for the SAP AS ABAP server from a distant location. We used for our set-up an Ubuntu server.
- Install NGINX Open Source
- Open the command line and execute the below commands to get the NGINX signing key and to add it to the apt program’s key ring
$ sudo wget https://nginx.org/keys/nginx_signing.key $ sudo apt-key add nginx_signing.key
- With the next command get the Ubuntu code name.
$ lsb_release -a
The Ubuntu code name we got for our set-up is bionic.
- Open the /etc/apt/sources.list file
$ sudo vi /etc/apt/sources.list
- Add the following lines to the sources.list file to name the repositories to obtain NGINX but replace bionic with your Ubuntu code name.
deb https://nginx.org/packages/ubuntu/ bionic nginx deb-src https://nginx.org/packages/ubuntu/ bionic nginx
- Install NGINX
$ sudo apt-get update $ sudo apt-get install nginx
- Start NGINX on localhost (127.0.0.1)
$ sudo nginx $ curl -I 127.0.0.1
You should see HTTP status “200 OK”
- Open the command line and execute the below commands to get the NGINX signing key and to add it to the apt program’s key ring
- Setup a SAPUI5 server blockNGINX allows to create virtual hosts called server blocks for different sites or applications. So, let’s create a server block dedicated for our SAPUI5 resources in a brand-new configuration file.
- First you have to create a server configuration file in the main configuration directory /etc/nginx/conf.d. I name the file resources.conf.
- Open the new file and add a server block with the SAPUI5 configuration to it as follows but replace <ABAP system FQDN> with the Fully Qualified Domain Name (FQDN) of the SAP ABAP system and <ABAP system port> with its port.
server { listen 50001; # UI5 resources endpoint location /resources/ { proxy_pass https://<ABAP system FQDN>:<ABAP system port>/sap/public/bc/ui5_ui5/resources/; } }
We assigned our SAPUI5 server block the port 50001 but you could choose any number and can reference it via this port. The proxy_pass directive needs to get the full path to the endpoint of the SAPUI5 resources in your system.
- Finally validate your configuration
$ sudo nginx -t
You should see a message that the configuration is ok. In case of errors you can check the NGINX error log at /var/log/nginx/error.log.
- Let’s test the connection to our NGINX server. Start a browser and try to open the abap.js SAPUI5 resource via the following proxy address
http://example.com:50001/resources/sap/ushell_abap/bootstrap/evo/abap.js
The example.com is the domain of the virtual host where you have installed NGINX. The 50001 port hints NGINX to choose the server block defined in the resources.conf file to handle the request.
Note that HTTP is used. In production, this would lead to a browser rejection to load the file with reason “Mixed content”. Web applications hosted in an ABAP system are accessed via HTTPS, thus all subsequent dependencies should be fetched over SSL.
Next is to enable SSL in our server block.
- Setup SSLFirst you have to generate a key pair for SSL connection between browsers and the proxy. We used openssl for this purpose in the NGINX virtual host. The SSL certificate needs to be signed by a second level certificate of the company’s Certificate Authority (CA). As an alternative for the CA signed certificate, a self-signed certificate can be created, but it should have an additional Alternative Name with the virtual host domain or/and IP address specified to be trusted by browsers. So, let’s start:
- Create the directory /etc/nginx/ssl and set access permissions to it
$ sudo mkdir /etc/nginx/ssl $ sudo chmod 600 /etc/nginx/ssl
Permissions of 600 means that the directory owner has read and write access to the files in the directory. This is sufficient to generate the keys.
- Generate a private key. As indicated above we are using openssl and generated the private key like this:
$ openssl genrsa -out server.key 4096
- Generate the certificate signing request for the CA
$ openssl req -new -key server.key -out server.csr
You will be asked to enter some information about the distinguished name, your company and region, e.g.:
Country Name (2 letter code) [AU]:{your country} State or Province Name (full name) [Some-State]: Locality Name (eg, city) []: Organization Name (eg, company) [Internet Widgits Pty Ltd]:{your company name} Organizational Unit Name (eg, section) []:{your organization name} Common Name (e.g. server FQDN or YOUR name) []:{full domain name of the virtual host} Email Address []:{your e-mail address} Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
- Copy the content including the —–BEGIN CERTIFICATE REQUEST—– and —–END CERTIFICATE REQUEST—– of the server.csr file or the file itself. You have to provide the copy to your company’s CA.
- You should get a signed certificate then. Copy it or its content including the —–BEGIN CERTIFICATE—– and —–END CERTIFICATE—– and paste it in the /etc/nginx/ssl directory to the file with name server.crt. The /etc/nginx/ssl directory should have three files:
server.crt server.csr server.key
- Open the configuration file of our SAPUI5 server block /etc/nginx/conf.d/resources.conf. Add your SSL keys to the SAPUI5 server block and append ssl to the port. Save your changes.
server { # Accessing 50001 through SSL listen 50001 ssl; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_certificate /etc/nginx/ssl/server.crt; add_header Strict-Transport-Security max-age=31536000; # UI5 resources endpoint location /resources/ { proxy_pass https://<ABAP system FQDN>:<ABAP system port>/sap/public/bc/ui5_ui5/resources/; } }
Note the Strict-Transport-Security addition. This will let browsers to access the 50001 port of the proxy only using HTTPS.
- Validate your configuration
$ sudo nginx -t
- Reload the NGINX running instance, so the changes take effect
$ sudo systemctl reload nginx
- Тest the HTTPS connection to the reverse proxy. Start a browser and try to open the abap.js SAPUI5 resource via the proxy address
https://example.com:50001/resources/sap/ushell_abap/bootstrap/evo/abap.js
- Create the directory /etc/nginx/ssl and set access permissions to it
- Setup Cache
Next is to configure the cache settings.- First, you have to add some directives in the http block of the main configuration file /etc/nginx/nginx.conf. Namely, within the http block above the existing include add the proxy_cache_path directive as below. Save the file.
proxy_cache_path /etc/nginx/ui5cache keys_zone=ui5_cache:60m levels=1:2 inactive=3h max_size=20g; include /etc/nginx/conf.d/*.conf;
The proxy_cache_path is the basic cache configuration and declares a physical directory (two level hierarchy), a shared memory (+size) for the cache keys, a upper limit of the size of the cache and how long an item can stay inactive in the cache. The two-level hierarchy is recommended according to the High-Performance Caching with NGINX documentation for large deployments. The size of the cache in this example is 20 GB but could be adjusted or even omitted according to your needs.
- Create directory /etc/nginx/ui5cache
$ sudo mkdir /etc/nginx/ui5cache
- Open the server configuration file /etc/nginx/conf.d/resources.conf and add cache directives to the SAPUI5 server block. Save the file
server { # Accessing 50001 through SSL listen 50001 ssl; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_certificate /etc/nginx/ssl/server.crt; add_header Strict-Transport-Security max-age=31536000; # UI5 resources endpoint location /resources/ { # Performance cache proxy_cache ui5_cache; proxy_cache_key "$scheme$proxy_host$request_uri"; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_lock on; add_header X-Proxy-Cache $upstream_cache_status; # Upstream endpoint proxy_pass https://<ABAP system FQDN>:<ABAP system port>/sap/public/bc/ui5_ui5/resources/; } }
The proxy_cache* directives are well explained by the NGINX documentation. In short, the proxy_cache_key is the format of the cache keys that are used for item identifiers in the cache. The lock is for multiple requests to a same resource which is not cached to trigger a single request to the upstream. The stale instructs the proxy to return stale content while it is being updated on the upstream or in case of error. The X-Proxy-Cache will be returned to the browser with an information (HIT/MISS) if the resource was served from the proxy cache or from the upstream.
- Validate the configuration and reload NGINX
$ sudo nginx -t $ sudo systemctl reload nginx
- If you use NGINX Plus – the commercial version of NGING – you can also purging the cache. For testing you can simply delete the /etc/nginx/ui5cache directory and recreate it anew:
$ sudo rm -rf /home/nginx/ui5cache $ sudo mkdir /home/nginx/ui5cache
- Test the proxy cache. Start a browser and open the abap.js SAPUI5 resource. Reload the page
https://example.com:50001/resources/sap/ushell_abap/bootstrap/evo/abap.js
Open the dev tools of your browser and check the response header X-Proxy-Cache on the Network tab. It should be a HIT.
- First, you have to add some directives in the http block of the main configuration file /etc/nginx/nginx.conf. Namely, within the http block above the existing include add the proxy_cache_path directive as below. Save the file.
- Setup CORSSome SAPUI5 resource requests require proper CORS headers to be returned in case the proxy and the ABAP system are in different domains.As a next step we will allow CORS requests with the ABAP system’s domain.
- Open to the main configuration file /etc/nginx/nginx.conf. Within the http block add the map directive as written below but replace the placeholder <ABAP system domain> with the FQDN of your ABAP system. Save the file
map $http_origin $cors_header { default ""; ~.<ABAP system domain> $http_origin; } proxy_cache_path /etc/nginx/ui5cache keys_zone=ui5_cache:60m levels=1:2 inactive=3h max_size=20g; include /etc/nginx/conf.d/*.conf;
The cors_header variable will be set if the expected origin is found.
- Open the server conf file /etc/nginx/conf.d/resources.conf and add the CORS configuration to the SAPUI5 server block as shown below. Save the file
server { # Accessing 50001 through SSL listen 50001 ssl; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_certificate /etc/nginx/ssl/server.crt; add_header Strict-Transport-Security max-age=31536000; # UI5 resources endpoint location /resources/ { # Performance cache proxy_cache ui5_cache; proxy_cache_key "$scheme$proxy_host$request_uri"; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_lock on; add_header X-Proxy-Cache $upstream_cache_status; # CORS if ($request_method = "OPTIONS") { add_header Access-Control-Allow-Origin $cors_header; add_header Access-Control-Allow-Methods "GET, OPTIONS"; add_header Access-Control-Allow-Headers "X-Requested-With, X-XHR-Logon"; add_header Access-Control-Max-Age 31536000; add_header Content-Type "text/plain; charset=utf-8"; add_header Content-Length 0; return 204; } proxy_hide_header "access-control-allow-origin"; add_header Access-Control-Allow-Origin $cors_header; # Upstream endpoint proxy_pass https://<ABAP system FQDN>:<ABAP system port>/sap/public/bc/ui5_ui5/resources/; } }
Note: The proxy_hide_header is set to avoid duplication of the access-control-allow-origin header in the response if it was already set by the CORS policy of the upstream. If a CORS request contains headers like X-Requested-With and X-XHR-Logon (like in some standard SAP Fiori applications), an OPTIONS preflight request will be initiated by the browser to verify with NGINX that they are allowed. Thus, they must be added in the configuration.
- Validate the configuration and reload NGINX
$ sudo nginx -t $ sudo systemctl reload nginx
- Open to the main configuration file /etc/nginx/nginx.conf. Within the http block add the map directive as written below but replace the placeholder <ABAP system domain> with the FQDN of your ABAP system. Save the file
- Set-up log (for troubleshooting)This step is recommended only for detecting issues. For performance reasons you might want to skip it.
- Open to the main conf file /etc/nginx/nginx.conf. Within the http block add the log directive above the map directive as shown below and save the file
log_format ui5log '$remote_addr [$time_local] "$request" $status "$upstream_addr" $upstream_response_time'; map $http_origin $cors_header { default ""; ~.<ABAP system domain> $http_origin; } proxy_cache_path /etc/nginx/ui5cache keys_zone=ui5_cache:60m levels=1:2 inactive=3h max_size=20g; include /etc/nginx/conf.d/*.conf;
The ui5log will write an additional upstream address and response time when resources are served from the ABAP system.
- Open to the server conf file /etc/nginx/conf.d/resources.conf and add the ui5log configuration to the SAPUI5 server block. Save the file.
server { # Accessing 50001 through SSL listen 50001 ssl; ssl_certificate_key /etc/nginx/ssl/server.key; ssl_certificate /etc/nginx/ssl/server.crt; add_header Strict-Transport-Security max-age=31536000; # UI5 resources endpoint location /resources/ { # Performance cache proxy_cache ui5_cache; proxy_cache_key "$scheme$proxy_host$request_uri"; proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504; proxy_cache_lock on; add_header X-Proxy-Cache $upstream_cache_status; # CORS if ($request_method = "OPTIONS") { add_header Access-Control-Allow-Origin $cors_header; add_header Access-Control-Allow-Methods "GET, OPTIONS"; add_header Access-Control-Allow-Headers "X-Requested-With, X-XHR-Logon"; add_header Access-Control-Max-Age 31536000; add_header Content-Type "text/plain; charset=utf-8"; add_header Content-Length 0; return 204; } proxy_hide_header "access-control-allow-origin"; add_header Access-Control-Allow-Origin $cors_header; # Upstream endpoint proxy_pass https://<ABAP system FQDN>:<ABAP system port>/sap/public/bc/ui5_ui5/resources/; } # UI5 log access_log /var/log/nginx/ui5.log ui5log; }
- Validate the configuration and reload NGINX.
$ sudo nginx -t $ sudo systemctl reload nginx
- Test the log.Start a browser and open the abap.js SAPUI5 resource. Then check the contents of the /var/log/nginx/upstream.log file.
https://example.com:50001/resources/sap/ushell_abap/bootstrap/evo/abap.js
- If the resource is not cached, the log looks like the following:
<IP of NGINX Virtual Host> [13/Aug/2020:09:35:34 +0000] "GET /resources/sap/ushell_abap/bootstrap/evo/abap.js HTTP/1.1" 200 "<IP and Port of the ABAP system>" 1.149
- If it is served from the cache it looks like this:
<IP of NGINX Virtual Host> [13/Aug/2020:09:35:34 +0000] "GET /resources/sap/ushell_abap/bootstrap/evo/abap.js HTTP/1.1" 200 "-" -
- Open to the main conf file /etc/nginx/nginx.conf. Within the http block add the log directive above the map directive as shown below and save the file
- Configure your ABAP system for SAPUI5 CDN of choice
- Open transaction SPRO, then click on SAP Reference IMG push button.
- Expand the tree to locate Configure SAPUI5 Bootstrapping.
- Press F8. Create new entry in the table.
- Save the configuration.
- The feature requires the corrections of the SAP note 2952223 to be implemented in the ABAP system. Now you can test the complete configuration of the SAPUI5 CDN of choice with the SAP Fiori launchpad or any other SAPUI5 application.
https://<ABAP system FQDN>:<ABAP system port>/sap/bc/ui2/flp
- Open transaction SPRO, then click on SAP Reference IMG push button.
Summary
Thanks to the new customizing to configure the location for bootstrapping the SAPUI5 resources you can setup your own CDN. That will lead to faster loading times for your SAPUI5 apps, especially for locations far away. On the example of NGINX, you have seen what needs to be configured and how, including proxy, caching, and security setting.
References
- Required fix for ABAP systems – https://launchpad.support.sap.com/#/notes/2952223
- UI5 CDN Of Choice for on premise customers – https://launchpad.support.sap.com/#/notes/2943781
- Official SAP documentation – https://help.sap.com/viewer/a7b390faab1140c087b8926571e942b7/201909.001/en-US/843dafd6bf0c413e9a5fe698e1550380.html
- Installing NGINX Open Source – https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/
- NGINX high performance caching – https://www.nginx.com/resources/library/high-performance-caching-with-nginx-and-nginx-plus/
- Complete NGINX cookbook – https://www.nginx.com/resources/library/complete-nginx-cookbook/
Other related blog posts
- Improving SAP Fiori Performance with Amazon CloudFront and AWS Global Accelerator – https://aws.amazon.com/blogs/awsforsap/improving-sap-fiori-performance-with-amazon-cloudfront-and-aws-global-accelerator-part-2-how-to-guide/
For more information on UI5
- Exchange knowledge: SAP Community | Q&A | Blog Post | Slack
- Learn more: SAPUI5 Demo Kit | openSAP | UI5 NewsCast | UI5ers live
- Try UI5 for free: SAPUI5 | OpenUI5 | OpenUI5 on NPM | SAPUI5 on NPM
- Follow us: Twitter | YouTube