Search code examples
amazon-web-servicesnginxhttp-headersamazon-elastic-beanstalk

Install a dynamic nginx module on AWS Elastic Beanstalk, Amazon Linux 2


I would like to remove the "Server" HTTP header, added by nginx. The module headers-more-nginx-module adds this functionality.

This module is not available in the default Amazon yum repository.

How can I add the module to my AWS Elastic Beanstalk EC2 instances running on Amazon Linux 2?


Solution

  • You will need to compile the module from source code, as a "dynamic module". Here is an example, specifically for headers-more-nginx-module.

    Assuming you upload your application to Elastic Beanstalk in a zip file, the zip should contain three files, with contents as below.

    .ebextensions/01-nginx-modules.config

    # Install any system-level dependencies required to build nginx or your module
    packages:
      yum:
        pcre2-devel: []
        zlib-devel: []
    
    # Download the source for your nginx module
    sources:
      /root: https://github.com/openresty/headers-more-nginx-module/archive/refs/tags/v0.34.tar.gz
    

    .platform/hooks/predeploy/01-nginx-modules.sh

    #!/usr/bin/env bash
    
    set -o errexit -o pipefail -o verbose
    
    # Ensure we start in the user home dir
    cd ~
    
    # Dynamically get the current version of nginx
    nginx -V &> nginx_version.txt
    nginx_version=$(grep -oP "(?<=nginx version: nginx/).*" ./nginx_version.txt)
    
    # Download and extract nginx
    wget -O nginx.tar.gz http://nginx.org/download/nginx-"${nginx_version}".tar.gz
    tar -xzvf nginx.tar.gz
    
    # Build the module. Most of the settings are copied from `nginx -V`, in case they're required for binary compatibility.
    # We really just add `--add-dynamic-module` to the end.
    cd nginx-"${nginx_version}"/
    ./configure \
      --prefix=/usr/share/nginx \
      --sbin-path=/usr/sbin/nginx \
      --modules-path=/usr/lib64/nginx/modules \
      --conf-path=/etc/nginx/nginx.conf \
      --error-log-path=/var/log/nginx/error.log \
      --http-log-path=/var/log/nginx/access.log \
      --http-client-body-temp-path=/var/lib/nginx/tmp/client_body \
      --http-proxy-temp-path=/var/lib/nginx/tmp/proxy \
      --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi \
      --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi \
      --http-scgi-temp-path=/var/lib/nginx/tmp/scgi \
      --pid-path=/run/nginx.pid \
      --lock-path=/run/lock/subsys/nginx \
      --user=nginx \
      --group=nginx \
      --with-compat \
      --with-debug \
      --with-file-aio \
      --with-mail=dynamic \
      --with-pcre \
      --with-pcre-jit \
      --with-stream=dynamic \
      --with-threads \
      --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic' \
      --with-ld-opt='-Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -Wl,-E' \
      --add-dynamic-module=../headers-more-nginx-module-0.34/
    make modules
    
    # Copy the module somewhere it can be loaded dynamically.
    # Overwrite any existing file (`\cp`, to skip the alias for `cp -i`, which prompts for overwrite).
    \cp objs/ngx_http_headers_more_filter_module.so /usr/share/nginx/modules/
    
    # Edit the staged default nginx.conf, just inserting the `load_module` directive.
    # (This can't live in a `conf.d/` file, which only allows extending the `http` directive.)
    # The `sed` comment will insert (/i) our code before the line containing `events {`.
    # `-i.bak` will update the file in place, saving the original version as a new file with extension `.bak`.
    sed -i.bak \
      '/events {/i # Hide the Server HTTP header\nload_module modules/ngx_http_headers_more_filter_module.so;\n' \
      /var/proxy/staging/nginx/nginx.conf
    

    .platform/nginx/conf.d/01-remove-headers.conf

    more_clear_headers Server;
    

    This is is where you apply any directives within the http context.

    Risks

    1. Downloading from github.com and nginx.com means your app deployment could fail if either host is unavailable, or if the files move on those third-party servers.
    2. Installing dependencies, downloading source code, and compiling the module on each deployment will slow down your app deployments.
    3. Updates to Amazon Linux 2 (or changing the OS) could change the version of nginx, or the compilation flags, which create binary incompatibility.

    These risks could be mitigated by:

    1. Storing the source packages on S3.
    2. Storing the compiled module in S3, and make the compilation a manual step. (Devs could compile nginx in a VM.)
    3. ... hmm...