A few years ago it was deemed state-of-the-art to store any kind of extra resources (images, css/js-files) directly on the webserver.
Of course this was just the best-practice, left with many who were not able to follow because of company restrictions: no access to web server, not allowed to store files, too many regulations, and so on.
Luckily APEX 5++ gave us nicely working Static Application Files and Static Workspace Files. Now everyone is using those to store extra files.
But there is a downside: it is still a hit on the database retrieving a BLOB.
This doesn’t really matter, if there is just a few consistent users, but has a huge impact for many first time visitors as on public websites like fab.earth, apex.oracle.com, or builtwithapex.com.
If you think this doesn’t concern you: APEX Theme Styles and Plugin Files are loaded the same way and benefit also from a speedup.
There is a very simple way to speed things up, which also works for any ORDS webservice you might use to deliver rather static content (ie.hardly ever changing images, …).
Anyway, here we go: the solution to speed up serving dynamic content is to cache it on the webserver.
If you have read my post on the Oracle APEX Reverse Proxy Guide using nginx, you already figured I like to use nginx, a free and lightweight alternative to Apache.
At first we need to know how APEX static files work: they are served through an ORDS webservice called “r”. For example https://myhost.prost/ords/myworkspace/r/files/static/v2/testimage.png
What we can see in this file-path is the folder /r/, which in fact is a generic ORDS webservice used for all kinds of APEX files (application, workspace, theme-style, plugin, …). But there is also a version number (v2) as part of the path. Whenever we change the file (update the image, …) the version number changes.
This is great information, because it means a full file path always results in the very same file. New file, new path.
So instead of passing the same file path over and over again to ORDS to read that file from the database, we can tell the webserver to cache a copy of that file and serve it directly to the next request.
In nginx-configuration we can easily set up a cache like this:
1. configure a cache bucket2. tell nginx which file-path to cache
The explanation for all those settings is documented in the official documentation. In short: put every file found on a path like /ords/*/r/*files/static/vnnn/ subfolder for at least 24hrs and also send a 300 day expiry header to the client.
For www.builtwithapex.com we also serve images (screenshots of websites) through an ORDS webservices, which is cached in a similar manner. That helped us to speed up file access by more than 300%.
That’s what I call an easy and quick win !
Edit 24.04.2020
The path to determine if it is a static application or workspace file was refined to avoid false positives with APEX 20.1 friendly url.
Thanks Peter, great work!
a silly question, could you please share the code allowing non-static files to pass to ORDS?
as soon as I added something like this
location ^~ /ords/ {proxy_pass http://10.0.0.2:8080/ords/;}
X-Cache-Status is no longer set.
Thanks
Frank
Hi Peter,
Thanks a lot for your post. I’m following your indications and I just have 2 comments:
1) Could you please post the text so I can copy/paste the config? I’ve copied it manually but I’m not confident to have any typo.
2) Is there any way to actually check that the cache is active? (I mean with Chrome dev tools or something similar) I’ve checked content of directory /var/lib/nginx/cache and it’s empty in the server.
Thanks a lot!
Jose,
here is the copied text:
# cache apex application/workspace static files
location ~* /ords/(.*)/r/([0-9/]*)files/static/v([0-9]+)/ {
proxy_cache backcache;
proxy_cache_key $host$uri$is_args$args;
proxy_cache_valid 200 24h;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:8080;
proxy_redirect off;
add_header X-Cache-Status $upstream_cache_status;
expires 300d;
}
In developer-tools check the response headers x-cache-status (if configured on your webserver).
… because as per your comments, (this is my Chomre devtools output), it seems the cache is not activated…
GENERAL:
Request URL: http://xxxxxx.josearostegui.com:8080/ords/heroapps/r/500/files/static/v88/hero-logo.png
Request Method: GET
Status Code: 200
Remote Address: 212.227.205.227:8080
Referrer Policy: strict-origin-when-cross-origin
RESPONSE HEADERS:
HTTP/1.1 200
Content-Disposition: inline; filename=”hero-logo.png”; filename*=UTF-8”hero-logo.png
X-Frame-Options: SAMEORIGIN
Content-Type: image/png;charset=utf-8
Transfer-Encoding: chunked
Date: Mon, 21 Dec 2020 13:19:10 GMT