[{"data":1,"prerenderedAt":1873},["ShallowReactive",2],{"blog-post:nginx-brotli-gzip-compression-docker":3},{"id":4,"title":5,"body":6,"date":1862,"description":1863,"draft":1864,"extension":1865,"lastModified":1866,"meta":1867,"navigation":122,"path":1868,"readingTime":1869,"seo":1870,"stem":1871,"__hash__":1872},"posts\u002Fblog\u002Fnginx-brotli-gzip-compression-docker.md","Add Brotli and Gzip compression to nginx in Docker",{"type":7,"value":8,"toc":1854},"minimark",[9,25,40,45,62,93,100,187,192,262,294,298,304,326,335,606,614,719,749,752,776,803,809,829,833,849,908,911,933,955,959,968,1002,1103,1106,1122,1138,1143,1542,1546,1810,1818,1821,1850],[10,11,12,19,20,24],"p",{},[13,14,18],"a",{"href":15,"rel":16},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fbrotli",[17],"nofollow","Brotli"," provides improved compression ratio\nand performance compared to gzip and can greatly improve webpage loading\nperformance since we are sending lot smaller bytes down the wire. Web browser\nsupport for brotli is pretty good too, almost all latest browsers support brotli\nfile format decompression. We can verify it by looking at ",[21,22,23],"code",{},"Accept-Encoding: br","\nrequest header.",[10,26,27,28,33,34,39],{},"nginx comes with\n",[13,29,32],{"href":30,"rel":31},"https:\u002F\u002Fnginx.org\u002Fen\u002Fdocs\u002Fhttp\u002Fngx_http_gzip_module.html",[17],"gzip"," module support\nby default (we need to turn it on \u002F opt in) but to setup brotli support we need\nto reconfigure nginx modules. I'll be using ",[13,35,38],{"href":36,"rel":37},"https:\u002F\u002Fwww.docker.com\u002F",[17],"Docker"," to\nsetup nginx with brotli compression but overall steps should be somewhat similar\nif you're setting it up manually in a server.",[41,42,44],"h2",{"id":43},"dockerfile","Dockerfile",[10,46,47,48,51,52,57,58,61],{},"Let's create a simple ",[21,49,50],{},"DockerFile"," and use the latest stable\n",[13,53,56],{"href":54,"rel":55},"https:\u002F\u002Fhub.docker.com\u002F_\u002Fnginx\u002F",[17],"nginx docker image"," and set the working\ndirectory to ",[21,59,60],{},"\u002Froot\u002F"," (this can be whatever you want)",[63,64,69],"pre",{"className":65,"code":66,"language":67,"meta":68,"style":68},"language-docker shiki shiki-themes github-dark","FROM nginx:1.23.2-alpine\nWORKDIR \u002Froot\u002F\n","docker","",[21,70,71,84],{"__ignoreMap":68},[72,73,76,80],"span",{"class":74,"line":75},"line",1,[72,77,79],{"class":78},"snl16","FROM",[72,81,83],{"class":82},"s95oV"," nginx:1.23.2-alpine\n",[72,85,87,90],{"class":74,"line":86},2,[72,88,89],{"class":78},"WORKDIR",[72,91,92],{"class":82}," \u002Froot\u002F\n",[10,94,95,96,99],{},"Add a ",[21,97,98],{},"RUN"," command:",[63,101,103],{"className":65,"code":102,"language":67,"meta":68,"style":68},"FROM nginx:1.23.2-alpine\nWORKDIR \u002Froot\u002F\n\nRUN apk add --update --no-cache git pcre-dev openssl-dev zlib-dev linux-headers build-base \\\n    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-1.23.2.tar.gz \\\n    && tar zxf nginx-1.23.2.tar.gz \\\n    && git clone https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli.git \\\n    && cd ngx_brotli \\\n    && git submodule update --init --recursive \\\n    && cd ..\u002Fnginx-1.23.2 \\\n    && .\u002Fconfigure --add-dynamic-module=..\u002Fngx_brotli --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer -g' --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n    && make modules\n",[21,104,105,111,117,124,132,138,144,150,156,162,168,181],{"__ignoreMap":68},[72,106,107,109],{"class":74,"line":75},[72,108,79],{"class":78},[72,110,83],{"class":82},[72,112,113,115],{"class":74,"line":86},[72,114,89],{"class":78},[72,116,92],{"class":82},[72,118,120],{"class":74,"line":119},3,[72,121,123],{"emptyLinePlaceholder":122},true,"\n",[72,125,127,129],{"class":74,"line":126},4,[72,128,98],{"class":78},[72,130,131],{"class":82}," apk add --update --no-cache git pcre-dev openssl-dev zlib-dev linux-headers build-base \\\n",[72,133,135],{"class":74,"line":134},5,[72,136,137],{"class":82},"    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-1.23.2.tar.gz \\\n",[72,139,141],{"class":74,"line":140},6,[72,142,143],{"class":82},"    && tar zxf nginx-1.23.2.tar.gz \\\n",[72,145,147],{"class":74,"line":146},7,[72,148,149],{"class":82},"    && git clone https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli.git \\\n",[72,151,153],{"class":74,"line":152},8,[72,154,155],{"class":82},"    && cd ngx_brotli \\\n",[72,157,159],{"class":74,"line":158},9,[72,160,161],{"class":82},"    && git submodule update --init --recursive \\\n",[72,163,165],{"class":74,"line":164},10,[72,166,167],{"class":82},"    && cd ..\u002Fnginx-1.23.2 \\\n",[72,169,171,174,178],{"class":74,"line":170},11,[72,172,173],{"class":82},"    && .\u002Fconfigure --add-dynamic-module=..\u002Fngx_brotli --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt=",[72,175,177],{"class":176},"sU2Wk","'-Os -fomit-frame-pointer -g'",[72,179,180],{"class":82}," --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n",[72,182,184],{"class":74,"line":183},12,[72,185,186],{"class":82},"    && make modules\n",[188,189,191],"h3",{"id":190},"run-command-does-these-things","RUN command does these things:",[193,194,195,199,202,211,243],"ol",{},[196,197,198],"li",{},"Update the packages, install git and other dependencies",[196,200,201],{},"Download the nginx package (same version as our docker image) and unzip it in\nthe current working directory",[196,203,204,205,210],{},"Clone the ",[13,206,209],{"href":207,"rel":208},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli",[17],"ngx_brotli"," repository from\ngithub and run update submodule to fetch all data from the project",[196,212,213,214,217,218],{},"cd back into nginx package that we downloaded and run ",[21,215,216],{},"configure"," script\nwith:\n",[219,220,221,236],"ul",{},[196,222,223,224,227,228],{},"Default Arguments (",[21,225,226],{},"nginx -V"," to get the default compile arguments)\n",[229,230],"img",{"alt":231,"dataZoomable":68,"height":232,"loading":233,"src":234,"width":235},"nginx configure default arguments",582,"lazy","\u002Fcontent\u002Fnginx_default_arguments.png",1933,[196,237,238,239,242],{},"Add Dynamic Module argument pointing to our downloaded ngx_brotli\nrepository (",[21,240,241],{},"..\u002Fngx_brotli",")",[196,244,245,250,251,254,255,258,259],{},[13,246,249],{"href":247,"rel":248},"https:\u002F\u002Fwww.nginx.com\u002Fresources\u002Fwiki\u002Fextending\u002Fcompiling\u002F",[17],"Compile the dynamic modules","\nusing ",[21,252,253],{},"make modules"," which can be loaded using ",[21,256,257],{},"load_module"," in our\n",[21,260,261],{},"nginx.conf",[10,263,264,265,268,269,271,272,274,275,278,279,278,282,285,286,289,290,293],{},"Note that we are combining\u002Fchaining multiple commands here using ",[21,266,267],{},"&&"," into a\nsingle ",[21,270,98],{}," command because docker executes each instruction in a new\nstandalone container\u002Flayer (except ",[21,273,79],{},"). We want our ",[21,276,277],{},"cd",", ",[21,280,281],{},"wget",[21,283,284],{},"make",",\n",[21,287,288],{},".\u002Fconfigure"," etc commands to run in the same context under same directory\n(",[21,291,292],{},"PWD","), there is a workaround for this and it would require us to manually add\nabsolute paths to our commands but I find this to be much easier and it also\nreduces number of layers and size of our resulting docker image.",[41,295,297],{"id":296},"load-brotli-module-and-enable-it","Load Brotli Module and Enable it",[10,299,300,301,303],{},"Now in our ",[21,302,261],{}," file we load the brotli module.",[63,305,309],{"className":306,"code":307,"language":308,"meta":68,"style":68},"language-nginx shiki shiki-themes github-dark","load_module \u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_filter_module.so;\nload_module \u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_static_module.so;\n","nginx",[21,310,311,319],{"__ignoreMap":68},[72,312,313,316],{"class":74,"line":75},[72,314,315],{"class":78},"load_module ",[72,317,318],{"class":82},"\u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_filter_module.so;\n",[72,320,321,323],{"class":74,"line":86},[72,322,315],{"class":78},[72,324,325],{"class":82},"\u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_static_module.so;\n",[10,327,328,329,334],{},"We can enable the brotli module and\n",[13,330,333],{"href":331,"rel":332},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli#configuration-directives",[17],"configure it",":",[63,336,338],{"className":306,"code":337,"language":308,"meta":68,"style":68},"load_module \u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_filter_module.so;\nload_module \u002Froot\u002Fnginx-1.23.2\u002Fobjs\u002Fngx_http_brotli_static_module.so;\n\nuser nginx;\n\nworker_processes 1;\n\nevents {\n  worker_connections 1024;\n}\n\nhttp {\n  include \u002Fetc\u002Fnginx\u002Fmime.types;\n  default_type application\u002Foctet-stream;\n\n  root \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml;\n\n  server {\n    listen 80;\n\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n\n    # Add Brotli compression config\n    brotli on;\n    brotli_comp_level 6;\n    brotli_static on;\n    brotli_types application\u002Fatom+xml application\u002Fjavascript application\u002Fjson application\u002Frss+xml\n             application\u002Fvnd.ms-fontobject application\u002Fx-font-opentype application\u002Fx-font-truetype\n             application\u002Fx-font-ttf application\u002Fx-javascript application\u002Fxhtml+xml application\u002Fxml\n             font\u002Feot font\u002Fopentype font\u002Fotf font\u002Ftruetype image\u002Fsvg+xml image\u002Fvnd.microsoft.icon\n             image\u002Fx-icon image\u002Fx-win-bitmap text\u002Fcss text\u002Fjavascript text\u002Fplain text\u002Fxml text\u002Fhtml;\n  }\n\n}\n",[21,339,340,346,352,356,364,368,380,384,392,402,407,411,418,427,436,441,450,455,463,474,479,490,500,510,515,522,533,544,554,563,572,578,584,590,596,601],{"__ignoreMap":68},[72,341,342,344],{"class":74,"line":75},[72,343,315],{"class":78},[72,345,318],{"class":82},[72,347,348,350],{"class":74,"line":86},[72,349,315],{"class":78},[72,351,325],{"class":82},[72,353,354],{"class":74,"line":119},[72,355,123],{"emptyLinePlaceholder":122},[72,357,358,361],{"class":74,"line":126},[72,359,360],{"class":78},"user ",[72,362,363],{"class":82},"nginx;\n",[72,365,366],{"class":74,"line":134},[72,367,123],{"emptyLinePlaceholder":122},[72,369,370,373,377],{"class":74,"line":140},[72,371,372],{"class":78},"worker_processes ",[72,374,376],{"class":375},"sDLfK","1",[72,378,379],{"class":82},";\n",[72,381,382],{"class":74,"line":146},[72,383,123],{"emptyLinePlaceholder":122},[72,385,386,389],{"class":74,"line":152},[72,387,388],{"class":78},"events",[72,390,391],{"class":82}," {\n",[72,393,394,397,400],{"class":74,"line":158},[72,395,396],{"class":78},"  worker_connections ",[72,398,399],{"class":375},"1024",[72,401,379],{"class":82},[72,403,404],{"class":74,"line":164},[72,405,406],{"class":82},"}\n",[72,408,409],{"class":74,"line":170},[72,410,123],{"emptyLinePlaceholder":122},[72,412,413,416],{"class":74,"line":183},[72,414,415],{"class":78},"http",[72,417,391],{"class":82},[72,419,421,424],{"class":74,"line":420},13,[72,422,423],{"class":78},"  include ",[72,425,426],{"class":82},"\u002Fetc\u002Fnginx\u002Fmime.types;\n",[72,428,430,433],{"class":74,"line":429},14,[72,431,432],{"class":78},"  default_type ",[72,434,435],{"class":82},"application\u002Foctet-stream;\n",[72,437,439],{"class":74,"line":438},15,[72,440,123],{"emptyLinePlaceholder":122},[72,442,444,447],{"class":74,"line":443},16,[72,445,446],{"class":78},"  root ",[72,448,449],{"class":82},"\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml;\n",[72,451,453],{"class":74,"line":452},17,[72,454,123],{"emptyLinePlaceholder":122},[72,456,458,461],{"class":74,"line":457},18,[72,459,460],{"class":78},"  server",[72,462,391],{"class":82},[72,464,466,469,472],{"class":74,"line":465},19,[72,467,468],{"class":78},"    listen ",[72,470,471],{"class":375},"80",[72,473,379],{"class":82},[72,475,477],{"class":74,"line":476},20,[72,478,123],{"emptyLinePlaceholder":122},[72,480,482,485,488],{"class":74,"line":481},21,[72,483,484],{"class":78},"    sendfile ",[72,486,487],{"class":375},"on",[72,489,379],{"class":82},[72,491,493,496,498],{"class":74,"line":492},22,[72,494,495],{"class":78},"    tcp_nopush ",[72,497,487],{"class":375},[72,499,379],{"class":82},[72,501,503,506,508],{"class":74,"line":502},23,[72,504,505],{"class":78},"    tcp_nodelay ",[72,507,487],{"class":375},[72,509,379],{"class":82},[72,511,513],{"class":74,"line":512},24,[72,514,123],{"emptyLinePlaceholder":122},[72,516,518],{"class":74,"line":517},25,[72,519,521],{"class":520},"sAwPA","    # Add Brotli compression config\n",[72,523,525,528,531],{"class":74,"line":524},26,[72,526,527],{"class":78},"    brotli",[72,529,530],{"class":375}," on",[72,532,379],{"class":82},[72,534,536,539,542],{"class":74,"line":535},27,[72,537,538],{"class":78},"    brotli_comp_level",[72,540,541],{"class":375}," 6",[72,543,379],{"class":82},[72,545,547,550,552],{"class":74,"line":546},28,[72,548,549],{"class":78},"    brotli_static",[72,551,530],{"class":375},[72,553,379],{"class":82},[72,555,557,560],{"class":74,"line":556},29,[72,558,559],{"class":78},"    brotli_types",[72,561,562],{"class":82}," application\u002Fatom+xml application\u002Fjavascript application\u002Fjson application\u002Frss+xml\n",[72,564,566,569],{"class":74,"line":565},30,[72,567,568],{"class":375},"             application\u002Fvnd.ms-fontobject",[72,570,571],{"class":82}," application\u002Fx-font-opentype application\u002Fx-font-truetype\n",[72,573,575],{"class":74,"line":574},31,[72,576,577],{"class":82},"             application\u002Fx-font-ttf application\u002Fx-javascript application\u002Fxhtml+xml application\u002Fxml\n",[72,579,581],{"class":74,"line":580},32,[72,582,583],{"class":82},"             font\u002Feot font\u002Fopentype font\u002Fotf font\u002Ftruetype image\u002Fsvg+xml image\u002Fvnd.microsoft.icon\n",[72,585,587],{"class":74,"line":586},33,[72,588,589],{"class":82},"             image\u002Fx-icon image\u002Fx-win-bitmap text\u002Fcss text\u002Fjavascript text\u002Fplain text\u002Fxml text\u002Fhtml;\n",[72,591,593],{"class":74,"line":592},34,[72,594,595],{"class":82},"  }\n",[72,597,599],{"class":74,"line":598},35,[72,600,123],{"emptyLinePlaceholder":122},[72,602,604],{"class":74,"line":603},36,[72,605,406],{"class":82},[10,607,608,610,611],{},[21,609,44],{}," till now that sets up brotli compression and serves static files\nfrom ",[21,612,613],{},"\u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002F",[63,615,617],{"className":65,"code":616,"language":67,"meta":68,"style":68},"FROM nginx:1.23.2-alpine AS builder\nWORKDIR \u002Froot\u002F\n\nRUN apk add --update --no-cache git pcre-dev openssl-dev zlib-dev linux-headers build-base \\\n    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-1.23.2.tar.gz \\\n    && tar zxf nginx-1.23.2.tar.gz \\\n    && git clone https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli.git \\\n    && cd ngx_brotli \\\n    && git submodule update --init --recursive \\\n    && cd ..\u002Fnginx-1.23.2 \\\n    && .\u002Fconfigure --add-dynamic-module=..\u002Fngx_brotli --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer -g' --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n    && make modules\n\n# Updated nginx.conf file with load_module for brotli\nCOPY nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\n\nWORKDIR \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002F\nCOPY www .\n",[21,618,619,632,638,642,648,652,656,660,664,668,672,680,684,688,693,701,705,712],{"__ignoreMap":68},[72,620,621,623,626,629],{"class":74,"line":75},[72,622,79],{"class":78},[72,624,625],{"class":82}," nginx:1.23.2-alpine ",[72,627,628],{"class":78},"AS",[72,630,631],{"class":82}," builder\n",[72,633,634,636],{"class":74,"line":86},[72,635,89],{"class":78},[72,637,92],{"class":82},[72,639,640],{"class":74,"line":119},[72,641,123],{"emptyLinePlaceholder":122},[72,643,644,646],{"class":74,"line":126},[72,645,98],{"class":78},[72,647,131],{"class":82},[72,649,650],{"class":74,"line":134},[72,651,137],{"class":82},[72,653,654],{"class":74,"line":140},[72,655,143],{"class":82},[72,657,658],{"class":74,"line":146},[72,659,149],{"class":82},[72,661,662],{"class":74,"line":152},[72,663,155],{"class":82},[72,665,666],{"class":74,"line":158},[72,667,161],{"class":82},[72,669,670],{"class":74,"line":164},[72,671,167],{"class":82},[72,673,674,676,678],{"class":74,"line":170},[72,675,173],{"class":82},[72,677,177],{"class":176},[72,679,180],{"class":82},[72,681,682],{"class":74,"line":183},[72,683,186],{"class":82},[72,685,686],{"class":74,"line":420},[72,687,123],{"emptyLinePlaceholder":122},[72,689,690],{"class":74,"line":429},[72,691,692],{"class":520},"# Updated nginx.conf file with load_module for brotli\n",[72,694,695,698],{"class":74,"line":438},[72,696,697],{"class":78},"COPY",[72,699,700],{"class":82}," nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\n",[72,702,703],{"class":74,"line":443},[72,704,123],{"emptyLinePlaceholder":122},[72,706,707,709],{"class":74,"line":452},[72,708,89],{"class":78},[72,710,711],{"class":82}," \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002F\n",[72,713,714,716],{"class":74,"line":457},[72,715,697],{"class":78},[72,717,718],{"class":82}," www .\n",[10,720,721,722,725,726,729,730,733,734,737,738,740,741,744,745,748],{},"I have made a ",[21,723,724],{},"www"," directory and added ",[21,727,728],{},"index.html"," and a ",[21,731,732],{},"styles.css"," file to\ntest brotli compression. If you see the ",[21,735,736],{},"brotli_types"," in the ",[21,739,261],{}," file,\nwe have ",[21,742,743],{},"text\u002Fcss"," and ",[21,746,747],{},"text\u002Fhtml"," added as the potential file types that we\nwould like to be compressed.",[10,750,751],{},"Let's test it out by building and starting the container.",[63,753,757],{"className":754,"code":755,"language":756,"meta":68,"style":68},"language-sh shiki shiki-themes github-dark","docker build -t nginx-gzip-brotli .\n","sh",[21,758,759],{"__ignoreMap":68},[72,760,761,764,767,770,773],{"class":74,"line":75},[72,762,67],{"class":763},"svObZ",[72,765,766],{"class":176}," build",[72,768,769],{"class":375}," -t",[72,771,772],{"class":176}," nginx-gzip-brotli",[72,774,775],{"class":176}," .\n",[63,777,779],{"className":754,"code":778,"language":756,"meta":68,"style":68},"docker run --rm -itd -p 3000:80 nginx-gzip-brotli\n",[21,780,781],{"__ignoreMap":68},[72,782,783,785,788,791,794,797,800],{"class":74,"line":75},[72,784,67],{"class":763},[72,786,787],{"class":176}," run",[72,789,790],{"class":375}," --rm",[72,792,793],{"class":375}," -itd",[72,795,796],{"class":375}," -p",[72,798,799],{"class":176}," 3000:80",[72,801,802],{"class":176}," nginx-gzip-brotli\n",[10,804,805,806,808],{},"Make sure the browser supports brotli compression, i.e sends\n",[21,807,23],{}," header",[10,810,811,817,818,824],{},[229,812],{"alt":813,"dataZoomable":68,"height":814,"loading":233,"src":815,"width":816},"Browser Supports Brotli using Accept-Encoding Header",409,"\u002Fcontent\u002Fbrowser_support.png",1148,"\nNeat! We get the response in brotli format:\n",[229,819],{"alt":820,"dataZoomable":68,"height":821,"loading":233,"src":822,"width":823},"Brotli Compression headers in browser",1172,"\u002Fcontent\u002Fbrotli_compression.png",2696,[229,825],{"alt":820,"dataZoomable":68,"height":826,"loading":233,"src":827,"width":828},642,"\u002Fcontent\u002Fbrotli_compression_zoomed.png",1233,[41,830,832],{"id":831},"add-fallback-gzip-compression","Add fallback Gzip compression",[10,834,835,836,839,840,842,843,848],{},"Now let's also add gzip compression to nginx so browsers that don't yet support\nbrotli format can use gzip. Since its support is built into nginx (I mean nginx\ncompiled with ",[21,837,838],{},"--with-http_gunzip_module --with-http_gzip_static_module"," flags,\nwhich is usually the case) we just have to update our ",[21,841,261],{}," file based on\n",[13,844,847],{"href":845,"rel":846},"https:\u002F\u002Fnginx.org\u002Fen\u002Fdocs\u002Fhttp\u002Fngx_http_gzip_module.html#example",[17],"nginx_gzip_module","\nconfiguration parameters.",[63,850,852],{"className":306,"code":851,"language":308,"meta":68,"style":68},"gzip on;\ngzip_vary on;\ngzip_min_length 20;\ngzip_types text\u002Fplain application\u002Fjson application\u002Fjavascript application\u002Fx-javascript text\u002Fjavascript text\u002Fcss;\ngzip_proxied expired no-cache no-store private auth;\ngzip_disable \"MSIE [1-6]\\.\";\n",[21,853,854,863,872,882,890,898],{"__ignoreMap":68},[72,855,856,859,861],{"class":74,"line":75},[72,857,858],{"class":78},"gzip ",[72,860,487],{"class":375},[72,862,379],{"class":82},[72,864,865,868,870],{"class":74,"line":86},[72,866,867],{"class":78},"gzip_vary ",[72,869,487],{"class":375},[72,871,379],{"class":82},[72,873,874,877,880],{"class":74,"line":119},[72,875,876],{"class":78},"gzip_min_length ",[72,878,879],{"class":375},"20",[72,881,379],{"class":82},[72,883,884,887],{"class":74,"line":126},[72,885,886],{"class":78},"gzip_types ",[72,888,889],{"class":82},"text\u002Fplain application\u002Fjson application\u002Fjavascript application\u002Fx-javascript text\u002Fjavascript text\u002Fcss;\n",[72,891,892,895],{"class":74,"line":134},[72,893,894],{"class":78},"gzip_proxied ",[72,896,897],{"class":82},"expired no-cache no-store private auth;\n",[72,899,900,903,906],{"class":74,"line":140},[72,901,902],{"class":78},"gzip_disable ",[72,904,905],{"class":176},"\"MSIE [1-6]\\.\"",[72,907,379],{"class":82},[10,909,910],{},"Let's test it out if the fallback works with:",[63,912,914],{"className":754,"code":913,"language":756,"meta":68,"style":68},"curl -I -H \"Accept-Encoding: gzip\" localhost:3333\n",[21,915,916],{"__ignoreMap":68},[72,917,918,921,924,927,930],{"class":74,"line":75},[72,919,920],{"class":763},"curl",[72,922,923],{"class":375}," -I",[72,925,926],{"class":375}," -H",[72,928,929],{"class":176}," \"Accept-Encoding: gzip\"",[72,931,932],{"class":176}," localhost:3333\n",[10,934,935,941,942,945,946,948,949],{},[229,936],{"alt":937,"dataZoomable":68,"height":938,"loading":233,"src":939,"width":940},"Curl Command with Response Headers for gzip",433,"\u002Fcontent\u002Fcurl_gzip.png",1774,"\nAs we can see the response header ",[21,943,944],{},"Content-Encoding"," value as ",[21,947,32],{}," indicating response\ntype is compressed with gzip. Let's also check if brotli works when gzip and br headers\nare sent:\n",[229,950],{"alt":951,"dataZoomable":68,"height":952,"loading":233,"src":953,"width":954},"Curl Command with Response Headers for gzip and br",420,"\u002Fcontent\u002Fcurl_gzip_br.png",1782,[41,956,958],{"id":957},"cleaning-up-dockerfile","Cleaning up Dockerfile",[10,960,961,962,964,965,967],{},"If you see the Dockerfile, its setup is tied to a specific version of nginx (i.e\n1.23.2) and if we want to change the version number we would have to update it\nin multiple lines in the ",[21,963,44],{}," as well as update the brotli module paths\nin our ",[21,966,261],{}," files. Let's try to clean all that up and improve this.",[10,969,970,971,979,980,983,984,986,987,995,996,998,999,1001],{},"We'll use ",[13,972,975,976],{"href":973,"rel":974},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Freference\u002Fbuilder\u002F#arg",[17],"Docker ",[21,977,978],{},"ARG","\nto specify the ",[21,981,982],{},"version"," number of nginx and use it across our ",[21,985,44],{},".\nAlso note that we need add multiple ARG instruction because of how\n",[13,988,991,994],{"href":989,"rel":990},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Freference\u002Fbuilder\u002F#scope",[17],[21,992,993],{},"SCOPE"," works"," in\n",[21,997,44],{}," after every ",[21,1000,79],{}," instruction.",[63,1003,1005],{"className":65,"code":1004,"language":67,"meta":68,"style":68},"ARG version=1.23.2\nFROM nginx:${version}-alpine\nARG version\n\nRUN apk add --update --no-cache git pcre-dev openssl-dev zlib-dev linux-headers build-base \\\n    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-${version}.tar.gz \\\n    && tar zxf nginx-${version}.tar.gz \\\n    && git clone https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli.git \\\n    && cd ngx_brotli \\\n    && git submodule update --init --recursive \\\n    && cd ..\u002Fnginx-${version} \\\n    && .\u002Fconfigure --add-dynamic-module=..\u002Fngx_brotli --with-compat --with-file-aio --with-threads --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-mail --with-mail_ssl_module --with-stream --with-stream_realip_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-cc-opt='-Os -fomit-frame-pointer -g' --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n    && make modules\n\nCOPY nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\n\nWORKDIR \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002F\nCOPY www .\n",[21,1006,1007,1014,1021,1028,1032,1038,1043,1048,1052,1056,1060,1065,1073,1077,1081,1087,1091,1097],{"__ignoreMap":68},[72,1008,1009,1011],{"class":74,"line":75},[72,1010,978],{"class":78},[72,1012,1013],{"class":82}," version=1.23.2\n",[72,1015,1016,1018],{"class":74,"line":86},[72,1017,79],{"class":78},[72,1019,1020],{"class":82}," nginx:${version}-alpine\n",[72,1022,1023,1025],{"class":74,"line":119},[72,1024,978],{"class":78},[72,1026,1027],{"class":82}," version\n",[72,1029,1030],{"class":74,"line":126},[72,1031,123],{"emptyLinePlaceholder":122},[72,1033,1034,1036],{"class":74,"line":134},[72,1035,98],{"class":78},[72,1037,131],{"class":82},[72,1039,1040],{"class":74,"line":140},[72,1041,1042],{"class":82},"    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-${version}.tar.gz \\\n",[72,1044,1045],{"class":74,"line":146},[72,1046,1047],{"class":82},"    && tar zxf nginx-${version}.tar.gz \\\n",[72,1049,1050],{"class":74,"line":152},[72,1051,149],{"class":82},[72,1053,1054],{"class":74,"line":158},[72,1055,155],{"class":82},[72,1057,1058],{"class":74,"line":164},[72,1059,161],{"class":82},[72,1061,1062],{"class":74,"line":170},[72,1063,1064],{"class":82},"    && cd ..\u002Fnginx-${version} \\\n",[72,1066,1067,1069,1071],{"class":74,"line":183},[72,1068,173],{"class":82},[72,1070,177],{"class":176},[72,1072,180],{"class":82},[72,1074,1075],{"class":74,"line":420},[72,1076,186],{"class":82},[72,1078,1079],{"class":74,"line":429},[72,1080,123],{"emptyLinePlaceholder":122},[72,1082,1083,1085],{"class":74,"line":438},[72,1084,697],{"class":78},[72,1086,700],{"class":82},[72,1088,1089],{"class":74,"line":443},[72,1090,123],{"emptyLinePlaceholder":122},[72,1092,1093,1095],{"class":74,"line":452},[72,1094,89],{"class":78},[72,1096,711],{"class":82},[72,1098,1099,1101],{"class":74,"line":457},[72,1100,697],{"class":78},[72,1102,718],{"class":82},[10,1104,1105],{},"Okay now let's try to clean-up our nginx.conf file and free it from nginx\nversion number. i.e these lines",[63,1107,1108],{"className":306,"code":307,"language":308,"meta":68,"style":68},[21,1109,1110,1116],{"__ignoreMap":68},[72,1111,1112,1114],{"class":74,"line":75},[72,1113,315],{"class":78},[72,1115,318],{"class":82},[72,1117,1118,1120],{"class":74,"line":86},[72,1119,315],{"class":78},[72,1121,325],{"class":82},[10,1123,1124,1125,1128,1129,1131,1132,1134,1135,1137],{},"We can copy the compiled dynamic modules from our ",[21,1126,1127],{},"builder"," image into\n\u002Fusr\u002Flib\u002Fnginx\u002Fmodules directory in a clean ",[21,1130,308],{}," image as a new layer and\nload those in ",[21,1133,261],{}," file. Note: I have also updated the Dockerfile\n",[21,1136,288],{}," command and added few extra parameters there for this to work\nproperly.",[10,1139,1140,1141,334],{},"Complete ",[21,1142,50],{},[63,1144,1146],{"className":65,"code":1145,"language":67,"meta":68,"style":68},"ARG version=1.23.2\nFROM nginx:${version}-alpine AS builder\nARG version\n\nWORKDIR \u002Froot\u002F\n\nRUN apk add --update --no-cache git pcre-dev openssl-dev zlib-dev linux-headers build-base \\\n    && wget http:\u002F\u002Fnginx.org\u002Fdownload\u002Fnginx-${version}.tar.gz \\\n    && tar zxf nginx-${version}.tar.gz \\\n    && git clone https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli.git \\\n    && cd ngx_brotli \\\n    && git submodule update --init --recursive \\\n    && cd ..\u002Fnginx-${version} \\\n    && .\u002Fconfigure \\\n    --add-dynamic-module=..\u002Fngx_brotli \\\n    --prefix=\u002Fetc\u002Fnginx \\\n    --sbin-path=\u002Fusr\u002Fsbin\u002Fnginx \\\n    --modules-path=\u002Fusr\u002Flib\u002Fnginx\u002Fmodules \\\n    --conf-path=\u002Fetc\u002Fnginx\u002Fnginx.conf \\\n    --error-log-path=\u002Fvar\u002Flog\u002Fnginx\u002Ferror.log \\\n    --http-log-path=\u002Fvar\u002Flog\u002Fnginx\u002Faccess.log \\\n    --pid-path=\u002Fvar\u002Frun\u002Fnginx.pid \\\n    --lock-path=\u002Fvar\u002Frun\u002Fnginx.lock \\\n    --http-client-body-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fclient_temp \\\n    --http-proxy-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fproxy_temp \\\n    --http-fastcgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Ffastcgi_temp \\\n    --http-uwsgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fuwsgi_temp \\\n    --http-scgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fscgi_temp \\\n    --with-perl_modules_path=\u002Fusr\u002Flib\u002Fperl5\u002Fvendor_perl \\\n    --user=nginx \\\n    --group=nginx \\\n    --with-compat \\\n    --with-file-aio \\\n    --with-threads \\\n    --with-http_addition_module \\\n    --with-http_auth_request_module \\\n    --with-http_dav_module \\\n    --with-http_flv_module \\\n    --with-http_gunzip_module \\\n    --with-http_gzip_static_module \\\n    --with-http_mp4_module \\\n    --with-http_random_index_module \\\n    --with-http_realip_module \\\n    --with-http_secure_link_module \\\n    --with-http_slice_module \\\n    --with-http_ssl_module \\\n    --with-http_stub_status_module \\\n    --with-http_sub_module \\\n    --with-http_v2_module \\\n    --with-mail \\\n    --with-mail_ssl_module \\\n    --with-stream \\\n    --with-stream_realip_module \\\n    --with-stream_ssl_module \\\n    --with-stream_ssl_preread_module \\\n    --with-cc-opt='-Os -fomit-frame-pointer -g' \\\n    --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n    && make modules\n\nFROM nginx:${version}-alpine\n\nARG version\n\nCOPY --from=builder \u002Froot\u002Fnginx-${version}\u002Fobjs\u002Fngx_http_brotli_filter_module.so \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002F\nCOPY --from=builder \u002Froot\u002Fnginx-${version}\u002Fobjs\u002Fngx_http_brotli_static_module.so \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002F\n\nCOPY nginx.conf \u002Fetc\u002Fnginx\u002Fnginx.conf\n\nWORKDIR \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml\u002F\nCOPY www .\n",[21,1147,1148,1154,1165,1171,1175,1181,1185,1191,1195,1199,1203,1207,1211,1215,1220,1225,1230,1235,1240,1245,1250,1255,1260,1265,1270,1275,1280,1285,1290,1295,1300,1305,1310,1315,1320,1325,1330,1336,1342,1348,1354,1360,1366,1372,1378,1384,1390,1396,1402,1408,1414,1420,1426,1432,1438,1444,1455,1461,1466,1471,1478,1483,1490,1495,1503,1511,1516,1523,1528,1535],{"__ignoreMap":68},[72,1149,1150,1152],{"class":74,"line":75},[72,1151,978],{"class":78},[72,1153,1013],{"class":82},[72,1155,1156,1158,1161,1163],{"class":74,"line":86},[72,1157,79],{"class":78},[72,1159,1160],{"class":82}," nginx:${version}-alpine ",[72,1162,628],{"class":78},[72,1164,631],{"class":82},[72,1166,1167,1169],{"class":74,"line":119},[72,1168,978],{"class":78},[72,1170,1027],{"class":82},[72,1172,1173],{"class":74,"line":126},[72,1174,123],{"emptyLinePlaceholder":122},[72,1176,1177,1179],{"class":74,"line":134},[72,1178,89],{"class":78},[72,1180,92],{"class":82},[72,1182,1183],{"class":74,"line":140},[72,1184,123],{"emptyLinePlaceholder":122},[72,1186,1187,1189],{"class":74,"line":146},[72,1188,98],{"class":78},[72,1190,131],{"class":82},[72,1192,1193],{"class":74,"line":152},[72,1194,1042],{"class":82},[72,1196,1197],{"class":74,"line":158},[72,1198,1047],{"class":82},[72,1200,1201],{"class":74,"line":164},[72,1202,149],{"class":82},[72,1204,1205],{"class":74,"line":170},[72,1206,155],{"class":82},[72,1208,1209],{"class":74,"line":183},[72,1210,161],{"class":82},[72,1212,1213],{"class":74,"line":420},[72,1214,1064],{"class":82},[72,1216,1217],{"class":74,"line":429},[72,1218,1219],{"class":82},"    && .\u002Fconfigure \\\n",[72,1221,1222],{"class":74,"line":438},[72,1223,1224],{"class":82},"    --add-dynamic-module=..\u002Fngx_brotli \\\n",[72,1226,1227],{"class":74,"line":443},[72,1228,1229],{"class":82},"    --prefix=\u002Fetc\u002Fnginx \\\n",[72,1231,1232],{"class":74,"line":452},[72,1233,1234],{"class":82},"    --sbin-path=\u002Fusr\u002Fsbin\u002Fnginx \\\n",[72,1236,1237],{"class":74,"line":457},[72,1238,1239],{"class":82},"    --modules-path=\u002Fusr\u002Flib\u002Fnginx\u002Fmodules \\\n",[72,1241,1242],{"class":74,"line":465},[72,1243,1244],{"class":82},"    --conf-path=\u002Fetc\u002Fnginx\u002Fnginx.conf \\\n",[72,1246,1247],{"class":74,"line":476},[72,1248,1249],{"class":82},"    --error-log-path=\u002Fvar\u002Flog\u002Fnginx\u002Ferror.log \\\n",[72,1251,1252],{"class":74,"line":481},[72,1253,1254],{"class":82},"    --http-log-path=\u002Fvar\u002Flog\u002Fnginx\u002Faccess.log \\\n",[72,1256,1257],{"class":74,"line":492},[72,1258,1259],{"class":82},"    --pid-path=\u002Fvar\u002Frun\u002Fnginx.pid \\\n",[72,1261,1262],{"class":74,"line":502},[72,1263,1264],{"class":82},"    --lock-path=\u002Fvar\u002Frun\u002Fnginx.lock \\\n",[72,1266,1267],{"class":74,"line":512},[72,1268,1269],{"class":82},"    --http-client-body-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fclient_temp \\\n",[72,1271,1272],{"class":74,"line":517},[72,1273,1274],{"class":82},"    --http-proxy-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fproxy_temp \\\n",[72,1276,1277],{"class":74,"line":524},[72,1278,1279],{"class":82},"    --http-fastcgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Ffastcgi_temp \\\n",[72,1281,1282],{"class":74,"line":535},[72,1283,1284],{"class":82},"    --http-uwsgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fuwsgi_temp \\\n",[72,1286,1287],{"class":74,"line":546},[72,1288,1289],{"class":82},"    --http-scgi-temp-path=\u002Fvar\u002Fcache\u002Fnginx\u002Fscgi_temp \\\n",[72,1291,1292],{"class":74,"line":556},[72,1293,1294],{"class":82},"    --with-perl_modules_path=\u002Fusr\u002Flib\u002Fperl5\u002Fvendor_perl \\\n",[72,1296,1297],{"class":74,"line":565},[72,1298,1299],{"class":82},"    --user=nginx \\\n",[72,1301,1302],{"class":74,"line":574},[72,1303,1304],{"class":82},"    --group=nginx \\\n",[72,1306,1307],{"class":74,"line":580},[72,1308,1309],{"class":82},"    --with-compat \\\n",[72,1311,1312],{"class":74,"line":586},[72,1313,1314],{"class":82},"    --with-file-aio \\\n",[72,1316,1317],{"class":74,"line":592},[72,1318,1319],{"class":82},"    --with-threads \\\n",[72,1321,1322],{"class":74,"line":598},[72,1323,1324],{"class":82},"    --with-http_addition_module \\\n",[72,1326,1327],{"class":74,"line":603},[72,1328,1329],{"class":82},"    --with-http_auth_request_module \\\n",[72,1331,1333],{"class":74,"line":1332},37,[72,1334,1335],{"class":82},"    --with-http_dav_module \\\n",[72,1337,1339],{"class":74,"line":1338},38,[72,1340,1341],{"class":82},"    --with-http_flv_module \\\n",[72,1343,1345],{"class":74,"line":1344},39,[72,1346,1347],{"class":82},"    --with-http_gunzip_module \\\n",[72,1349,1351],{"class":74,"line":1350},40,[72,1352,1353],{"class":82},"    --with-http_gzip_static_module \\\n",[72,1355,1357],{"class":74,"line":1356},41,[72,1358,1359],{"class":82},"    --with-http_mp4_module \\\n",[72,1361,1363],{"class":74,"line":1362},42,[72,1364,1365],{"class":82},"    --with-http_random_index_module \\\n",[72,1367,1369],{"class":74,"line":1368},43,[72,1370,1371],{"class":82},"    --with-http_realip_module \\\n",[72,1373,1375],{"class":74,"line":1374},44,[72,1376,1377],{"class":82},"    --with-http_secure_link_module \\\n",[72,1379,1381],{"class":74,"line":1380},45,[72,1382,1383],{"class":82},"    --with-http_slice_module \\\n",[72,1385,1387],{"class":74,"line":1386},46,[72,1388,1389],{"class":82},"    --with-http_ssl_module \\\n",[72,1391,1393],{"class":74,"line":1392},47,[72,1394,1395],{"class":82},"    --with-http_stub_status_module \\\n",[72,1397,1399],{"class":74,"line":1398},48,[72,1400,1401],{"class":82},"    --with-http_sub_module \\\n",[72,1403,1405],{"class":74,"line":1404},49,[72,1406,1407],{"class":82},"    --with-http_v2_module \\\n",[72,1409,1411],{"class":74,"line":1410},50,[72,1412,1413],{"class":82},"    --with-mail \\\n",[72,1415,1417],{"class":74,"line":1416},51,[72,1418,1419],{"class":82},"    --with-mail_ssl_module \\\n",[72,1421,1423],{"class":74,"line":1422},52,[72,1424,1425],{"class":82},"    --with-stream \\\n",[72,1427,1429],{"class":74,"line":1428},53,[72,1430,1431],{"class":82},"    --with-stream_realip_module \\\n",[72,1433,1435],{"class":74,"line":1434},54,[72,1436,1437],{"class":82},"    --with-stream_ssl_module \\\n",[72,1439,1441],{"class":74,"line":1440},55,[72,1442,1443],{"class":82},"    --with-stream_ssl_preread_module \\\n",[72,1445,1447,1450,1452],{"class":74,"line":1446},56,[72,1448,1449],{"class":82},"    --with-cc-opt=",[72,1451,177],{"class":176},[72,1453,1454],{"class":82}," \\\n",[72,1456,1458],{"class":74,"line":1457},57,[72,1459,1460],{"class":82},"    --with-ld-opt=-Wl,--as-needed,-O1,--sort-common \\\n",[72,1462,1464],{"class":74,"line":1463},58,[72,1465,186],{"class":82},[72,1467,1469],{"class":74,"line":1468},59,[72,1470,123],{"emptyLinePlaceholder":122},[72,1472,1474,1476],{"class":74,"line":1473},60,[72,1475,79],{"class":78},[72,1477,1020],{"class":82},[72,1479,1481],{"class":74,"line":1480},61,[72,1482,123],{"emptyLinePlaceholder":122},[72,1484,1486,1488],{"class":74,"line":1485},62,[72,1487,978],{"class":78},[72,1489,1027],{"class":82},[72,1491,1493],{"class":74,"line":1492},63,[72,1494,123],{"emptyLinePlaceholder":122},[72,1496,1498,1500],{"class":74,"line":1497},64,[72,1499,697],{"class":78},[72,1501,1502],{"class":82}," --from=builder \u002Froot\u002Fnginx-${version}\u002Fobjs\u002Fngx_http_brotli_filter_module.so \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002F\n",[72,1504,1506,1508],{"class":74,"line":1505},65,[72,1507,697],{"class":78},[72,1509,1510],{"class":82}," --from=builder \u002Froot\u002Fnginx-${version}\u002Fobjs\u002Fngx_http_brotli_static_module.so \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002F\n",[72,1512,1514],{"class":74,"line":1513},66,[72,1515,123],{"emptyLinePlaceholder":122},[72,1517,1519,1521],{"class":74,"line":1518},67,[72,1520,697],{"class":78},[72,1522,700],{"class":82},[72,1524,1526],{"class":74,"line":1525},68,[72,1527,123],{"emptyLinePlaceholder":122},[72,1529,1531,1533],{"class":74,"line":1530},69,[72,1532,89],{"class":78},[72,1534,711],{"class":82},[72,1536,1538,1540],{"class":74,"line":1537},70,[72,1539,697],{"class":78},[72,1541,718],{"class":82},[10,1543,1140,1544,334],{},[21,1545,261],{},[63,1547,1549],{"className":306,"code":1548,"language":308,"meta":68,"style":68},"load_module \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002Fngx_http_brotli_filter_module.so;\nload_module \u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002Fngx_http_brotli_static_module.so;\n\nuser nginx;\n\nworker_processes 1;\n\nevents {\n  worker_connections 1024;\n}\n\nhttp {\n  include \u002Fetc\u002Fnginx\u002Fmime.types;\n  default_type application\u002Foctet-stream;\n\n  root \u002Fusr\u002Fshare\u002Fnginx\u002Fhtml;\n\n  server {\n    listen 80;\n\n    sendfile on;\n    tcp_nopush on;\n    tcp_nodelay on;\n\n    gzip on;\n    gzip_vary on;\n    gzip_min_length 20;\n    gzip_types text\u002Fplain application\u002Fjson application\u002Fjavascript application\u002Fx-javascript text\u002Fjavascript text\u002Fcss;\n    gzip_proxied expired no-cache no-store private auth;\n    gzip_disable \"MSIE [1-6]\\.\";\n\n    # Add Brotli compression config\n    brotli on;\n    brotli_comp_level 6;\n    brotli_static on;\n    brotli_types application\u002Fatom+xml application\u002Fjavascript application\u002Fjson application\u002Frss+xml\n             application\u002Fvnd.ms-fontobject application\u002Fx-font-opentype application\u002Fx-font-truetype\n             application\u002Fx-font-ttf application\u002Fx-javascript application\u002Fxhtml+xml application\u002Fxml\n             font\u002Feot font\u002Fopentype font\u002Fotf font\u002Ftruetype image\u002Fsvg+xml image\u002Fvnd.microsoft.icon\n             image\u002Fx-icon image\u002Fx-win-bitmap text\u002Fcss text\u002Fjavascript text\u002Fplain text\u002Fxml;\n  }\n\n}\n",[21,1550,1551,1558,1565,1569,1575,1579,1587,1591,1597,1605,1609,1613,1619,1625,1631,1635,1641,1645,1651,1659,1663,1671,1679,1687,1691,1700,1709,1718,1725,1732,1741,1745,1749,1757,1765,1773,1779,1785,1789,1793,1798,1802,1806],{"__ignoreMap":68},[72,1552,1553,1555],{"class":74,"line":75},[72,1554,315],{"class":78},[72,1556,1557],{"class":82},"\u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002Fngx_http_brotli_filter_module.so;\n",[72,1559,1560,1562],{"class":74,"line":86},[72,1561,315],{"class":78},[72,1563,1564],{"class":82},"\u002Fusr\u002Flib\u002Fnginx\u002Fmodules\u002Fngx_http_brotli_static_module.so;\n",[72,1566,1567],{"class":74,"line":119},[72,1568,123],{"emptyLinePlaceholder":122},[72,1570,1571,1573],{"class":74,"line":126},[72,1572,360],{"class":78},[72,1574,363],{"class":82},[72,1576,1577],{"class":74,"line":134},[72,1578,123],{"emptyLinePlaceholder":122},[72,1580,1581,1583,1585],{"class":74,"line":140},[72,1582,372],{"class":78},[72,1584,376],{"class":375},[72,1586,379],{"class":82},[72,1588,1589],{"class":74,"line":146},[72,1590,123],{"emptyLinePlaceholder":122},[72,1592,1593,1595],{"class":74,"line":152},[72,1594,388],{"class":78},[72,1596,391],{"class":82},[72,1598,1599,1601,1603],{"class":74,"line":158},[72,1600,396],{"class":78},[72,1602,399],{"class":375},[72,1604,379],{"class":82},[72,1606,1607],{"class":74,"line":164},[72,1608,406],{"class":82},[72,1610,1611],{"class":74,"line":170},[72,1612,123],{"emptyLinePlaceholder":122},[72,1614,1615,1617],{"class":74,"line":183},[72,1616,415],{"class":78},[72,1618,391],{"class":82},[72,1620,1621,1623],{"class":74,"line":420},[72,1622,423],{"class":78},[72,1624,426],{"class":82},[72,1626,1627,1629],{"class":74,"line":429},[72,1628,432],{"class":78},[72,1630,435],{"class":82},[72,1632,1633],{"class":74,"line":438},[72,1634,123],{"emptyLinePlaceholder":122},[72,1636,1637,1639],{"class":74,"line":443},[72,1638,446],{"class":78},[72,1640,449],{"class":82},[72,1642,1643],{"class":74,"line":452},[72,1644,123],{"emptyLinePlaceholder":122},[72,1646,1647,1649],{"class":74,"line":457},[72,1648,460],{"class":78},[72,1650,391],{"class":82},[72,1652,1653,1655,1657],{"class":74,"line":465},[72,1654,468],{"class":78},[72,1656,471],{"class":375},[72,1658,379],{"class":82},[72,1660,1661],{"class":74,"line":476},[72,1662,123],{"emptyLinePlaceholder":122},[72,1664,1665,1667,1669],{"class":74,"line":481},[72,1666,484],{"class":78},[72,1668,487],{"class":375},[72,1670,379],{"class":82},[72,1672,1673,1675,1677],{"class":74,"line":492},[72,1674,495],{"class":78},[72,1676,487],{"class":375},[72,1678,379],{"class":82},[72,1680,1681,1683,1685],{"class":74,"line":502},[72,1682,505],{"class":78},[72,1684,487],{"class":375},[72,1686,379],{"class":82},[72,1688,1689],{"class":74,"line":512},[72,1690,123],{"emptyLinePlaceholder":122},[72,1692,1693,1696,1698],{"class":74,"line":517},[72,1694,1695],{"class":78},"    gzip ",[72,1697,487],{"class":375},[72,1699,379],{"class":82},[72,1701,1702,1705,1707],{"class":74,"line":524},[72,1703,1704],{"class":78},"    gzip_vary ",[72,1706,487],{"class":375},[72,1708,379],{"class":82},[72,1710,1711,1714,1716],{"class":74,"line":535},[72,1712,1713],{"class":78},"    gzip_min_length ",[72,1715,879],{"class":375},[72,1717,379],{"class":82},[72,1719,1720,1723],{"class":74,"line":546},[72,1721,1722],{"class":78},"    gzip_types ",[72,1724,889],{"class":82},[72,1726,1727,1730],{"class":74,"line":556},[72,1728,1729],{"class":78},"    gzip_proxied ",[72,1731,897],{"class":82},[72,1733,1734,1737,1739],{"class":74,"line":565},[72,1735,1736],{"class":78},"    gzip_disable ",[72,1738,905],{"class":176},[72,1740,379],{"class":82},[72,1742,1743],{"class":74,"line":574},[72,1744,123],{"emptyLinePlaceholder":122},[72,1746,1747],{"class":74,"line":580},[72,1748,521],{"class":520},[72,1750,1751,1753,1755],{"class":74,"line":586},[72,1752,527],{"class":78},[72,1754,530],{"class":375},[72,1756,379],{"class":82},[72,1758,1759,1761,1763],{"class":74,"line":592},[72,1760,538],{"class":78},[72,1762,541],{"class":375},[72,1764,379],{"class":82},[72,1766,1767,1769,1771],{"class":74,"line":598},[72,1768,549],{"class":78},[72,1770,530],{"class":375},[72,1772,379],{"class":82},[72,1774,1775,1777],{"class":74,"line":603},[72,1776,559],{"class":78},[72,1778,562],{"class":82},[72,1780,1781,1783],{"class":74,"line":1332},[72,1782,568],{"class":375},[72,1784,571],{"class":82},[72,1786,1787],{"class":74,"line":1338},[72,1788,577],{"class":82},[72,1790,1791],{"class":74,"line":1344},[72,1792,583],{"class":82},[72,1794,1795],{"class":74,"line":1350},[72,1796,1797],{"class":82},"             image\u002Fx-icon image\u002Fx-win-bitmap text\u002Fcss text\u002Fjavascript text\u002Fplain text\u002Fxml;\n",[72,1799,1800],{"class":74,"line":1356},[72,1801,595],{"class":82},[72,1803,1804],{"class":74,"line":1362},[72,1805,123],{"emptyLinePlaceholder":122},[72,1807,1808],{"class":74,"line":1368},[72,1809,406],{"class":82},[10,1811,1812,1813,1815,1816],{},"Now if we ever want to update our nginx version we just update one ARG ",[21,1814,982],{},"\ninstruction in our ",[21,1817,44],{},[10,1819,1820],{},"Further Reading \u002F References:",[219,1822,1823,1830,1837,1843],{},[196,1824,1825],{},[13,1826,1829],{"href":1827,"rel":1828},"https:\u002F\u002Fcss-tricks.com\u002Fbrotli-static-compression\u002F",[17],"Brotli and Static Compression",[196,1831,1832],{},[13,1833,1836],{"href":1834,"rel":1835},"https:\u002F\u002Fgithub.com\u002Fgoogle\u002Fngx_brotli#installation",[17],"nginx brotli",[196,1838,1839],{},[13,1840,1842],{"href":845,"rel":1841},[17],"nginx gzip",[196,1844,1845],{},[13,1846,1849],{"href":1847,"rel":1848},"https:\u002F\u002Fdocs.docker.com\u002Fengine\u002Freference\u002Fbuilder\u002F",[17],"Dockerfile Reference",[1851,1852,1853],"style",{},"html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}",{"title":68,"searchDepth":86,"depth":86,"links":1855},[1856,1859,1860,1861],{"id":43,"depth":86,"text":44,"children":1857},[1858],{"id":190,"depth":119,"text":191},{"id":296,"depth":86,"text":297},{"id":831,"depth":86,"text":832},{"id":957,"depth":86,"text":958},"2022-11-27","Add Brotli and Gzip compression to nginx inside Docker. Build the ngx_brotli module into the image, set the levels and MIME types, then check the headers.",false,"md","2026-08-29T17:42:32+07:00",{},"\u002Fblog\u002Fnginx-brotli-gzip-compression-docker","8 min read",{"title":5,"description":1863},"blog\u002Fnginx-brotli-gzip-compression-docker","e_vRM8TrLtqokMGFz4h92w_5cZln5TeEAf48MthBILs",1788101292657]