diff --git a/Dockerfile b/Dockerfile index 37ce3d0..ba5f7a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,10 +2,15 @@ FROM behance/docker-base:5.0.1-ubuntu-20.04 # Use in multi-phase builds, when an init process requests for the container to gracefully exit, so that it may be committed # Used with alternative CMD (worker.sh), leverages supervisor to maintain long-running processes +# +# NGINX_VERSION is the MAJOR.MINOR.PATCH version available from upstream +# providers (https://launchpad.net/~ondrej/+archive/ubuntu/nginx) at the time +# of the build ENV CONTAINER_ROLE=web \ CONTAINER_PORT=8080 \ CONF_NGINX_SITE="/etc/nginx/sites-available/default" \ CONF_NGINX_SERVER="/etc/nginx/nginx.conf" \ + NGINX_VERSION="1.22.0" \ NOT_ROOT_USER=www-data \ S6_KILL_FINISH_MAXTIME=55000 @@ -23,8 +28,9 @@ RUN /bin/bash -e /security_updates.sh && \ add-apt-repository ppa:ondrej/nginx -y && \ apt-get update -yqq && \ apt-get install -yqq --no-install-recommends \ - nginx-light \ + nginx-light=${NGINX_VERSION}-* \ ca-certificates \ + libnginx-mod-brotli=${NGINX_VERSION}-* \ && \ apt-get remove --purge -yq \ manpages \ diff --git a/container/root/etc/cont-init.d/10-nginx-config.sh b/container/root/etc/cont-init.d/10-nginx-config.sh index d58f1f6..7224f72 100755 --- a/container/root/etc/cont-init.d/10-nginx-config.sh +++ b/container/root/etc/cont-init.d/10-nginx-config.sh @@ -84,8 +84,35 @@ then sed -i "s/^[ ]*listen ${CONTAINER_PORT}/ listen ${CONTAINER_PORT} ssl/" $CONF_NGINX_SITE fi +if [[ $SERVER_ENABLE_NGX_BROTLI ]]; +then + echo "[nginx] enabling nginx brotli module" + # Enable the brotli module + sed -i "s/#load_module modules\/ngx_http_brotli_/load_module modules\/ngx_http_brotli_/" $CONF_NGINX_SERVER + + # Enable brotli-specific configuration. All brotli configs begin with brotli* + # Ref: https://github.com/google/ngx_brotli + sed -i "s/#brotli/brotli/" $CONF_NGINX_SERVER +fi + if [[ $SERVER_ENABLE_NGX_HTTP_JS ]]; then + # Enable the njs module echo "[nginx] enabling nginx njs module" - sed -i "s/#load_module/load_module/" $CONF_NGINX_SERVER + sed -i "s/#load_module modules\/ngx_http_js_/load_module modules\/ngx_http_js_/" $CONF_NGINX_SERVER +fi + +# Useful when you need to debug the contents of nginx.conf +# +# Should be the last entry in this script to ensure that all prior +# modifications have been applied +if [[ $SERVER_SHOW_NGINX_CONF ]]; +then + if [[ -f "$CONF_NGINX_SERVER" ]]; + then + echo "" + echo "*** SERVER_SHOW_NGINX_CONF is set. Dumping $CONF_NGINX_SERVER ***" + echo "" + cat $CONF_NGINX_SERVER + fi fi diff --git a/container/root/etc/nginx/nginx.conf b/container/root/etc/nginx/nginx.conf index 233e6d2..0be742c 100644 --- a/container/root/etc/nginx/nginx.conf +++ b/container/root/etc/nginx/nginx.conf @@ -19,9 +19,12 @@ error_log /dev/stdout warn; # Number of file descriptors used for nginx worker_rlimit_nofile 40000; -# Set SERVER_ENABLE_NGX_HTTP_JS=true to enable this module -#load_module /usr/lib/nginx/modules/ngx_http_js_module.so; +# Set Set SERVER_ENABLE_NGX_BROTLI=true to enable this module +#load_module modules/ngx_http_brotli_filter_module.so; +#load_module modules/ngx_http_brotli_static_module.so; +# Set SERVER_ENABLE_NGX_HTTP_JS=true to enable this module +#load_module modules/ngx_http_js_module.so; events { # Optimized to serve many clients with each thread, essential for linux @@ -102,6 +105,12 @@ http { #gzip on; + # Set SERVER_ENABLE_NGX_BROTLI=true to enable the following brotli settings + #brotli on; + #brotli_static on; + #brotli_comp_level 6; + #brotli_types application/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font application/x-font-opentype application/x-font-otf application/x-font-truetype application/x-font-ttf application/xhtml+xml application/xml font/opentype font/otf font/ttf image/svg+xml image/x-icon text/css text/javascript text/plain text/xml; + client_body_temp_path /tmp/.nginx/client_body; fastcgi_temp_path /tmp/.nginx/fastcgi_temp; proxy_temp_path /tmp/.nginx/proxy_temp; diff --git a/container/root/tests/ubuntu/brotli.goss.yaml b/container/root/tests/ubuntu/brotli.goss.yaml new file mode 100644 index 0000000..d3007d1 --- /dev/null +++ b/container/root/tests/ubuntu/brotli.goss.yaml @@ -0,0 +1,20 @@ +file: + /etc/nginx/nginx.conf: + exists: true + # By default, the brotli configs are specified in nginx.conf but disabled + contains: + - '/#load_module\s*modules\/ngx_http_brotli_filter_module\.so;/' + - '/#load_module\s*modules\/ngx_http_brotli_static_module\.so;/' + - '/#brotli\s*on;/' + - '/#brotli_static\s*on;/' + - '/#brotli_comp_level\s*6;/' + - '/#brotli_types/' + title: /etc/nginx/nginx.conf should exist and contain brotli-specific configs + /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so: + exists: true + owner: root + title: /usr/lib/nginx/modules/ngx_http_brotli_filter_module.so should exist and owned by root + /usr/lib/nginx/modules/ngx_http_brotli_static_module.so: + exists: true + owner: root + title: /usr/lib/nginx/modules/ngx_http_brotli_static_module.so should exist and owned by root diff --git a/container/root/tests/ubuntu/nginx.goss.yaml b/container/root/tests/ubuntu/nginx.goss.yaml index 429cf0c..60999fb 100644 --- a/container/root/tests/ubuntu/nginx.goss.yaml +++ b/container/root/tests/ubuntu/nginx.goss.yaml @@ -1,5 +1,7 @@ gossfile: /tests/common/nginx.goss.yaml: {} + # To be enabled when we add support for Ubuntu 22.04 + # /tests/ubuntu/brotli.goss.yaml: {} user: www-data: diff --git a/docs/env_vars.md b/docs/env_vars.md index 7dd78e4..fcbf841 100644 --- a/docs/env_vars.md +++ b/docs/env_vars.md @@ -10,7 +10,8 @@ SERVER_APP_NAME | SERVER_APP_NAME='view' | Gets appended to the default logging SERVER_GZIP_OPTIONS | SERVER_GZIP_OPTIONS=1 | Allows default set of static content to be served gzipped SERVER_SENDFILE | SERVER_SENDFILE=off | Allows runtime to specify value of nginx's `sendfile` (default, on) SERVER_ENABLE_HTTPS | SERVER_ENABLE_HTTPS=true | Enable encrypted transmission using certificates -SERVER_ENABLE_NGX_HTTP_JS | SERVER_ENABLE_NGX_HTTP_JS=true | Enable nginx njs module (default, false) +SERVER_ENABLE_NGX_BROTLI | SERVER_ENABLE_NGX_BROTLI=true | Enable Brotli compression (default: false) +SERVER_ENABLE_NGX_HTTP_JS | SERVER_ENABLE_NGX_HTTP_JS=true | Enable nginx njs module (default: false) SERVER_KEEPALIVE | SERVER_KEEPALIVE=30 | Define HTTP 1.1's keepalive timeout SERVER_WORKER_PROCESSES | SERVER_WORKER_PROCESSES=4 | Set to the number of cores in the machine, or the number of cores allocated to container SERVER_WORKER_CONNECTIONS | SERVER_WORKER_CONNECTIONS=2048 | Sets up the number of connections for worker processes @@ -18,6 +19,7 @@ SERVER_CLIENT_HEADER_BUFFER_SIZE | SERVER_CLIENT_HEADER_BUFFER_SIZE=16k | [docs] SERVER_LARGE_CLIENT_HEADER_BUFFERS | SERVER_LARGE_CLIENT_HEADER_BUFFERS=8 16k | [docs](http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers) SERVER_CLIENT_BODY_BUFFER_SIZE | SERVER_CLIENT_BODY_BUFFER_SIZE=128k | [docs](http://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size) SERVER_LOG_MINIMAL | SERVER_LOG_MINIMAL=1 | Minimize the logging format, appropriate for development environments +SERVER_SHOW_NGINX_CONF | SERVER_SHOW_NGINX_CONF=true | Dump the contents of nginx.conf. Useful when debugging the config during start up (default: false) S6_KILL_FINISH_MAXTIME | S6_KILL_FINISH_MAXTIME=55000 | The maximum time (in ms) a script in /etc/cont-finish.d could take before sending a KILL signal to it. Take into account that this parameter will be used per each script execution, it's not a max time for the whole set of scripts. This value has a max of 65535 on Alpine variants. S6_KILL_GRACETIME | S6_KILL_GRACETIME=500 | Wait time (in ms) for S6 finish scripts before sending kill signal diff --git a/tests/brotli/Dockerfile b/tests/brotli/Dockerfile new file mode 100644 index 0000000..57e2f23 --- /dev/null +++ b/tests/brotli/Dockerfile @@ -0,0 +1 @@ +FROM docker-nginx:brotli diff --git a/tests/brotli/Makefile b/tests/brotli/Makefile new file mode 100644 index 0000000..1a6425a --- /dev/null +++ b/tests/brotli/Makefile @@ -0,0 +1,16 @@ +.PHONY: build + +# Name of the image to build +IMAGE_TAG=docker-nginx:brotli + +default: build + +build-src: + cd ../.. && docker build -t $(IMAGE_TAG) -f Dockerfile . + +build: build-src + docker build -t $(IMAGE_TAG)-test -f Dockerfile . + +dgoss: build + GOSS_WAIT_OPTS="-r 60s -s 5s > /dev/null" dgoss run -e SERVER_ENABLE_NGX_BROTLI=true -p 8080:8080 $(IMAGE_TAG)-test + diff --git a/tests/brotli/README.md b/tests/brotli/README.md new file mode 100644 index 0000000..5a4ecfb --- /dev/null +++ b/tests/brotli/README.md @@ -0,0 +1,52 @@ +brotli +==== + +This is a simple [dgoss] test to validate that the brotli module is running. + +To test: + +1. cd `tests/brotli` +1. Run `make dgoss` + +Behind the scenes, it builds the `brotli`-enabled docker image, then builds +a test image. + +Finally, it runs `dgoss` and passes in `Accept-Encoding: gzip, deflate, br` +as part of the request. + +Here's a sample curl request when `SERVER_ENABLE_NGX_BROTLI=true`: + +```shell +$ curl http://localhost:8080/ -v -H "Accept-Encoding: gzip, deflate, br" +* Trying ::1... +* TCP_NODELAY set +* Connected to localhost (::1) port 8083 (#0) +> GET / HTTP/1.1 +> Host: localhost:8080 +> User-Agent: curl/7.64.1 +> Accept: */* +> Accept-Encoding: gzip, deflate, br +> +< HTTP/1.1 200 OK +< Server: nginx +< Date: Wed, 17 Aug 2022 21:41:21 GMT +< Content-Type: text/html +< Last-Modified: Wed, 17 Aug 2022 17:59:04 GMT +< Transfer-Encoding: chunked +< Connection: keep-alive +< ETag: W/"62fd2c68-279" +< X-XSS-Protection: 1; mode=block +< X-Content-Type-Options: nosniff +< Content-Encoding: br +< +Warning: Binary output can mess up your terminal. Use "--output -" to tell +Warning: curl to output it to your terminal anyway, or consider "--output +Warning: " to save to a file. +* Failed writing body (0 != 299) +* Failed writing data +* Closing connection 0 +``` + +The script assumes that you have `dgoss` installed. + +[dgoss]: https://github.com/aelsabbahy/goss/blob/master/extras/dgoss/README.md diff --git a/tests/brotli/goss.yaml b/tests/brotli/goss.yaml new file mode 100644 index 0000000..ac2b6ef --- /dev/null +++ b/tests/brotli/goss.yaml @@ -0,0 +1,23 @@ +file: + /etc/nginx/nginx.conf: + exists: true + contains: + - '/load_module\s*modules\/ngx_http_brotli_filter_module\.so;/' + - '/load_module\s*modules\/ngx_http_brotli_static_module\.so;/' + - '/brotli\s*on;/' + - '/brotli_static\s*on;/' + - '/brotli_comp_level\s*6;/' + - '/brotli_types/' + title: brotli-specific modules and configs should be enabled +http: + http://localhost:8080/: + status: 200 + allow-insecure: true + request-headers: + - "Accept-Encoding: gzip, deflate, br" + timeout: 5000 + headers: + # When you pass in the Accept-Encoding header + # the response header will include "Content-Encoding: br" + # and the output will be compressed/binary + - "Content-Encoding: br" diff --git a/tests/brotli/goss_wait.yaml b/tests/brotli/goss_wait.yaml new file mode 100644 index 0000000..bcbf127 --- /dev/null +++ b/tests/brotli/goss_wait.yaml @@ -0,0 +1,7 @@ +file: + /goss/docker_output.log: + exists: true + contains: + # When starting up the container, this line should show up + # if SERVER_ENABLE_NGX_BROTLI=true + - '[nginx] enabling nginx brotli module'