NGINX and Lua scripting: conditional use in content_by_lua - nginx

I'm trying to create a conditional content_by_lua script, where the content should be set by lua only under a turthy condition.
example:
nginx.conf
location / {
content_by_lua_file /nginx/lua/nginx.lua;
root /nginx/www;
index index.html;
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff|ttf)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
}
nginx.lua
if condition then
ngx.header["Content-type"] = "text/html"
ngx.say('<H1>Hello World.</H1>');
ngx.exit(0)
else
-- serve the original content (index.html)
end
the problem is - lua scripting under nginx doesnt support 2 content directive within the same route, is there a workaround I can do?
with the current usage when the condition false I expect the index.html to be shown but receive a blank page instead

You can do a ngx.exec call which does an internal call.
nginx.conf
location / {
content_by_lua_file /nginx/lua/nginx.lua;
root /nginx/www;
index index.html;
location ~* \.(?:ico|css|js|gif|jpe?g|png|woff|ttf)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
}
location /default_index {
root /nginx/www;
index index.html;
}
nginx.lua
if condition then
ngx.header["Content-type"] = "text/html"
ngx.say('<H1>Hello World.</H1>');
ngx.exit(0)
else
-- serve the original content (index.html)
ngx.exec("/default_index", ngx.var.args)
end

Related

Nginx: How to set headers for all the files under a specific folder

