OpenResty Edge caches HTTP responses at the gateway (edge node), so requests that hit the cache never reach your backend—cutting origin load and response latency. You turn on the proxy cache with a single switch in a page rule, set the cache key, and release it to every gateway node with no Nginx config or reload. This tutorial shows how, then verifies each Cache-Status: HIT or MISS with curl and shows how to enforce caching even when the origin sends no Cache-Control header.

On a cache miss, the edge node forwards the request to the backend server

When the client requests hit the cache on the Edge Node server, no requests need to be sent to the backend server. This reduces response latency and saves network bandwidth—the same mechanism behind building a private CDN with OpenResty Edge.

On a cache hit, the edge node serves the response without contacting the backend

Enable Proxy Cache in a Page Rule and Set the Cache Key

Let’s go to the OpenResty Edge’s Admin web console. This is our sample deployment of the console. Every user has her own deployment.

We can continue with our previous application example, test-edge.com.

The OpenResty Edge Admin web console home page

We already have an upstream defined.

The upstream list showing a defined backend upstream

This my_backend upstream has only 1 backend server.

The my_backend upstream configured with a single backend server

Note the IP address of the backend server ends with number 191. We will use this IP address later.

The backend server IP address ending in 191

And we also have a page rule already defined.

The page rule list with a rule already defined

This page rule sets up a reverse proxy to this upstream.

The page rule configured as a reverse proxy to the upstream

Apparently we haven’t enabled the proxy cache for this page rule yet.

Now let’s edit this page rule to add response caching in the gateway.

Editing the page rule to add proxy cache

Let’s enable the proxy cache.

Turning on the proxy cache switch in the page rule

Here we can configure the cache key.

Configuring the cache key for the proxy cache

By default, the cache key consists of two components: the URI, and the query string.

You can choose to use other kinds of key components.

Choosing additional cache key components

The list of available cache key component types

Or we can remove the whole query string from the key.

Removing the query string from the cache key

We can also add even more key components.

Adding more components to the cache key

For this example, we’ll just keep the default cache key.

Save this page rule.

Saving the page rule with proxy cache enabled

Let’s make a new release.

Creating a new release for the pending changes

Push out our pending changes.

Reviewing the pending changes before pushing them out

Ship it!

Confirming the release to ship the changes

Our new release is now synchronized to all our gateway servers.

The new release synchronized to all gateway servers

Our configuration changes do NOT require server reload, restart, or binary upgrade. So it’s very efficient.

The configuration change propagating to gateway nodes without a reload

Test the Cache and Verify Cache-Status HIT/MISS with curl

Let’s test a gateway server for caching.

The gateway server list in the OpenResty Edge console

We copy the IP address of this San Francisco gateway server.

Copying the IP address of the San Francisco gateway server

Note the last number of this IP address is 133.

On the terminal, we send an HTTP request to this gateway server via the curl command-line utility.

curl -I -H 'Host: test-edge.com' http://138.68.231.133/

Note the Cache-Status: MISS response header returned.

The curl response showing a Cache-Status: MISS header

Do it again.

curl -I -H 'Host: test-edge.com' http://138.68.231.133/

We are still getting the Cache-Status: MISS header. It means that the cache is not used at all. Why? Because the original response header from the backend server lacks headers like Expires and Cache-Control.

The second request still returning Cache-Status: MISS

We can log onto the backend server.

ssh ec2-user@54.213.103.191

Recall that the backend server’s IP address ends with 191.

Logging onto the backend server whose IP ends in 191

This backend server runs the open source OpenResty software.

ps aux | grep nginx

The backend running the open source OpenResty nginx processes

The backend server may run any other software that speaks HTTP.

Any HTTP-speaking software can serve as an edge backend

We can send a test request to this backend server directly.

curl -I -H 'Host: test-edge.com' http://127.0.0.1/

Note that we are accessing the local host.

Sending a curl request directly to the backend on localhost

Okay, it indeed does not provide any Expires or Cache-Control headers.

The backend response with no Expires or Cache-Control headers

Now let’s re-configure our backend server.

cd /usr/local/openresty/nginx/

Open the nginx configuration file.

sudo vim conf/nginx.conf

Find our root location, location /.

Finding the root location block in the nginx configuration file

And add an expiration time of 1 hour.

expires 1h;

Note that the backend server can define different expiration times for different locations. Or disable the cache completely for certain responses.

Adding an expires 1h directive to the backend location block

Save and quit the file.

Test if the nginx configuration file is correct.

sudo ./sbin/nginx -t

Good.

Testing the nginx configuration file with nginx -t

Now reload the server.

sudo kill -HUP `cat logs/nginx.pid`

Reloading the backend nginx server with a HUP signal

Note that for open source Nginx servers, the configuration is also the same.

