Nginx proxy: unknown directive "ssl_early_data"

Hello good fellows of the Mattermost world.

Summary

I’m trying to setup a Nginx proxy with the example from the officiel documentation however when validating the Nginx configuration file it fails and throws unknown directive "ssl_early_data".

TLS 1.3 is enabled on Nginx, and so is http_ssl_module.

Steps to reproduce

Install Mattermost, create Nginx configuration with example from Installing Mattermost on Debian Buster — Mattermost documentation then validate configuration file with sudo nginx -t.

Expected behavior

File is expected to be validated by Nginx.

Observed behavior

Error while validating Nginx configuration file:

nginx: [emerg] unknown directive "ssl_early_data" in /etc/nginx/sites-enabled/mattermost.conf:32
nginx: configuration file /etc/nginx/nginx.conf test failed

Thank you for any help I could get.

Just did some quick researching - it seems that the module you are attempting to utilize takes advantage of TLS 1.3, which must be enabled/included in your configuration file explicitly, or else the ssl_early_data module will fail.

Example (without any of the reverse proxy configuration):

root@95eed784a081:/etc/nginx/conf.d# cat 443.conf

server {
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        server_name _;

        ssl_protocols TLSv1.2 TLSv1.3;
        ssl_early_data on;
        #
        ssl_certificate /etc/ssl/certs/ssl-cert-snakeoil.pem;
        ssl_certificate_key /etc/ssl/private/ssl-cert-snakeoil.key;
[..]

Hello @XxLilBoPeepsxX,

Thank you for the suggestion.

The TLSv1.3 instruction is already included in my Nginx configuration which is inspired from the official Mattermost documentation.

It was already enabled by default in the main Nginx configuration anyway.

For more information here is my full configuration:

upstream backend {
   server 127.0.0.1:8065;
   keepalive 32;
}

proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=mattermost_cache:10m max_size=3g inactive=120m use_temp_path=off;

server {
  listen 80;
  server_name   mattermost.xxxxxx.com;
  return 301 https://$server_name$request_uri;
}

server {
   listen 443 ssl http2;
   server_name    mattermost.xxxxxx.com;

   http2_push_preload on; # Enable HTTP/2 Server Push

   ssl on;
   ssl_certificate /etc/letsencrypt/live/xxxxxx.com/fullchain.pem;
   ssl_certificate_key /etc/letsencrypt/live/xxxxxx.com/privkey.pem;
   ssl_session_timeout 1d;

   # Enable TLS versions (TLSv1.3 is required upcoming HTTP/3 QUIC).
   ssl_protocols TLSv1.2 TLSv1.3;

   # Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
   # prevent replay attacks.
   #
   # @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
   ssl_early_data on;

   ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
   ssl_prefer_server_ciphers on;
   ssl_session_cache shared:SSL:50m;
   # HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
   add_header Strict-Transport-Security max-age=15768000;
   # OCSP Stapling ---
   # fetch OCSP records from URL in ssl_certificate and cache them
   ssl_stapling on;
   ssl_stapling_verify on;

   add_header X-Early-Data $tls1_3_early_data;

   location ~ /api/v[0-9]+/(users/)?websocket$ {
       proxy_set_header Upgrade $http_upgrade;
       proxy_set_header Connection "upgrade";
       client_max_body_size 50M;
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       client_body_timeout 60;
       send_timeout 300;
       lingering_timeout 5;
       proxy_connect_timeout 90;
       proxy_send_timeout 300;
       proxy_read_timeout 90s;
       proxy_http_version 1.1;
       proxy_pass http://backend;
   }

   location / {
       client_max_body_size 50M;
       proxy_set_header Connection "";
       proxy_set_header Host $http_host;
       proxy_set_header X-Real-IP $remote_addr;
       proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       proxy_set_header X-Forwarded-Proto $scheme;
       proxy_set_header X-Frame-Options SAMEORIGIN;
       proxy_buffers 256 16k;
       proxy_buffer_size 16k;
       proxy_read_timeout 600s;
       proxy_cache mattermost_cache;
       proxy_cache_revalidate on;
       proxy_cache_min_uses 2;
       proxy_cache_use_stale timeout;
       proxy_cache_lock on;
       proxy_http_version 1.1;
       proxy_pass http://backend;
   }
}

# This block is useful for debugging TLS v1.3. Please feel free to remove this
# and use the `$ssl_early_data` variable exposed by NGINX directly should you
# wish to do so.
map $ssl_early_data $tls1_3_early_data {
  "~." $ssl_early_data;
  default "";
}

Regards sir

1 Like

I see, thank you for providing that information - would you be able to send the contents of the /etc/nginx/mods-available/ folder? I’m curious if the Nginx module that uses this function is installed or not.

Hello sir,

/etc/nginx/modules-available/ is empty, however:

/usr/share/nginx/modules-available/ contains

mod-http-auth-pam.conf
mod-http-echo.conf
mod-http-image-filter.conf
mod-http-upstream-fair.conf
mod-mail.conf
mod-http-dav-ext.conf
mod-http-geoip.conf
mod-http-subs-filter.conf
mod-http-xslt-filter.conf
mod-stream.conf

and /etc/nginx/modules-enabled/ contains

50-mod-http-auth-pam.conf -> /usr/share/nginx/modules-available/mod-http-auth-pam.conf
50-mod-http-dav-ext.conf -> /usr/share/nginx/modules-available/mod-http-dav-ext.conf
50-mod-http-echo.conf -> /usr/share/nginx/modules-available/mod-http-echo.conf
50-mod-http-geoip.conf -> /usr/share/nginx/modules-available/mod-http-geoip.conf
50-mod-http-image-filter.conf -> /usr/share/nginx/modules-available/mod-http-image-filter.conf
50-mod-http-subs-filter.conf -> /usr/share/nginx/modules-available/mod-http-subs-filter.conf
50-mod-http-upstream-fair.conf -> /usr/share/nginx/modules-available/mod-http-upstream-fair.conf
50-mod-http-xslt-filter.conf -> /usr/share/nginx/modules-available/mod-http-xslt-filter.conf
50-mod-mail.conf -> /usr/share/nginx/modules-available/mod-mail.conf
50-mod-stream.conf -> /usr/share/nginx/modules-available/mod-stream.conf

I don’t see anything related to http_ssl_module in here. Does that mean it’s not installed?

I thought it was because when I do sudo nginx -V I got

nginx version: nginx/1.14.2
built with OpenSSL 1.1.1d  10 Sep 2019
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-m1Thpq/nginx-1.14.2=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/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 --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-m1Thpq/nginx-1.14.2/debian/modules/http-auth-pam --add-dynamic-module=/build/nginx-m1Thpq/nginx-1.14.2/debian/modules/http-dav-ext --add-dynamic-module=/build/nginx-m1Thpq/nginx-1.14.2/debian/modules/http-echo --add-dynamic-module=/build/nginx-m1Thpq/nginx-1.14.2/debian/modules/http-upstream-fair --add-dynamic-module=/build/nginx-m1Thpq/nginx-1.14.2/debian/modules/http-subs-filter

which contains --with-http_ssl_module.

Regards sir

You can update your nginx to 1.15 or later version, see official doc, the directive appeared in version 1.15.3.

1 Like