So Let's say I have my application where files are under
https://myapp.com/v1/assets/images/*.jpg
and
https://myapp.com/v1/assets/js/*.jpg
I would like to add a rule that would set no-cache headers to anything under /assets
I believe what I can for now do is
location ~ .*assets/js/.*$ {
add_header Cache-Control "public, max-age=0, no-store";
}
location ~ .*assets/images/.*$ {
add_header Cache-Control "public, max-age=0, no-store";
}
But that seems not working plus if I have many other folders under assets, I will need to add a separate rule.
Can I group everything in a pattern so that anything under /assets/* would have that header?
Thanks
This can be done via map directive:
map $uri $cache_control {
~/assets/(images|js)/ "no-cache, no-store, must-revalidate";
}
server {
...
add_header Cache-Control $cache_control;
...
}
If your URI won't match the regex, $cache_control variable would have an empty value and nginx won't add that header to its response. However there are other nginx directives that could affect Cache-Control header, i.e. expires. If you have something like expires <value>; in your config, you can use two map blocks:
map $uri $cache_control {
~/assets/(images|js)/ "no-cache, no-store, must-revalidate";
}
map $uri $expire {
~/assets/(images|js)/ off;
default <value>;
}
server {
...
expires $expire;
add_header Cache-Control $cache_control;
...
}
And take a look at this answer to not be surprised with add_header directive behavior.

Disabling Cache-Control in Nginx for certain IPs

Static files on my server served with browser caching via Cache-Control headers:
location ~* \.(css|js|gif|jpe?g|png)$ {
expires 1h;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
Is it possible to disable this header for certain IPs so they would not cache any files?
P.S. I need it for users who log in as administrators to see the last changes.
The expires directive can be controlled by a variable, usually generated by a map directive. See this document for details.
For example:
map $remote_addr $expires {
default 1h;
10.1.2.3 -1;
}
server {
...
location ~* \.(css|js|gif|jpe?g|png)$ {
expires $expires;
add_header Pragma public;
add_header Cache-Control "public, must-revalidate, proxy-revalidate";
}
}
It is assumed that the add_header statements can remain, even if expires is set to -1 to disable the caching.

Define specific cache control header for selected file only

I'm setting up a Nginx sever (version 1.17.1) for Gatsby following up the recommendation at https://www.gatsbyjs.org/docs/caching/.
The snippet below is the portion my server {} block attempting implementing the recommended caching configuration;
location ~* \.(?:html)$ {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location /static {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(?:css|js)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location /sw\.js {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
Equally tried an if statement in place of the location {} block for defining cache configuration for the service worker file, sw.js, as below;
if ($request_uri ~ ^sw\.(?:js)$) {
set $no_cache 1;
}
Unfortunately, all files get cached successfully as expected except sw.js.
What am I doing wrong and how can I fix it so as to effectively set cache control header for sw.js to public, max-age=0, must-revalidate?
I ended up with the following nginx configuration regarding caching for Gatsby.js:
location ~* \.(?:html)$ {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location /page-data {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location = /sw.js {
add_header Cache-Control "public, max-age=0, must-revalidate";
}
location /static {
add_header Cache-Control "public, max-age=31536000, immutable";
}
location ~* \.(?:js|css)$ {
add_header Cache-Control "public, max-age=31536000, immutable";
}
#OP: With which configuration did you end up? Maybe you can edit this answer to match the perfect solution after all; for people searching for "caching nginx gatsby".
The order of precedence of location is described here https://nginx.org/en/docs/http/ngx_http_core_module.html#location
When an exact match is found (using the = modifier) the search terminates and regular expressions will not be checked, so you can use that for your sw.js:
location = /sw.js {
add_header Cache-Control "public, max-age=0, must-revalidate";
}

Set headers for .apk files served by nginx

In my server block I have
location / {
proxy_pass http://echocdn;
include /etc/nginx/mime.types;
add_header Cache-Control "max-age=31536000, private, no-transform, no-cache";
location ~* \.apk$ {
add_header Content-Type application/vnd.android.package-archive;
add_header Content-Disposition "attachment";
}
}
If I remove the inner location block, I can reach the APK file (and all other files).
With the block added, any .apk file returns a 404. How do I add the headers for APK files?
Note: Content types for other file types are handled well by the included mime.types, but even if I add the line for APK files as described How to download ".apk" as ".apk"? (not as ".zip") and https://blog.mypapit.net/2015/08/how-to-set-apk-mime-type-for-nginx-web-server.html it only returns a content-type of text/html for apk files.
maybe it's better not to set a header directly, for me it resulted in a double content-type.
but if you declare it in the location-block types it also works fine.
take a look:
location ~* \.apk$ {
types {
application/vnd.android.package-archive apk;
}
add_header Content-Disposition "attachment";
}
You need to have proxy_pass inside the apk block also. Nginx doesn't work like a programming language so you are not executing anything from the parent block.
Also for setting the content type using default_type directive
location / {
proxy_pass http://echocdn;
include /etc/nginx/mime.types;
#proxy_pass http://127.0.0.1:8082;
add_header Cache-Control "max-age=31536000, private, no-transform, no-cache";
location ~* \.apk$ {
default_type application/vnd.android.package-archive;
add_header Content-Type application/vnd.android.package-archive;
add_header Content-Disposition "attachment";
proxy_pass http://echocdn;
}
}
You can even handle this with a if
location / {
proxy_pass http://echocdn;
include /etc/nginx/mime.types;
#proxy_pass http://127.0.0.1:8082;
add_header Cache-Control "max-age=31536000, private, no-transform, no-cache";
if ($request_uri ~* \.apk$) {
default_type application/vnd.android.package-archive;
add_header Content-Type application/vnd.android.package-archive;
add_header Content-Disposition "attachment";
}
}
Try this:
location ~*.(apk)${
root /tmp/app;
add_header Content-Disposition attachment;
}
/tmp/app is your APK files full path.

How to add headers to only specific files with nginx

I have pictures, and I want to add their headers to max, I have profile pictures which can be changed and post pictures, I want to add headers only for post pictures, but not to profile pictures, I have no idea how can I manage this. thank you, this is my configuration,
this is the path of posts, /post/name-of-the-picture.jpg
this is the path of users, /user/name-of-the-picture.jpg
I only want to add headers to post path
location ~* \.(css|js|png|gif)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public";
}
Currently we have two options to solve this:
Option 1:
Duplicated locations: NGINX looks for the best match. (a little better performance)
location /post/ {
post config stuff;
.
.
.
}
location ~* ^/post/.*\.(css|js|png|gif)$ {
post/files.(css|js|png|gif) config stuff;
expires max;
add_header Pragma public;
add_header Cache-Control "public";
}
location /user/ {
user folder config stuff;
.
.
.
}
location ~* ^/user/.*\.(css|js|png|gif)$ {
user/files.(css|js|png|gif) config stuff;
.
.
.
}
Option 2:
Nested locations: Filtered by extension in the inner location blocks
location /post/{
...
location ~* \.(css|js|png|gif)$ {
expires max;
add_header Pragma public;
add_header Cache-Control "public";
}
}
location /user/{
...
location ~* \.(css|js|png|gif)$ {
...
}
}

Resources