Time to test the backend server again.

curl -I -H 'Host: test-edge.com' http://127.0.0.1/

Yay! It responds with the Expires and Cache-Control headers now.

The backend now returning Expires and Cache-Control headers

Send the request to the gateway server instead.

curl -I -H 'Host: test-edge.com' http://138.68.231.133/

It still shows the Cache-Status: MISS header.

The first gateway request returning Cache-Status: MISS

It is an expected cache miss. Because this is our very first request.

Diagram of the first request missing the cache and reaching the backend

Send the request again.

curl -I -H 'Host: test-edge.com' http://138.68.231.133/

Great! We finally see the Cache-Status: HIT header!

The second gateway request returning Cache-Status: HIT

So it is now a cache hit as expected.

Diagram of the second request served from cache without hitting the backend

If we add a query string,

curl -I -H 'Host: test-edge.com' 'http://138.68.231.133/?a=3'

Note the a=3 part.

A request with an a=3 query string returning a cache miss

then it will be a cache miss again.

This is because the default cache key includes the query string.

The query string is part of the default cache key, causing the miss

Running the same request again should result in a cache hit.

curl -I -H 'Host: test-edge.com' 'http://138.68.231.133/?a=3'

It’s indeed a cache hit now. If you don’t care about the query string, you can remove it from the cache key.

Repeating the query-string request returns a cache hit

Enforce Cache Without a Cache-Control Header

Sometimes we are just too lazy to change the backend server’s configuration. Then we can also enforce caching for responses without any cache controlling headers in the gateway.

We can change our original page rule to enable this feature.

We enforce caching by default.

Enabling enforced caching by default in the page rule

We can set the default expiration time for cacheable response status codes.

Setting the default expiration time for cacheable response status codes

We’ll demonstrate this feature in another video. Once responses are cached, you can also purge the HTTP cache in real time whenever the origin content changes.

Frequently Asked Questions

Why does OpenResty Edge return Cache-Status: MISS even after I enable the proxy cache?

A Cache-Status: MISS after enabling the proxy cache usually means the origin response is not cacheable. In this demo the backend sends no Expires or Cache-Control header, so the gateway will not cache it. Adding expires 1h; to the backend location makes the origin emit those headers, after which the second request returns Cache-Status: HIT.

How do I cache responses when the backend sends no Cache-Control header?

Edit the page rule and turn on enforced caching so the gateway caches responses even when the origin omits cache-controlling headers. You then set a default expiration time for the cacheable response status codes. This lets you cache at the edge without touching the backend server’s configuration at all.

Why does adding a query string cause a cache miss?

By default the cache key is built from the URI plus the query string, so a request with ?a=3 is a different key from one without it and misses the cache on its first hit. Running the same query-string request again returns a hit. If the query string does not affect the response, remove it from the cache key so all variants share one cached entry.

Do OpenResty Edge cache changes require an Nginx reload or restart?

No. Enabling the proxy cache and releasing the change synchronizes to every gateway server without a server reload, restart, or binary upgrade, so the new caching behavior takes effect with no downtime.

What is OpenResty Edge

OpenResty Edge is our all-in-one gateway software for microservices and distributed traffic architectures. It combines traffic management, private CDN construction, API gateway, security, and more to help you easily build, manage, and protect modern applications. OpenResty Edge delivers industry-leading performance and scalability to meet the demanding needs of high concurrency, high load scenarios. It supports scheduling containerized application traffic such as K8s and manages massive domains, making it easy to meet the needs of large websites and complex applications.

If you like this tutorial, please subscribe to this blog site and/or our YouTube channel. Thank you!

About The Author

Yichun Zhang (Github handle: agentzh), is the original creator of the OpenResty® open-source project and the CEO of OpenResty Inc..

Yichun is one of the earliest advocates and leaders of “open-source technology”. He worked at many internationally renowned tech companies, such as Cloudflare, Yahoo!. He is a pioneer of “edge computing”, “dynamic tracing” and “machine coding”, with over 22 years of programming and 16 years of open source experience. Yichun is well-known in the open-source space as the project leader of OpenResty®, adopted by more than 40 million global website domains.

OpenResty Inc., the enterprise software start-up founded by Yichun in 2017, has customers from some of the biggest companies in the world. Its flagship product, OpenResty XRay, is a non-invasive profiling and troubleshooting tool that significantly enhances and utilizes dynamic tracing technology. And its OpenResty Edge product is a powerful distributed traffic management and private CDN software product.

As an avid open-source contributor, Yichun has contributed more than a million lines of code to numerous open-source projects, including Linux kernel, Nginx, LuaJIT, GDB, SystemTap, LLVM, Perl, etc. He has also authored more than 60 open-source software libraries.