diff --git a/php/docker/templates/nginx-vhost-conf.d/30-well-knonw-locations.conf b/php/docker/templates/nginx-vhost-conf.d/30-well-known-locations.conf similarity index 100% rename from php/docker/templates/nginx-vhost-conf.d/30-well-knonw-locations.conf rename to php/docker/templates/nginx-vhost-conf.d/30-well-known-locations.conf diff --git a/php/docker/templates/nginx-vhost-conf.d/75-page-cache-locations.conf b/php/docker/templates/nginx-vhost-conf.d/75-page-cache-locations.conf new file mode 100644 index 0000000..f7b4d91 --- /dev/null +++ b/php/docker/templates/nginx-vhost-conf.d/75-page-cache-locations.conf @@ -0,0 +1,57 @@ +# vim: set ft=nginx: + +{{- $chosenBackend := default "" .Env.STACK_PAGE_CACHE_BACKEND }} +{{- $redisHost := default "localhost" .Env.STACK_PAGE_CACHE_REDIS_HOST }} +{{- $redisPort := default "6379" .Env.STACK_PAGE_CACHE_REDIS_PORT }} +{{- $memcachedHost := default "127.0.0.1" .Env.STACK_PAGE_CACHE_MEMCACHED_HOST }} +{{- $memcachedPort := default "11211" .Env.STACK_PAGE_CACHE_MEMCACHED_PORT }} + +{{- if eq $chosenBackend "redis" }} + +location = /.stack-cache-fetch { + internal; + + set $redis_key $args; + redis_pass {{ $redisHost }}:{{ $redisPort }}; +} + +location = /.stack-cache-store { + internal; + + set_unescape_uri $exptime $arg_exptime; + set_unescape_uri $key $arg_key; + + redis2_query set $key $echo_request_body; + redis2_query expire $key $exptime; + redis2_pass {{ $redisHost }}:{{ $redisPort }}; +} + +{{- else if eq $chosenBackend "memcached" }} +location = /.stack-cache-fetch { + internal; + + set $memc_key $args; + + memc_connect_timeout 500ms; + memc_read_timeout 500ms; + memc_ignore_client_abort on; + + memc_pass {{ $memcachedHost }}:{{ $memcachedPort }}; +} + +location = /.stack-cache-store { + internal; + + set_unescape_uri $exptime $arg_exptime; + set_unescape_uri $key $arg_key; + + set $memc_key $key; + set $memc_exptime $exptime; + + memc_connect_timeout 500ms; + memc_send_timeout 500ms; + memc_ignore_client_abort on; + + memc_pass {{ $memcachedHost }}:{{ $memcachedPort }}; +} +{{- end }} diff --git a/php/docker/templates/nginx-vhost-conf.d/80-index.conf b/php/docker/templates/nginx-vhost-conf.d/80-index.conf index 58a9ebb..acf257d 100644 --- a/php/docker/templates/nginx-vhost-conf.d/80-index.conf +++ b/php/docker/templates/nginx-vhost-conf.d/80-index.conf @@ -5,8 +5,9 @@ location / { } location ~ \.php$ { - fastcgi_pass $upstream; + include /usr/local/docker/etc/nginx-vhost-conf.d/page-cache.d/*.conf; + fastcgi_pass $upstream; fastcgi_read_timeout {{ max 60 (add 10 (default "30" .Env.PHP_REQUEST_TIMEOUT | atoi)) }}; - fastcgi_index index.php; - include /usr/local/openresty/nginx/conf/fastcgi.conf; + fastcgi_index index.php; + include /usr/local/openresty/nginx/conf/fastcgi.conf; } diff --git a/php/docker/templates/nginx-vhost-conf.d/page-cache.d/10-index.conf b/php/docker/templates/nginx-vhost-conf.d/page-cache.d/10-index.conf new file mode 100644 index 0000000..1678f76 --- /dev/null +++ b/php/docker/templates/nginx-vhost-conf.d/page-cache.d/10-index.conf @@ -0,0 +1,156 @@ +# vim: set ft=nginx: + +{{- $chosenBackend := default "" .Env.STACK_PAGE_CACHE_BACKEND }} +{{- $allowedBackends := list "redis" "memcached" "custom" }} +{{- $memcachedHost := default "127.0.0.1" .Env.STACK_PAGE_CACHE_MEMCACHED_HOST }} +{{- $memcachedPort := default "11211" .Env.STACK_PAGE_CACHE_MEMCACHED_PORT }} +{{- $truthStrings := list "true" "on" "yes" -}} +{{- $keyPrefix := default "nginx-cache:" .Env.STACK_PAGE_CACHE_KEY_PREFIX }} +{{- $keyUID := default "https$request_method$host$request_uri" .Env.STACK_PAGE_CACHE_KEY_UID }} + +{{- if has $chosenBackend $allowedBackends }} +set $skip_cache 0; + +set_by_lua_block $skip_cache { + local scheme = ngx.var.scheme + local uri = ngx.var.request_uri + local request = ngx.ctx.request or {} + ngx.ctx.request = request + local user_agent = ngx.var.http_user_agent or '' + local request_method = ngx.req.get_method() + + re = {} + re.wp_loggedin = [[wordpress_logged_in|wordpress_no_cache|comment_author_|wp-postpass_|wp_gdsr_|fbs_|wp-query_monitor_]] + re.woocommerce_cookies = [[woocommerce_cart_hash|woocommerce_items_in_cart|wp_woocommerce_session_]] + re.woocommerce_args = [[remove_item|removed_item|remove_coupon|undo_item|order|add-to-cart|added-to-cart|revoke-key]] + re.bbpress_cookies = [[EmailID]] + + function find_plain(s, sub) + if string.find(s, sub, 1, true) == nil then + return false + end + + return true + end + + request.is_wp_admin = ( + not ngx.re.match(uri, "^.*/wp-admin/admin-ajax.php") + and ngx.re.match(uri, "^.*/(wp-admin/|wp-login.php|wp-signup.php|wp-cron.php|xmlrpc.php|git-webhook.php|feed/|sitemap.xml|sitemap_index.xml)", "o") + ) + + request.wp_loggedin = (ngx.re.match(ngx.var.http_cookie or '', re.wp_loggedin, 'io') and true or false) + + request.query_string = (ngx.var.is_args or '') .. (ngx.var.args or '') + + request.is_woocommerce = ( + ngx.re.match(request.query_string or '', re.woocommerce_args, 'io') or + (ngx.re.match(ngx.var.http_cookie or '', re.woocommerce_cookies, 'io') and true) or + (find_plain(uri, '/wc-api/') or ngx.re.match(request.query_string, 'wc-api=', 'o')) + ) + + request.is_dynamic = ( + request.is_wp_admin or + request.wp_loggedin or + request.is_woocommerce or + (request_method ~= 'GET' and + request_method ~= 'HEAD') or + -- skip cache if there are query strings (TODO: improve this logic for better cache hit) + request.query_string ~= '' + ) + + local cache_bypass = (ngx.var.skip_cache or '0') ~= '0' + or (ngx.re.match(ngx.var.http_cookie or '', re.bbpress_cookies, 'io') and true) + or false + + local skip_cache = 0 + if request.is_dynamic or cache_bypass then + skip_cache = 1 + end + + return skip_cache +} + +set $key ""; +set $key_prefix {{ $keyPrefix }}; +set $key_uid {{ $keyUID }}; +set $escaped_key ""; +set_escape_uri $escaped_key_prefix $key_prefix; +set_escape_uri $escaped_key_uid $key_uid; + +# Use versioned keys with memcached by default, for implementing cache flush +{{- if and (eq $chosenBackend "memcached") ( has (default "on" .Env.STACK_PAGE_CACHE_MEMCACHED_USE_VERSION) $truthStrings) }} +rewrite_by_lua_block { + if ngx.var.skip_cache == "1" then + return + end + + local memcached = require "resty.memcached" + + local function identity(key) return key end + + local memc, err = memcached:new{ + -- don't escape/unescape keys + key_transform = { identity, identity } + } + + if not memc then + ngx.log(ngx.ERR, "failed to instantiate memcached: ", err) + return + end + + memc:set_timeout(1000) + + local ok, err = memc:connect("{{ $memcachedHost }}:{{ $memcachedPort }}") + if not ok then + ngx.log(ngx.ERR, "failed to connect to memcached: ", err) + return + end + + local versionKey = ngx.var.key_prefix .. "version" + + local version, flags, err = memc:get(versionKey) + if err then + ngx.log(ngx.ERR, "failed to get memcached version: ", err) + return + end + + if not version then + ngx.log(ngx.INFO, "memcached version not found, attempting to set one...") + + version = tostring(os.time()) .. ":" + local ok, err = memc:set(versionKey, version) + if not ok then + ngx.log(ngx.ERR, "failed to set memcached version: ", err) + return + end + end + + ngx.var.key = ngx.var.key_prefix .. version .. ngx.var.key_uid + ngx.var.escaped_key = ngx.var.escaped_key_prefix .. ngx.escape_uri(version) .. ngx.var.escaped_key_uid + + local ok, err = memc:close() + if not ok then + ngx.say("failed to close memcached: ", err) + return + end +} + +{{- else }} +# default key is nginx-cache:https$request_method$host$request_uri +set $key $key_prefix$key_uid; +set $escaped_key $escaped_key_prefix$escaped_key_uid; +{{- end }} + +srcache_fetch_skip $skip_cache; +srcache_store_skip $skip_cache; +srcache_store_statuses {{ default "200 301 302" .Env.STACK_PAGE_CACHE_STORE_STATUSES }}; + +# https://github.com/openresty/srcache-nginx-module#srcache_response_cache_control +srcache_response_cache_control {{ default "on" .Env.STACK_PAGE_CACHE_RESPONSE_CACHE_CONTROL }}; + +srcache_fetch GET /.stack-cache-fetch $key; +srcache_store PUT /.stack-cache-store key=$escaped_key&exptime={{ default "360" .Env.STACK_PAGE_CACHE_EXPIRE_SECONDS | atoi }}; + +more_set_headers "x-cache-fetch $srcache_fetch_status"; + +{{- end }} \ No newline at end of file