diff --git a/README.md b/README.md
index 5dc0542..00449e4 100644
--- a/README.md
+++ b/README.md
@@ -14,13 +14,13 @@ Once you are done, you can open a pull request, or [email me](mailto:daniel@danw
 Installation Instructions:
 --------------------------
 
-The configuration was tested with a standard Debian bookworm and Ubuntu 22.04 LTS installation. It's recommended you install Debian bookworm (or newer) on your server, but with a little tweaking you may also get this working on other distributions and/or versions. If you want to build it on a raspberry pi, please do not use the raspbian images as several things will break. Download an image for your pi model from [https://raspi.debian.net/daily-images/](https://raspi.debian.net/daily-images/) instead.
+The configuration was tested with a standard Debian bookworm and Ubuntu 24.04 LTS installation. It's recommended you install Debian bookworm (or newer) on your server, but with a little tweaking you may also get this working on other distributions and/or versions. If you want to build it on a raspberry pi, please do not use the raspbian images as several things will break. Download an image for your pi model from [https://raspi.debian.net/daily-images/](https://raspi.debian.net/daily-images/) instead.
 
 Because I regularly get asked to make a video tutorial on how to set this up, I decided to create a tutorial which you can [watch on YouTube](https://www.youtube.com/watch?v=f2-SOlnIYmg). It is basically just copy-pasting commands, but maybe it helps someone.
 
 Uninstall packages that may interfere with this setup:
 ```
-DEBIAN_FRONTEND=noninteractive apt-get purge -y apache2* dnsmasq* eatmydata exim4* imagemagick-6-common mysql-client* mysql-server* nginx* libnginx-mod* php7* resolvconf && systemctl disable systemd-resolved.service && systemctl stop systemd-resolved.service
+DEBIAN_FRONTEND=noninteractive apt purge -y apache2* dnsmasq* eatmydata exim4* imagemagick-6-common mysql-client* mysql-server* nginx* libnginx-mod* php7* resolvconf && systemctl disable systemd-resolved.service && systemctl stop systemd-resolved.service
 ```
 
 If you have problems resolving hostnames after this step, temporarily switch to a public nameserver like 1.1.1.1 (from CloudFlare) or 8.8.8.8 (from Google)
@@ -29,10 +29,20 @@ If you have problems resolving hostnames after this step, temporarily switch to
 rm /etc/resolv.conf && echo "nameserver 1.1.1.1" > /etc/resolv.conf
 ```
 
+Add additional repositories:
+```
+apt update && apt install git
+curl -sSL https://deb.torproject.org/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc > /etc/apt/trusted.gpg.d/torproject.gpg
+curl -sSL https://packages.sury.org/nginx/apt.gpg > /etc/apt/trusted.gpg.d/sury.gpg
+echo "deb tor://apow7mjfryruh65chtdydfmqfpj5btws7nbocgtaovhvezgccyjazpqd.onion/torproject.org/ `lsb_release -cs` main" >> /etc/apt/sources.list
+echo "deb https://packages.sury.org/nginx/ `lsb_release -cs` main" >> /etc/apt/sources.list
+apt update && apt upgrade
+```
+
 Install git and clone this repository
 
 ```
-apt-get update && apt-get install git && git clone https://github.com/DanWin/hosting && cd hosting
+apt update && apt install git && git clone https://github.com/DanWin/hosting && cd hosting
 ```
 
 Install custom optimized binaries
@@ -40,15 +50,6 @@ Install custom optimized binaries
 ./install_binaries.sh
 ```
 
-To get the latest mariadb version, you should follow these instructions to add the official repository for your distribution: (https://downloads.mariadb.org/mariadb/repositories/)
-
-Add torproject to our repositories:
-```
-curl --socks5-hostname 127.0.0.1:9050 -sSL http://apow7mjfryruh65chtdydfmqfpj5btws7nbocgtaovhvezgccyjazpqd.onion/torproject.org/A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89.asc > /etc/apt/trusted.gpg.d/torproject.gpg
-echo "deb tor://apow7mjfryruh65chtdydfmqfpj5btws7nbocgtaovhvezgccyjazpqd.onion/torproject.org/ `lsb_release -cs` main" >> /etc/apt/sources.list
-apt-get update && apt-get upgrade
-```
-
 Note that debian also has an onion service package archive, so you may want to edit /etc/apt/sources.list to load from there instead:
 ```
 deb tor://2s4yqjx5ul6okpp3f2gaunr2syex5jgbfpfvhxxbbjwnrsvbk5v3qbid.onion/debian `lsb_release -cs` main
diff --git a/etc/nginx/nginx.conf b/etc/nginx/nginx.conf
index 97db4c5..b1cb25e 100644
--- a/etc/nginx/nginx.conf
+++ b/etc/nginx/nginx.conf
@@ -2,6 +2,7 @@ daemon on;
 user www-data;
 worker_processes 1;
 pid /run/nginx.pid;
+include /etc/nginx/modules-enabled/*.conf;
 pcre_jit on;
 worker_rlimit_nofile 100000;
 worker_shutdown_timeout 30m;
diff --git a/install_binaries.sh b/install_binaries.sh
index 278fbb6..4755087 100755
--- a/install_binaries.sh
+++ b/install_binaries.sh
@@ -6,9 +6,9 @@ export LANG=C.UTF-8
 export PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
 # install all required packages
 DEBIAN_FRONTEND=noninteractive apt-get update
-DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -y apt-transport-tor bash-completion bind9 brotli bzip2 ca-certificates clamav-daemon clamav-freshclam curl dovecot-imapd dovecot-lmtpd dovecot-pop3d git hardlink haveged iptables libio-socket-ip-perl libsasl2-modules locales locales-all logrotate lsb-release mariadb-server nano postfix postfix-mysql quota quotatool redis rspamd rsync ssh tor unzip util-linux vim wget xz-utils zip zopfli
+DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -y apt-transport-tor bash-completion bind9 brotli bzip2 ca-certificates clamav-daemon clamav-freshclam curl dovecot-imapd dovecot-lmtpd dovecot-pop3d git hardlink haveged iptables libio-socket-ip-perl libnginx-mod-http-brotli libnginx-mod-stream libsasl2-modules locales locales-all logrotate lsb-release mariadb-server nano nginx postfix postfix-mysql quota quotatool redis rspamd rsync ssh tor unzip util-linux vim wget xz-utils zip zopfli
 # build dependencies
-DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -y autoconf automake bison g++ gcc ghostscript gnupg libaom-dev `apt-cache search --names-only 'libargon2(-0)?-dev' | awk '{print $1;}' | head -n1` binutils-dev libbrotli-dev libbz2-dev libc-client2007e-dev libcurl4-openssl-dev libde265-dev libdjvulibre-dev libedit-dev `apt-cache search --names-only 'libenchant(-2)?-dev' | awk '{print $1;}' | head -n1` libffi-dev `apt-cache search --names-only libfreetype6?-dev | awk '{print $1;}' | head -n1` libfftw3-dev libfribidi-dev libgd-dev libgmp-dev libgpg-error-dev libgpgme-dev libgraphviz-dev libgs-dev libharfbuzz-dev libheif-dev libjbig-dev libjbig2dec0-dev libjxl-dev libkrb5-dev libldap2-dev liblmdb-dev liblqr-1-0-dev libmariadb-dev libonig-dev libopenexr-dev libopenjp2-7-dev libpango1.0-dev libpcre3-dev libpng-dev libpspell-dev libqdbm-dev libraqm-dev libraw-dev libreadline-dev librsvg2-dev libsasl2-dev libsodium-dev libssh2-1-dev libssl-dev libsqlite3-dev libsystemd-dev libtidy-dev libtool libwebp-dev libwmf-dev libx265-dev libxml2-dev libxpm-dev libxslt1-dev libzip-dev libzstd-dev make poppler-utils re2c zlib1g-dev
+DEBIAN_FRONTEND=noninteractive apt-get --no-install-recommends install -y autoconf automake bison g++ gcc ghostscript gnupg libaom-dev `apt-cache search --names-only 'libargon2(-0)?-dev' | awk '{print $1;}' | head -n1` binutils-dev libbrotli-dev libbz2-dev libc-client2007e-dev libcurl4-openssl-dev libdjvulibre-dev libedit-dev `apt-cache search --names-only 'libenchant(-2)?-dev' | awk '{print $1;}' | head -n1` libffi-dev `apt-cache search --names-only libfreetype6?-dev | awk '{print $1;}' | head -n1` libfftw3-dev libfribidi-dev libgd-dev libgmp-dev libgpg-error-dev libgpgme-dev libgraphviz-dev libgs-dev libharfbuzz-dev libheif-dev libjbig-dev libjbig2dec0-dev libjxl-dev libkrb5-dev libldap2-dev liblmdb-dev liblqr-1-0-dev libmariadb-dev libonig-dev libopenexr-dev libopenjp2-7-dev libpango1.0-dev libpng-dev libpspell-dev libqdbm-dev libraqm-dev libraw-dev libreadline-dev librsvg2-dev libsasl2-dev libsodium-dev libssh2-1-dev libssl-dev libsqlite3-dev libsystemd-dev libtidy-dev libtool libwebp-dev libwmf-dev libxml2-dev libxpm-dev libxslt1-dev libzip-dev libzstd-dev make poppler-utils re2c zlib1g-dev
 
 # install nvm
 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
@@ -27,14 +27,6 @@ npm i -g yarn
 if [ ! -e ImageMagick ]; then
 	git clone https://github.com/ImageMagick/ImageMagick
 fi
-if [ ! -e nginx ]; then
-	git clone https://github.com/nginx/nginx
-fi
-cd nginx
-if [ ! -e ngx_brotli ]; then
-	git clone https://github.com/google/ngx_brotli
-fi
-cd ..
 if [ ! -e php-src ]; then
 	git clone https://github.com/php/php-src
 fi
@@ -66,1242 +58,11 @@ export PROC_LIMIT=`free -g | grep Mem | awk -v nproc=$(nproc) '{print (($2 + 1)
 #start build
 cd ImageMagick
 git fetch --all
-git checkout 7.1.1-34
+git checkout 7.1.1-36
 CXXFLAGS='-O3 -mtune=native -march=native' CFLAGS='-O3 -mtune=native -march=native' ./configure --without-perl --without-magick-plus-plus --disable-openmp --with-fftw --with-gslib --with-gvc --with-rsvg --with-wmf
 make -j $PROC_LIMIT install
 make distclean
 ldconfig
-cd ../nginx
-git fetch --all
-git checkout release-1.27.0
-cd ngx_brotli && git fetch --all && git checkout 6e975bcb015f62e1f303054897783355e2a877dc && cd ..
-# apply dynamic TLS record and HTTP2 HPACK patch by CloudFlare
-cat <<EOF | git apply -
-diff --git a/auto/modules b/auto/modules
-index f1c63f3d..edb7863f 100644
---- a/auto/modules
-+++ b/auto/modules
-@@ -423,6 +423,10 @@ if [ \$HTTP = YES ]; then
-         . auto/module
-     fi
- 
-+    if [ \$HTTP_V2_HPACK_ENC = YES ]; then
-+        have=NGX_HTTP_V2_HPACK_ENC . auto/have
-+    fi
-+
-     if :; then
-         ngx_module_name=ngx_http_static_module
-         ngx_module_incs=
-diff --git a/auto/options b/auto/options
-index 0b21def2..69ea76cb 100644
---- a/auto/options
-+++ b/auto/options
-@@ -59,6 +59,7 @@ HTTP_CHARSET=YES
- HTTP_GZIP=YES
- HTTP_SSL=NO
- HTTP_V2=NO
-+HTTP_V2_HPACK_ENC=NO
- HTTP_V3=NO
- HTTP_SSI=YES
- HTTP_REALIP=NO
-@@ -235,6 +236,7 @@ \$0: warning: the \"--with-ipv6\" option is deprecated"
- 
-         --with-http_ssl_module)          HTTP_SSL=YES               ;;
-         --with-http_v2_module)           HTTP_V2=YES                ;;
-+        --with-http_v2_hpack_enc)        HTTP_V2_HPACK_ENC=YES      ;;
-         --with-http_v3_module)           HTTP_V3=YES                ;;
-         --with-http_realip_module)       HTTP_REALIP=YES            ;;
-         --with-http_addition_module)     HTTP_ADDITION=YES          ;;
-@@ -456,6 +458,7 @@ cat << END
- 
-   --with-http_ssl_module             enable ngx_http_ssl_module
-   --with-http_v2_module              enable ngx_http_v2_module
-+  --with-http_v2_hpack_enc           enable ngx_http_v2_hpack_enc
-   --with-http_v3_module              enable ngx_http_v3_module
-   --with-http_realip_module          enable ngx_http_realip_module
-   --with-http_addition_module        enable ngx_http_addition_module
-diff --git a/src/core/ngx_murmurhash.c b/src/core/ngx_murmurhash.c
-index 5ade658d..4932f20d 100644
---- a/src/core/ngx_murmurhash.c
-+++ b/src/core/ngx_murmurhash.c
-@@ -50,3 +50,63 @@ ngx_murmur_hash2(u_char *data, size_t len)
- 
-     return h;
- }
-+
-+
-+uint64_t
-+ngx_murmur_hash2_64(u_char *data, size_t len, uint64_t seed)
-+{
-+    uint64_t  h, k;
-+
-+    h = seed ^ len;
-+
-+    while (len >= 8) {
-+        k  = data[0];
-+        k |= data[1] << 8;
-+        k |= data[2] << 16;
-+        k |= data[3] << 24;
-+        k |= (uint64_t)data[4] << 32;
-+        k |= (uint64_t)data[5] << 40;
-+        k |= (uint64_t)data[6] << 48;
-+        k |= (uint64_t)data[7] << 56;
-+
-+        k *= 0xc6a4a7935bd1e995ull;
-+        k ^= k >> 47;
-+        k *= 0xc6a4a7935bd1e995ull;
-+
-+        h ^= k;
-+        h *= 0xc6a4a7935bd1e995ull;
-+
-+        data += 8;
-+        len -= 8;
-+    }
-+
-+    switch (len) {
-+    case 7:
-+        h ^= (uint64_t)data[6] << 48;
-+        /* fall through */
-+    case 6:
-+        h ^= (uint64_t)data[5] << 40;
-+        /* fall through */
-+    case 5:
-+        h ^= (uint64_t)data[4] << 32;
-+        /* fall through */
-+    case 4:
-+        h ^= data[3] << 24;
-+        /* fall through */
-+    case 3:
-+        h ^= data[2] << 16;
-+        /* fall through */
-+    case 2:
-+        h ^= data[1] << 8;
-+        /* fall through */
-+    case 1:
-+        h ^= data[0];
-+        h *= 0xc6a4a7935bd1e995ull;
-+    }
-+
-+    h ^= h >> 47;
-+    h *= 0xc6a4a7935bd1e995ull;
-+    h ^= h >> 47;
-+
-+    return h;
-+}
-diff --git a/src/core/ngx_murmurhash.h b/src/core/ngx_murmurhash.h
-index 54e867d3..322b3df9 100644
---- a/src/core/ngx_murmurhash.h
-+++ b/src/core/ngx_murmurhash.h
-@@ -15,5 +15,7 @@
- 
- uint32_t ngx_murmur_hash2(u_char *data, size_t len);
- 
-+uint64_t ngx_murmur_hash2_64(u_char *data, size_t len, uint64_t seed);
-+
- 
- #endif /* _NGX_MURMURHASH_H_INCLUDED_ */
-diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
-index fd2b92ff..397a4114 100644
---- a/src/event/ngx_event_openssl.c
-+++ b/src/event/ngx_event_openssl.c
-@@ -1590,6 +1590,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
- 
-     sc->buffer = ((flags & NGX_SSL_BUFFER) != 0);
-     sc->buffer_size = ssl->buffer_size;
-+    sc->dyn_rec = ssl->dyn_rec;
- 
-     sc->session_ctx = ssl->ctx;
- 
-@@ -2525,6 +2526,41 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
- 
-     for ( ;; ) {
- 
-+        /* Dynamic record resizing:
-+           We want the initial records to fit into one TCP segment
-+           so we don't get TCP HoL blocking due to TCP Slow Start.
-+           A connection always starts with small records, but after
-+           a given amount of records sent, we make the records larger
-+           to reduce header overhead.
-+           After a connection has idled for a given timeout, begin
-+           the process from the start. The actual parameters are
-+           configurable. If dyn_rec_timeout is 0, we assume dyn_rec is off. */
-+
-+        if (c->ssl->dyn_rec.timeout > 0 ) {
-+
-+            if (ngx_current_msec - c->ssl->dyn_rec_last_write >
-+                c->ssl->dyn_rec.timeout)
-+            {
-+                buf->end = buf->start + c->ssl->dyn_rec.size_lo;
-+                c->ssl->dyn_rec_records_sent = 0;
-+
-+            } else {
-+                if (c->ssl->dyn_rec_records_sent >
-+                    c->ssl->dyn_rec.threshold * 2)
-+                {
-+                    buf->end = buf->start + c->ssl->buffer_size;
-+
-+                } else if (c->ssl->dyn_rec_records_sent >
-+                           c->ssl->dyn_rec.threshold)
-+                {
-+                    buf->end = buf->start + c->ssl->dyn_rec.size_hi;
-+
-+                } else {
-+                    buf->end = buf->start + c->ssl->dyn_rec.size_lo;
-+                }
-+            }
-+        }
-+
-         while (in && buf->last < buf->end && send < limit) {
-             if (in->buf->last_buf || in->buf->flush) {
-                 flush = 1;
-@@ -2632,6 +2668,9 @@ ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size)
- 
-     if (n > 0) {
- 
-+        c->ssl->dyn_rec_records_sent++;
-+        c->ssl->dyn_rec_last_write = ngx_current_msec;
-+
-         if (c->ssl->saved_read_handler) {
- 
-             c->read->handler = c->ssl->saved_read_handler;
-diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
-index 329760d0..2c72f932 100644
---- a/src/event/ngx_event_openssl.h
-+++ b/src/event/ngx_event_openssl.h
-@@ -66,11 +66,19 @@
- 
- typedef struct ngx_ssl_ocsp_s  ngx_ssl_ocsp_t;
- 
-+typedef struct {
-+    ngx_msec_t                  timeout;
-+    ngx_uint_t                  threshold;
-+    size_t                      size_lo;
-+    size_t                      size_hi;
-+} ngx_ssl_dyn_rec_t;
-+
- 
- struct ngx_ssl_s {
-     SSL_CTX                    *ctx;
-     ngx_log_t                  *log;
-     size_t                      buffer_size;
-+    ngx_ssl_dyn_rec_t           dyn_rec;
- };
- 
- 
-@@ -115,6 +123,11 @@ struct ngx_ssl_connection_s {
-     unsigned                    shutdown_without_free:1;
-     unsigned                    handshake_buffer_set:1;
-     unsigned                    session_timeout_set:1;
-+
-+    ngx_ssl_dyn_rec_t           dyn_rec;
-+    ngx_msec_t                  dyn_rec_last_write;
-+    ngx_uint_t                  dyn_rec_records_sent;
-+
-     unsigned                    try_early_data:1;
-     unsigned                    in_early:1;
-     unsigned                    in_ocsp:1;
-@@ -115,7 +128,7 @@ struct ngx_ssl_connection_s {
- #define NGX_SSL_DFLT_BUILTIN_SCACHE  -5
- 
- 
--#define NGX_SSL_MAX_SESSION_SIZE  4096
-+#define NGX_SSL_MAX_SESSION_SIZE  16384
- 
- typedef struct ngx_ssl_sess_id_s  ngx_ssl_sess_id_t;
- 
-diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
-index e062b03a..2dae17d4 100644
---- a/src/http/modules/ngx_http_ssl_module.c
-+++ b/src/http/modules/ngx_http_ssl_module.c
-@@ -301,6 +301,41 @@ static ngx_command_t  ngx_http_ssl_commands[] = {
-       offsetof(ngx_http_ssl_srv_conf_t, reject_handshake),
-       NULL },
- 
-+    { ngx_string("ssl_dyn_rec_enable"),
-+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-+      ngx_conf_set_flag_slot,
-+      NGX_HTTP_SRV_CONF_OFFSET,
-+      offsetof(ngx_http_ssl_srv_conf_t, dyn_rec_enable),
-+      NULL },
-+
-+    { ngx_string("ssl_dyn_rec_timeout"),
-+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-+      ngx_conf_set_msec_slot,
-+      NGX_HTTP_SRV_CONF_OFFSET,
-+      offsetof(ngx_http_ssl_srv_conf_t, dyn_rec_timeout),
-+      NULL },
-+
-+    { ngx_string("ssl_dyn_rec_size_lo"),
-+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-+      ngx_conf_set_size_slot,
-+      NGX_HTTP_SRV_CONF_OFFSET,
-+      offsetof(ngx_http_ssl_srv_conf_t, dyn_rec_size_lo),
-+      NULL },
-+
-+    { ngx_string("ssl_dyn_rec_size_hi"),
-+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-+      ngx_conf_set_size_slot,
-+      NGX_HTTP_SRV_CONF_OFFSET,
-+      offsetof(ngx_http_ssl_srv_conf_t, dyn_rec_size_hi),
-+      NULL },
-+
-+    { ngx_string("ssl_dyn_rec_threshold"),
-+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
-+      ngx_conf_set_num_slot,
-+      NGX_HTTP_SRV_CONF_OFFSET,
-+      offsetof(ngx_http_ssl_srv_conf_t, dyn_rec_threshold),
-+      NULL },
-+
-       ngx_null_command
- };
- 
-@@ -637,6 +672,11 @@ ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
-     sscf->ocsp_cache_zone = NGX_CONF_UNSET_PTR;
-     sscf->stapling = NGX_CONF_UNSET;
-     sscf->stapling_verify = NGX_CONF_UNSET;
-+    sscf->dyn_rec_enable = NGX_CONF_UNSET;
-+    sscf->dyn_rec_timeout = NGX_CONF_UNSET_MSEC;
-+    sscf->dyn_rec_size_lo = NGX_CONF_UNSET_SIZE;
-+    sscf->dyn_rec_size_hi = NGX_CONF_UNSET_SIZE;
-+    sscf->dyn_rec_threshold = NGX_CONF_UNSET_UINT;
- 
-     return sscf;
- }
-@@ -694,6 +734,20 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
-     ngx_conf_merge_str_value(conf->stapling_responder,
-                          prev->stapling_responder, "");
- 
-+    ngx_conf_merge_value(conf->dyn_rec_enable, prev->dyn_rec_enable, 0);
-+    ngx_conf_merge_msec_value(conf->dyn_rec_timeout, prev->dyn_rec_timeout,
-+                             1000);
-+    /* Default sizes for the dynamic record sizes are defined to fit maximal
-+       TLS + IPv6 overhead in a single TCP segment for lo and 3 segments for hi:
-+       1369 = 1500 - 40 (IP) - 20 (TCP) - 10 (Time) - 61 (Max TLS overhead) */
-+    ngx_conf_merge_size_value(conf->dyn_rec_size_lo, prev->dyn_rec_size_lo,
-+                             1369);
-+    /* 4229 = (1500 - 40 - 20 - 10) * 3  - 61 */
-+    ngx_conf_merge_size_value(conf->dyn_rec_size_hi, prev->dyn_rec_size_hi,
-+                             4229);
-+    ngx_conf_merge_uint_value(conf->dyn_rec_threshold, prev->dyn_rec_threshold,
-+                             40);
-+
-     conf->ssl.log = cf->log;
- 
-     if (conf->certificates) {
-@@ -943,6 +997,28 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
-         return NGX_CONF_ERROR;
-     }
- 
-+    if (conf->dyn_rec_enable) {
-+        conf->ssl.dyn_rec.timeout = conf->dyn_rec_timeout;
-+        conf->ssl.dyn_rec.threshold = conf->dyn_rec_threshold;
-+
-+        if (conf->buffer_size > conf->dyn_rec_size_lo) {
-+            conf->ssl.dyn_rec.size_lo = conf->dyn_rec_size_lo;
-+
-+        } else {
-+            conf->ssl.dyn_rec.size_lo = conf->buffer_size;
-+        }
-+
-+        if (conf->buffer_size > conf->dyn_rec_size_hi) {
-+            conf->ssl.dyn_rec.size_hi = conf->dyn_rec_size_hi;
-+
-+        } else {
-+            conf->ssl.dyn_rec.size_hi = conf->buffer_size;
-+        }
-+
-+    } else {
-+        conf->ssl.dyn_rec.timeout = 0;
-+    }
-+
-     return NGX_CONF_OK;
- }
- 
-diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
-index 7ab0f7ea..4485a8b8 100644
---- a/src/http/modules/ngx_http_ssl_module.h
-+++ b/src/http/modules/ngx_http_ssl_module.h
-@@ -63,5 +63,11 @@ typedef struct {
-     ngx_str_t                       stapling_file;
-     ngx_str_t                       stapling_responder;
-+
-+    ngx_flag_t                      dyn_rec_enable;
-+    ngx_msec_t                      dyn_rec_timeout;
-+    size_t                          dyn_rec_size_lo;
-+    size_t                          dyn_rec_size_hi;
-+    ngx_uint_t                      dyn_rec_threshold;
- } ngx_http_ssl_srv_conf_t;
- 
- 
-diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
-index 58916a18..4297a0b6 100644
---- a/src/http/v2/ngx_http_v2.c
-+++ b/src/http/v2/ngx_http_v2.c
-@@ -245,6 +245,8 @@ ngx_http_v2_init(ngx_event_t *rev)
- 
-     h2c->frame_size = NGX_HTTP_V2_DEFAULT_FRAME_SIZE;
- 
-+    h2c->max_hpack_table_size = NGX_HTTP_V2_DEFAULT_HPACK_TABLE_SIZE;
-+
-     h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
- 
-     h2c->priority_limit = ngx_max(h2scf->concurrent_streams, 100);
-@@ -2254,6 +2256,13 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos,
- 
-         case NGX_HTTP_V2_HEADER_TABLE_SIZE_SETTING:
- 
-+            if (value > NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE) {
-+                h2c->max_hpack_table_size = NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE;
-+            } else {
-+                h2c->max_hpack_table_size = value;
-+            }
-+
-+            h2c->indicate_resize = 1;
-             h2c->table_update = 1;
-             break;
- 
-diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
-index 34922971..78bf9fc6 100644
---- a/src/http/v2/ngx_http_v2.h
-+++ b/src/http/v2/ngx_http_v2.h
-@@ -54,6 +54,13 @@
- 
- #define NGX_HTTP_V2_DEFAULT_WEIGHT       16
- 
-+#define HPACK_ENC_HTABLE_SZ              128 /* better to keep a PoT < 64k */
-+#define HPACK_ENC_HTABLE_ENTRIES         ((HPACK_ENC_HTABLE_SZ * 100) / 128)
-+#define HPACK_ENC_DYNAMIC_KEY_TBL_SZ     10  /* 10 is sufficient for most */
-+#define HPACK_ENC_MAX_ENTRY              512 /* longest header size to match */
-+
-+#define NGX_HTTP_V2_DEFAULT_HPACK_TABLE_SIZE     4096
-+#define NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE         16384 /* < 64k */
- 
- typedef struct ngx_http_v2_connection_s   ngx_http_v2_connection_t;
- typedef struct ngx_http_v2_node_s         ngx_http_v2_node_t;
-@@ -115,6 +122,46 @@ typedef struct {
- } ngx_http_v2_hpack_t;
- 
- 
-+#if (NGX_HTTP_V2_HPACK_ENC)
-+typedef struct {
-+    uint64_t                         hash_val;
-+    uint32_t                         index;
-+    uint16_t                         pos;
-+    uint16_t                         klen, vlen;
-+    uint16_t                         size;
-+    uint16_t                         next;
-+} ngx_http_v2_hpack_enc_entry_t;
-+
-+
-+typedef struct {
-+    uint64_t                         hash_val;
-+    uint32_t                         index;
-+    uint16_t                         pos;
-+    uint16_t                         klen;
-+} ngx_http_v2_hpack_name_entry_t;
-+
-+
-+typedef struct {
-+    size_t                           size;    /* size as defined in RFC 7541 */
-+    uint32_t                         top;     /* the last entry */
-+    uint32_t                         pos;
-+    uint16_t                         n_elems; /* number of elements */
-+    uint16_t                         base;    /* index of the oldest entry */
-+    uint16_t                         last;    /* index of the newest entry */
-+
-+    /* hash table for dynamic entries, instead using a generic hash table,
-+       which would be too slow to process a significant amount of headers,
-+       this table is not determenistic, and might ocasionally fail to insert
-+       a value, at the cost of slightly worse compression, but significantly
-+       faster performance */
-+    ngx_http_v2_hpack_enc_entry_t    htable[HPACK_ENC_HTABLE_SZ];
-+    ngx_http_v2_hpack_name_entry_t   heads[HPACK_ENC_DYNAMIC_KEY_TBL_SZ];
-+    u_char                           storage[NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE +
-+                                             HPACK_ENC_MAX_ENTRY];
-+} ngx_http_v2_hpack_enc_t;
-+#endif
-+
-+
- struct ngx_http_v2_connection_s {
-     ngx_connection_t                *connection;
-     ngx_http_connection_t           *http_connection;
-@@ -136,6 +183,8 @@ struct ngx_http_v2_connection_s {
- 
-     size_t                           frame_size;
- 
-+    size_t                           max_hpack_table_size;
-+
-     ngx_queue_t                      waiting;
- 
-     ngx_http_v2_state_t              state;
-@@ -165,6 +214,11 @@ struct ngx_http_v2_connection_s {
-     unsigned                         table_update:1;
-     unsigned                         blocked:1;
-     unsigned                         goaway:1;
-+    unsigned                         indicate_resize:1;
-+
-+#if (NGX_HTTP_V2_HPACK_ENC)
-+    ngx_http_v2_hpack_enc_t          hpack_enc;
-+#endif
- };
- 
- 
-@@ -413,4 +467,31 @@ u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
-     u_char *tmp, ngx_uint_t lower);
- 
- 
-+u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
-+    u_char *tmp, ngx_uint_t lower);
-+
-+u_char *
-+ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value);
-+
-+#define ngx_http_v2_write_name(dst, src, len, tmp)                            \\
-+    ngx_http_v2_string_encode(dst, src, len, tmp, 1)
-+#define ngx_http_v2_write_value(dst, src, len, tmp)                           \\
-+    ngx_http_v2_string_encode(dst, src, len, tmp, 0)
-+
-+u_char *
-+ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
-+    u_char *key, size_t key_len, u_char *value, size_t value_len,
-+    u_char *tmp);
-+
-+void
-+ngx_http_v2_table_resize(ngx_http_v2_connection_t *h2c);
-+
-+#define ngx_http_v2_write_header_str(key, value)                        \\
-+    ngx_http_v2_write_header(h2c, pos, (u_char *) key, sizeof(key) - 1, \\
-+    (u_char *) value, sizeof(value) - 1, tmp);
-+
-+#define ngx_http_v2_write_header_tbl(key, val)                          \\
-+    ngx_http_v2_write_header(h2c, pos, (u_char *) key, sizeof(key) - 1, \\
-+    val.data, val.len, tmp);
-+
- extern ngx_module_t  ngx_http_v2_module;
-diff --git a/src/http/v2/ngx_http_v2_encode.c b/src/http/v2/ngx_http_v2_encode.c
-index ac792084..d1fb7217 100644
---- a/src/http/v2/ngx_http_v2_encode.c
-+++ b/src/http/v2/ngx_http_v2_encode.c
-@@ -10,7 +10,7 @@
- #include <ngx_http.h>
- 
- 
--static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
-+u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
-     ngx_uint_t value);
- 
- 
-@@ -40,7 +40,7 @@ ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
- }
- 
- 
--static u_char *
-+u_char *
- ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value)
- {
-     if (value < prefix) {
-diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
-index a6e5e7d4..f4ebe53e 100644
---- a/src/http/v2/ngx_http_v2_filter_module.c
-+++ b/src/http/v2/ngx_http_v2_filter_module.c
-@@ -155,11 +155,9 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
- #endif
- 
-     static size_t nginx_ver_len = ngx_http_v2_literal_size(NGINX_VER);
--    static u_char nginx_ver[ngx_http_v2_literal_size(NGINX_VER)];
- 
-     static size_t nginx_ver_build_len =
-                                   ngx_http_v2_literal_size(NGINX_VER_BUILD);
--    static u_char nginx_ver_build[ngx_http_v2_literal_size(NGINX_VER_BUILD)];
- 
-     stream = r->stream;
- 
-@@ -435,7 +433,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
-     }
- 
-     tmp = ngx_palloc(r->pool, tmp_len);
--    pos = ngx_pnalloc(r->pool, len);
-+    pos = ngx_pnalloc(r->pool, len + 15 + 1);
- 
-     if (pos == NULL || tmp == NULL) {
-         return NGX_ERROR;
-@@ -450,6 +448,18 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
-         h2c->table_update = 0;
-     }
- 
-+    h2c = r->stream->connection;
-+
-+    if (h2c->indicate_resize) {
-+        *pos = 32;
-+        pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(5),
-+                                    h2c->max_hpack_table_size);
-+        h2c->indicate_resize = 0;
-+#if (NGX_HTTP_V2_HPACK_ENC)
-+        ngx_http_v2_table_resize(h2c);
-+#endif
-+    }
-+
-     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
-                    "http2 output header: \":status: %03ui\"",
-                    r->headers_out.status);
-@@ -458,67 +468,28 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
-         *pos++ = status;
- 
-     } else {
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_STATUS_INDEX);
--        *pos++ = NGX_HTTP_V2_ENCODE_RAW | 3;
--        pos = ngx_sprintf(pos, "%03ui", r->headers_out.status);
-+        ngx_sprintf(pos + 8, "%O3ui", r->headers_out.status);
-+        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)":status",
-+                                       sizeof(":status") - 1, pos + 8, 3, tmp);
-     }
- 
-     if (r->headers_out.server == NULL) {
--
-         if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
--            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                           "http2 output header: \"server: %s\"",
--                           NGINX_VER);
-+            pos = ngx_http_v2_write_header_str("server", NGINX_VER);
- 
-         } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
--            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                           "http2 output header: \"server: %s\"",
--                           NGINX_VER_BUILD);
-+            pos = ngx_http_v2_write_header_str("server", NGINX_VER_BUILD);
- 
-         } else {
--            ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                           "http2 output header: \"server: nginx\"");
--        }
--
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_SERVER_INDEX);
--
--        if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_ON) {
--            if (nginx_ver[0] == '\0') {
--                p = ngx_http_v2_write_value(nginx_ver, (u_char *) NGINX_VER,
--                                            sizeof(NGINX_VER) - 1, tmp);
--                nginx_ver_len = p - nginx_ver;
--            }
--
--            pos = ngx_cpymem(pos, nginx_ver, nginx_ver_len);
--
--        } else if (clcf->server_tokens == NGX_HTTP_SERVER_TOKENS_BUILD) {
--            if (nginx_ver_build[0] == '\0') {
--                p = ngx_http_v2_write_value(nginx_ver_build,
--                                            (u_char *) NGINX_VER_BUILD,
--                                            sizeof(NGINX_VER_BUILD) - 1, tmp);
--                nginx_ver_build_len = p - nginx_ver_build;
--            }
--
--            pos = ngx_cpymem(pos, nginx_ver_build, nginx_ver_build_len);
--
--        } else {
--            pos = ngx_cpymem(pos, nginx, sizeof(nginx));
-+            pos = ngx_http_v2_write_header_str("server", "nginx");
-         }
-     }
- 
-     if (r->headers_out.date == NULL) {
--        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"date: %V\"",
--                       &ngx_cached_http_time);
--
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_DATE_INDEX);
--        pos = ngx_http_v2_write_value(pos, ngx_cached_http_time.data,
--                                      ngx_cached_http_time.len, tmp);
-+        pos = ngx_http_v2_write_header_tbl("date", ngx_cached_http_time);
-     }
- 
-     if (r->headers_out.content_type.len) {
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_TYPE_INDEX);
--
-         if (r->headers_out.content_type_len == r->headers_out.content_type.len
-             && r->headers_out.charset.len)
-         {
-@@ -544,64 +515,36 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
-             r->headers_out.content_type.data = p - len;
-         }
- 
--        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"content-type: %V\"",
--                       &r->headers_out.content_type);
--
--        pos = ngx_http_v2_write_value(pos, r->headers_out.content_type.data,
--                                      r->headers_out.content_type.len, tmp);
-+        pos = ngx_http_v2_write_header_tbl("content-type",
-+                                           r->headers_out.content_type);
-     }
- 
-     if (r->headers_out.content_length == NULL
-         && r->headers_out.content_length_n >= 0)
-     {
--        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"content-length: %O\"",
--                       r->headers_out.content_length_n);
--
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_CONTENT_LENGTH_INDEX);
--
--        p = pos;
--        pos = ngx_sprintf(pos + 1, "%O", r->headers_out.content_length_n);
--        *p = NGX_HTTP_V2_ENCODE_RAW | (u_char) (pos - p - 1);
-+        p = ngx_sprintf(pos + 15, "%O", r->headers_out.content_length_n);
-+        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)"content-length",
-+                                       sizeof("content-length") - 1, pos + 15,
-+                                       p - (pos + 15), tmp);
-     }
- 
-     if (r->headers_out.last_modified == NULL
-         && r->headers_out.last_modified_time != -1)
-     {
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LAST_MODIFIED_INDEX);
--
--        ngx_http_time(pos, r->headers_out.last_modified_time);
-+        ngx_http_time(pos + 14, r->headers_out.last_modified_time);
-         len = sizeof("Wed, 31 Dec 1986 18:00:00 GMT") - 1;
--
--        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"last-modified: %*s\"",
--                       len, pos);
--
--        /*
--         * Date will always be encoded using huffman in the temporary buffer,
--         * so it's safe here to use src and dst pointing to the same address.
--         */
--        pos = ngx_http_v2_write_value(pos, pos, len, tmp);
-+        pos = ngx_http_v2_write_header(h2c, pos, (u_char *)"last-modified",
-+                                       sizeof("last-modified") - 1, pos + 14,
-+                                       len, tmp);
-     }
- 
-     if (r->headers_out.location && r->headers_out.location->value.len) {
--        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"location: %V\"",
--                       &r->headers_out.location->value);
--
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_LOCATION_INDEX);
--        pos = ngx_http_v2_write_value(pos, r->headers_out.location->value.data,
--                                      r->headers_out.location->value.len, tmp);
-+        pos = ngx_http_v2_write_header_tbl("location", r->headers_out.location->value);
-     }
- 
- #if (NGX_HTTP_GZIP)
-     if (r->gzip_vary) {
--        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                       "http2 output header: \"vary: Accept-Encoding\"");
--
--        *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_VARY_INDEX);
--        pos = ngx_cpymem(pos, accept_encoding, sizeof(accept_encoding));
-+        pos = ngx_http_v2_write_header_str("vary", "Accept-Encoding");
-     }
- #endif
- 
-@@ -624,23 +567,9 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
-             continue;
-         }
- 
--#if (NGX_DEBUG)
--        if (fc->log->log_level & NGX_LOG_DEBUG_HTTP) {
--            ngx_strlow(tmp, header[i].key.data, header[i].key.len);
--
--            ngx_log_debug3(NGX_LOG_DEBUG_HTTP, fc->log, 0,
--                           "http2 output header: \"%*s: %V\"",
--                           header[i].key.len, tmp, &header[i].value);
--        }
--#endif
--
--        *pos++ = 0;
--
--        pos = ngx_http_v2_write_name(pos, header[i].key.data,
--                                     header[i].key.len, tmp);
--
--        pos = ngx_http_v2_write_value(pos, header[i].value.data,
--                                      header[i].value.len, tmp);
-+        pos = ngx_http_v2_write_header(h2c, pos, header[i].key.data,
-+                                       header[i].key.len, header[i].value.data,
-+                                       header[i].value.len, tmp);
-     }
- 
-     fin = r->header_only
-@@ -1308,6 +1237,7 @@ ngx_http_v2_create_trailers_frame(ngx_http_request_t *r)
-     ngx_list_part_t   *part;
-     ngx_table_elt_t   *header;
-     ngx_connection_t  *fc;
-+    ngx_http_v2_connection_t  *h2c;
- 
-     fc = r->connection;
-     len = 0;
-@@ -1316,6 +1246,8 @@ ngx_http_v2_create_trailers_frame(ngx_http_request_t *r)
-     part = &r->headers_out.trailers.part;
-     header = part->elts;
- 
-+    h2c = r->stream->connection;
-+
-     for (i = 0; /* void */; i++) {
- 
-         if (i >= part->nelts) {
-@@ -1400,13 +1332,9 @@ ngx_http_v2_create_trailers_frame(ngx_http_request_t *r)
-         }
- #endif
- 
--        *pos++ = 0;
--
--        pos = ngx_http_v2_write_name(pos, header[i].key.data,
--                                     header[i].key.len, tmp);
--
--        pos = ngx_http_v2_write_value(pos, header[i].value.data,
--                                      header[i].value.len, tmp);
-+        pos = ngx_http_v2_write_header(h2c, pos, header[i].key.data,
-+                                       header[i].key.len, header[i].value.data,
-+                                       header[i].value.len, tmp);
-     }
- 
-     return ngx_http_v2_create_headers_frame(r, start, pos, 1);
-diff --git a/src/http/v2/ngx_http_v2_table.c b/src/http/v2/ngx_http_v2_table.c
-index 7d49803f..b9ee2048 100644
---- a/src/http/v2/ngx_http_v2_table.c
-+++ b/src/http/v2/ngx_http_v2_table.c
-@@ -361,3 +361,434 @@ ngx_http_v2_table_size(ngx_http_v2_connection_t *h2c, size_t size)
- 
-     return NGX_OK;
- }
-+
-+
-+#if (NGX_HTTP_V2_HPACK_ENC)
-+
-+static ngx_int_t
-+hpack_get_static_index(ngx_http_v2_connection_t *h2c, u_char *val, size_t len);
-+
-+static ngx_int_t
-+hpack_get_dynamic_index(ngx_http_v2_connection_t *h2c, uint64_t key_hash,
-+                        uint8_t *key, size_t key_len);
-+
-+
-+void
-+ngx_http_v2_table_resize(ngx_http_v2_connection_t *h2c)
-+{
-+    ngx_http_v2_hpack_enc_entry_t  *table;
-+    uint64_t                        idx;
-+
-+    table = h2c->hpack_enc.htable;
-+
-+    while (h2c->hpack_enc.size > h2c->max_hpack_table_size) {
-+        idx = h2c->hpack_enc.base;
-+        h2c->hpack_enc.base = table[idx].next;
-+        h2c->hpack_enc.size -= table[idx].size;
-+        table[idx].hash_val = 0;
-+        h2c->hpack_enc.n_elems--;
-+    }
-+}
-+
-+
-+/* checks if a header is in the hpack table - if so returns the table entry,
-+   otherwise encodes and inserts into the table and returns 0,
-+   if failed to insert into table, returns -1 */
-+static ngx_int_t
-+ngx_http_v2_table_encode_strings(ngx_http_v2_connection_t *h2c,
-+    size_t key_len, size_t val_len, uint8_t *key, uint8_t *val,
-+    ngx_int_t *header_idx)
-+{
-+    uint64_t  hash_val, key_hash, idx, lru;
-+    int       i;
-+    size_t    size = key_len + val_len + 32;
-+    uint8_t  *storage = h2c->hpack_enc.storage;
-+
-+    ngx_http_v2_hpack_enc_entry_t   *table;
-+    ngx_http_v2_hpack_name_entry_t  *name;
-+
-+    *header_idx = NGX_ERROR;
-+    /* step 1: compute the hash value of header */
-+    if (size > HPACK_ENC_MAX_ENTRY || size > h2c->max_hpack_table_size) {
-+        return NGX_ERROR;
-+    }
-+
-+    key_hash = ngx_murmur_hash2_64(key, key_len, 0x01234);
-+    hash_val = ngx_murmur_hash2_64(val, val_len, key_hash);
-+
-+    if (hash_val == 0) {
-+        return NGX_ERROR;
-+    }
-+
-+    /* step 2: check if full header in the table */
-+    idx = hash_val;
-+    i = -1;
-+    while (idx) {
-+         /* at most 8 locations are checked, but most will be done in 1 or 2 */
-+        table = &h2c->hpack_enc.htable[idx % HPACK_ENC_HTABLE_SZ];
-+        if (table->hash_val == hash_val
-+            && table->klen == key_len
-+            && table->vlen == val_len
-+            && ngx_memcmp(key, storage + table->pos, key_len) == 0
-+            && ngx_memcmp(val, storage + table->pos + key_len, val_len) == 0)
-+        {
-+            return (h2c->hpack_enc.top - table->index) + 61;
-+        }
-+
-+        if (table->hash_val == 0 && i == -1) {
-+            i = idx % HPACK_ENC_HTABLE_SZ;
-+            break;
-+        }
-+
-+        idx >>= 8;
-+    }
-+
-+    /* step 3: check if key is in one of the tables */
-+    *header_idx = hpack_get_static_index(h2c, key, key_len);
-+
-+    if (i == -1) {
-+        return NGX_ERROR;
-+    }
-+
-+    if (*header_idx == NGX_ERROR) {
-+        *header_idx = hpack_get_dynamic_index(h2c, key_hash, key, key_len);
-+    }
-+
-+    /* step 4: store the new entry */
-+    table =  h2c->hpack_enc.htable;
-+
-+    if (h2c->hpack_enc.top == 0xffffffff) {
-+        /* just to be on the safe side, avoid overflow */
-+        ngx_memset(&h2c->hpack_enc, 0, sizeof(ngx_http_v2_hpack_enc_t));
-+    }
-+
-+    while ((h2c->hpack_enc.size + size > h2c->max_hpack_table_size)
-+           || h2c->hpack_enc.n_elems == HPACK_ENC_HTABLE_ENTRIES) {
-+        /* make space for the new entry first */
-+        idx = h2c->hpack_enc.base;
-+        h2c->hpack_enc.base = table[idx].next;
-+        h2c->hpack_enc.size -= table[idx].size;
-+        table[idx].hash_val = 0;
-+        h2c->hpack_enc.n_elems--;
-+    }
-+
-+    table[i] = (ngx_http_v2_hpack_enc_entry_t){.hash_val = hash_val,
-+                                               .index = h2c->hpack_enc.top,
-+                                               .pos = h2c->hpack_enc.pos,
-+                                               .klen = key_len,
-+                                               .vlen = val_len,
-+                                               .size = size,
-+                                               .next = 0};
-+
-+    table[h2c->hpack_enc.last].next = i;
-+    if (h2c->hpack_enc.n_elems == 0) {
-+        h2c->hpack_enc.base = i;
-+    }
-+
-+    h2c->hpack_enc.last = i;
-+    h2c->hpack_enc.top++;
-+    h2c->hpack_enc.size += size;
-+    h2c->hpack_enc.n_elems++;
-+
-+    /* update header name lookup */
-+    if (*header_idx == NGX_ERROR ) {
-+        lru = h2c->hpack_enc.top;
-+
-+        for (i=0; i<HPACK_ENC_DYNAMIC_KEY_TBL_SZ; i++) {
-+
-+            name = &h2c->hpack_enc.heads[i];
-+
-+            if ( name->hash_val == 0 || (name->hash_val == key_hash
-+                && ngx_memcmp(storage + name->pos, key, key_len) == 0) )
-+            {
-+                name->hash_val = key_hash;
-+                name->pos = h2c->hpack_enc.pos;
-+                name->index = h2c->hpack_enc.top - 1;
-+                break;
-+            }
-+
-+            if (lru > name->index) {
-+                lru = name->index;
-+                idx = i;
-+            }
-+        }
-+
-+        if (i == HPACK_ENC_DYNAMIC_KEY_TBL_SZ) {
-+            name = &h2c->hpack_enc.heads[idx];
-+            name->hash_val = hash_val;
-+            name->pos = h2c->hpack_enc.pos;
-+            name->index = h2c->hpack_enc.top - 1;
-+        }
-+    }
-+
-+    ngx_memcpy(storage + h2c->hpack_enc.pos, key, key_len);
-+    ngx_memcpy(storage + h2c->hpack_enc.pos + key_len, val, val_len);
-+
-+    h2c->hpack_enc.pos += size;
-+    if (h2c->hpack_enc.pos > NGX_HTTP_V2_MAX_HPACK_TABLE_SIZE) {
-+        h2c->hpack_enc.pos = 0;
-+    }
-+
-+    return NGX_OK;
-+}
-+
-+
-+u_char *
-+ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
-+                         u_char *key, size_t key_len,
-+                         u_char *value, size_t value_len,
-+                         u_char *tmp)
-+{
-+    ngx_int_t idx, header_idx;
-+
-+    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                   "http2 output header: %*s: %*s", key_len, key, value_len,
-+                   value);
-+
-+    /* attempt to find the value in the dynamic table */
-+    idx = ngx_http_v2_table_encode_strings(h2c, key_len, value_len, key, value,
-+                                           &header_idx);
-+
-+    if (idx > 0) {
-+        /* positive index indicates success */
-+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                       "http2 hpack encode: Indexed Header Field: %ud", idx);
-+
-+        *pos = 128;
-+        pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(7), idx);
-+
-+    } else {
-+
-+        if (header_idx == NGX_ERROR) { /* if key is not present */
-+
-+            if (idx == NGX_ERROR) {    /* if header was not added */
-+                *pos++ = 0;
-+
-+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                              "http2 hpack encode: Literal Header Field without"
-+                              " Indexing — New Name");
-+            } else {                   /* if header was added */
-+                *pos++ = 64;
-+
-+                ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                              "http2 hpack encode: Literal Header Field with "
-+                              "Incremental Indexing — New Name");
-+            }
-+
-+            pos = ngx_http_v2_write_name(pos, key, key_len, tmp);
-+
-+        } else {                       /* if key is present */
-+
-+            if (idx == NGX_ERROR) {
-+                *pos = 0;
-+                pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(4), header_idx);
-+
-+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                              "http2 hpack encode: Literal Header Field without"
-+                              " Indexing — Indexed Name: %ud", header_idx);
-+            } else {
-+                *pos = 64;
-+                pos = ngx_http_v2_write_int(pos, ngx_http_v2_prefix(6), header_idx);
-+
-+                ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                              "http2 hpack encode: Literal Header Field with "
-+                              "Incremental Indexing — Indexed Name: %ud", header_idx);
-+            }
-+        }
-+
-+        pos = ngx_http_v2_write_value(pos, value, value_len, tmp);
-+    }
-+
-+    return pos;
-+}
-+
-+
-+static ngx_int_t
-+hpack_get_dynamic_index(ngx_http_v2_connection_t *h2c, uint64_t key_hash,
-+                        uint8_t *key, size_t key_len)
-+{
-+    ngx_http_v2_hpack_name_entry_t  *name;
-+    int                              i;
-+
-+    for (i=0; i<HPACK_ENC_DYNAMIC_KEY_TBL_SZ; i++) {
-+        name = &h2c->hpack_enc.heads[i];
-+
-+        if (name->hash_val == key_hash
-+            && ngx_memcmp(h2c->hpack_enc.storage + name->pos, key, key_len) == 0)
-+        {
-+            if (name->index >= h2c->hpack_enc.top - h2c->hpack_enc.n_elems) {
-+                return (h2c->hpack_enc.top - name->index) + 61;
-+            }
-+            break;
-+        }
-+    }
-+
-+    return NGX_ERROR;
-+}
-+
-+
-+/* decide if a given header is present in the static dictionary, this could be
-+   done in several ways, but it seems the fastest one is "exhaustive" search */
-+static ngx_int_t
-+hpack_get_static_index(ngx_http_v2_connection_t *h2c, u_char *val, size_t len)
-+{
-+    /* the static dictionary of response only headers,
-+       although response headers can be put by origin,
-+       that would be rare */
-+    static const struct {
-+        u_char         len;
-+        const u_char   val[28];
-+        u_char         idx;
-+    } server_headers[] = {
-+        { 3, "age",                         21},//0
-+        { 3, "via",                         60},
-+        { 4, "date",                        33},//2
-+        { 4, "etag",                        34},
-+        { 4, "link",                        45},
-+        { 4, "vary",                        59},
-+        { 5, "allow",                       22},//6
-+        { 6, "server",                      54},//7
-+        { 7, "expires",                     36},//8
-+        { 7, "refresh",                     52},
-+        { 8, "location",                    46},//10
-+        {10, "set-cookie",                  55},//11
-+        {11, "retry-after",                 53},//12
-+        {12, "content-type",                31},//13
-+        {13, "content-range",               30},//14
-+        {13, "accept-ranges",               18},
-+        {13, "cache-control",               24},
-+        {13, "last-modified",               44},
-+        {14, "content-length",              28},//18
-+        {16, "content-encoding",            26},//19
-+        {16, "content-language",            27},
-+        {16, "content-location",            29},
-+        {16, "www-authenticate",            61},
-+        {17, "transfer-encoding",           57},//23
-+        {18, "proxy-authenticate",          48},//24
-+        {19, "content-disposition",         25},//25
-+        {25, "strict-transport-security",   56},//26
-+        {27, "access-control-allow-origin", 20},//27
-+        {99, "",                            99},
-+    }, *header;
-+
-+    /* for a given length, where to start the search
-+       since minimal length is 3, the table has a -3
-+       offset */
-+    static const int8_t start_at[] = {
-+        [3-3]  = 0,
-+        [4-3]  = 2,
-+        [5-3]  = 6,
-+        [6-3]  = 7,
-+        [7-3]  = 8,
-+        [8-3]  = 10,
-+        [9-3]  = -1,
-+        [10-3] = 11,
-+        [11-3] = 12,
-+        [12-3] = 13,
-+        [13-3] = 14,
-+        [14-3] = 18,
-+        [15-3] = -1,
-+        [16-3] = 19,
-+        [17-3] = 23,
-+        [18-3] = 24,
-+        [19-3] = 25,
-+        [20-3] = -1,
-+        [21-3] = -1,
-+        [22-3] = -1,
-+        [23-3] = -1,
-+        [24-3] = -1,
-+        [25-3] = 26,
-+        [26-3] = -1,
-+        [27-3] = 27,
-+    };
-+
-+    uint64_t pref;
-+    size_t   save_len = len, i;
-+    int8_t   start;
-+
-+    /* early exit for out of bounds lengths */
-+    if (len < 3 || len > 27) {
-+        return NGX_ERROR;
-+    }
-+
-+    start = start_at[len - 3];
-+    if (start == -1) {
-+        /* exit for non existent lengths */
-+        return NGX_ERROR;
-+    }
-+
-+    header = &server_headers[start_at[len - 3]];
-+
-+    /* load first 8 bytes of key, for fast comparison */
-+    if (len < 8) {
-+        pref = 0;
-+        if (len >= 4) {
-+            pref = *(uint32_t *)(val + len - 4) | 0x20202020;
-+            len -= 4;
-+        }
-+        while (len > 0) { /* 3 iterations at most */
-+            pref = (pref << 8) ^ (val[len - 1] | 0x20);
-+            len--;
-+        }
-+    } else {
-+        pref = *(uint64_t *)val | 0x2020202020202020;
-+        len -= 8;
-+    }
-+
-+    /* iterate over headers with the right length */
-+    while (header->len == save_len) {
-+        /* quickly compare the first 8 bytes, most tests will end here */
-+        if (pref != *(uint64_t *) header->val) {
-+            header++;
-+            continue;
-+        }
-+
-+        if (len == 0) {
-+            /* len == 0, indicates prefix held the entire key */
-+            return header->idx;
-+        }
-+        /* for longer keys compare the rest */
-+        i = 1 + (save_len + 7) % 8; /* align so we can compare in quadwords */
-+
-+        while (i + 8 <= save_len) { /* 3 iterations at most */
-+            if ( *(uint64_t *)&header->val[i]
-+                 != (*(uint64_t *) &val[i]| 0x2020202020202020) )
-+            {
-+                header++;
-+                i = 0;
-+                break;
-+            }
-+            i += 8;
-+        }
-+
-+        if (i == 0) {
-+            continue;
-+        }
-+
-+        /* found the corresponding entry in the static dictionary */
-+        return header->idx;
-+    }
-+
-+    return NGX_ERROR;
-+}
-+
-+#else
-+
-+u_char *
-+ngx_http_v2_write_header(ngx_http_v2_connection_t *h2c, u_char *pos,
-+                         u_char *key, size_t key_len,
-+                         u_char *value, size_t value_len,
-+                         u_char *tmp)
-+{
-+    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
-+                   "http2 output header: %*s: %*s", key_len, key, value_len,
-+                   value);
-+
-+    *pos++ = 64;
-+    pos = ngx_http_v2_write_name(pos, key, key_len, tmp);
-+    pos = ngx_http_v2_write_value(pos, value, value_len, tmp);
-+
-+    return pos;
-+}
-+
-+#endif
-EOF
-
-./auto/configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --http-client-body-temp-path=/tmp/body --http-fastcgi-temp-path=/tmp/fastcgi --http-proxy-temp-path=/tmp/proxy --with-threads --with-file-aio --with-pcre-jit --with-http_ssl_module --with-http_v2_module --with-http_v2_hpack_enc --with-http_v3_module --with-http_gzip_static_module --without-http_ssi_module --without-http_userid_module --without-http_mirror_module --without-http_geo_module --without-http_split_clients_module --without-http_uwsgi_module --without-http_scgi_module --without-http_grpc_module --without-http_memcached_module --without-http_empty_gif_module --without-http_browser_module --without-http_upstream_hash_module --without-http_upstream_ip_hash_module --without-http_upstream_least_conn_module --without-http_upstream_keepalive_module --without-http_upstream_zone_module --with-stream --with-stream_ssl_module --without-stream_geo_module --without-stream_map_module --without-stream_split_clients_module --without-stream_return_module --without-stream_upstream_hash_module --without-stream_upstream_least_conn_module --without-stream_upstream_zone_module --with-cc-opt='-O3 -march=native -mtune=native -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --add-module=ngx_brotli --without-pcre2
-make -j $PROC_LIMIT install
-make clean
-git reset --hard
 cd ..
 ln -fs /usr/include/qdbm/depot.h /usr/include/depot.h
 cd php-src