Nginx reverse proxy with Let's Encrypt

This guide describes how an existing Elasticsearch server can be secured using an Nginx reverse proxy via a native HTTPS connection on port 443 with a Let's Encrypt certificate.

Prerequisites

  • Active Elasticsearch Server
  • No installed service on port 80 or 443
  • SSH root access to the Elasticsearch Server

Preparation

First log in to the Elasticsearch Server via SSH to carry out the further configuration steps. If you did not store a public SSH key for the server when you ordered the server, you can retrieve the access data via the Customer Center under the menu item Server โ†’ Virtual servers โ†’ Access data.



In this guide, the reverse proxy for the Elasticsearch server sXXXXX.creolineserver.com is set up. Please adjust the hostname in all following configuration files accordingly.



Log in to the server via SSH with the root user:

ssh root@sXXXXX.creolineserver.com


Nginx installation

By using Nginx, a Let's Encrypt certificate can be configured in addition to the HTTPS connection on port 443, which is automatically renewed before it expires.


apt update && apt install curl gnupg2 ca-certificates lsb-release

# Install the official Nginx repository
wget -qO - http://nginx.org/packages/keys/nginx_signing.key | apt-key add -
echo "deb http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" | tee /etc/apt/sources.list.d/nginx.list

# Installation of the nginx web server
apt update && apt install nginx



After the installation, you can use systemctl to check whether the Nginx server has been successfully installed and started.

systemctl status nginx

โ— nginx.service - nginx - high performance web server
   Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
   Active: active (running) since Wed 2021-09-22 16:01:18 CEST; 6s ago



Nginx configuration

Deactivate the default host configuration with the following command:

mv /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.disabled


Then add a new configuration file with the following command:

nano /etc/nginx/conf.d/elasticsearch-proxy.conf



server {
    listen 80;
    server_name localhost sXXXXX.creolineserver.com;

    location / {
        proxy_pass http://127.0.0.1:9200;
        proxy_read_timeout 60;
        proxy_connect_timeout 60;
        proxy_buffering off;
        client_max_body_size 100M;

        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
    }
}


If you have changed the Elasticsearch HTTP API port, this must be adjusted accordingly in the NGINX configuration.


Then check the configuration for syntax errors and reload the Nginx configuration so that your changes take effect.

nginx -t

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

systemctl reload nginx



Let's Encrypt installation

Install the Certbot package to be able to issue Let's Encrypt certificates:


apt update && apt install certbot python3-certbot-nginx



Let's Encrypt configuration

After successfully installing the Certbot package, you can issue the required SSL certificate using the certbot command.


If you are using the certbot command for the first time, you must enter an e-mail address for expiry notifications or important security information.


certbot --nginx -d sXXXXX.creolineserver.com
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Enter email address (used for urgent renewal and security notices) (Enter 'c' to
cancel): info@creoline.de

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N

Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2

Obtaining a new certificate
Performing the following challenges:
http-01 challenge for sXXXXX.creolineserver.com
Using default address 80 for authentication.
Waiting for verification...
Cleaning up challenges

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://sXXXXX.creolineserver.com

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=sXXXXX.creolineserver.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Agree to HTTPS redirection if you want to automatically redirect incoming traffic on port 80 (HTTP) to port 443 (HTTPS).



Automatic renewal of SSL certificates

The certbot package already includes the certbot.service and the certbot.timer for automatic renewal, so that a manual cronjob is no longer required.


If the two systemd services are not to be used by certbot, the certbot package can also be triggered twice a day via cronjob using crontab -e:


52 0.12 * * * certbot renew --post-hook "nginx -t && systemctl reload nginx"


The cronjob is only necessary if the systemd services certbot.service and certbot.timer have been deactivated.



Firewall configuration

Direct Elasticsearch access can then be blocked via the Cloud-Firewall so that all future HTTP requests must be sent exclusively via the Nginx proxy.

To do this, create a new firewall rule that allows incoming TCP communication on ports 80 and 443 and block the remaining incoming traffic using another rule.



Please note that additional rules are required to access Kibana. If your application server has a static IP address, it is recommended to enable HTTP and HTTPS communication exclusively from the source address of the application server.



Test HTTP(S) requests

You can use curl to check whether the configuration was successful and the Nginx proxy works as desired.


curl https://sXXXXX.creolineserver.com
{
  "name" : "sXXXXX.creolineserver.com",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "Mi_bhUolSw2UTHTnVNoKZA",
  "version" : {
    "number" : "7.14.2",
    "build_flavor" : "default",
    "build_type" : "deb",
    "build_hash" : "6bc13727ce758c0e943c3c21653b3da82f627f75",
    "build_date" : "2021-09-15T10:18:09.722761972Z",
    "build_snapshot" : false,
    "lucene_version" : "8.9.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}



If you have activated HTTPS forwarding in the Let's Encrypt configuration, you can also test the forwarding:


curl -I http://sXXXXX.creolineserver.com

HTTP/1.1 301 Moved Permanently
Server: nginx/1.21.3
Date: Wed, 22 Sep 2021 15:12:31 GMT
Content-Type: text/html
Content-Length: 169
Connection: keep-alive
Location: https://sXXXXX.creolineserver.com


The HTTP status code 301 and the Location header of the response indicate that the HTTPS forwarding is working properly.


The Elasticsearch server can now be addressed by your application via https:// without specifying a port.



Disable Nginx version in HTTP responses

In the standard configuration of Nginx, the Nginx version used is returned in the server header in every HTTP response. This behavior can be deactivated via nginx.conf.


To do this, edit the file /etc/nginx/nginx.conf and add the parameter server_tokens off; in the http block.


user nginx;
worker_processes auto;

error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      ' '$http_user_agent' "$http_x_forwarded_for"';

    access_log /var/log/nginx/access.log main;

    sendfile on;
    keepalive_timeout 65;
    server_tokens off;

    include /etc/nginx/conf.d/*.conf;
}


The Nginx server configuration must be reloaded for the changes to take effect:


nginx -t && systemctl reload nginx


The Nginx version used is then hidden in the HTTP responses:


curl -I https://sXXXXX.creolineserver.com

HTTP/1.1 200 OK
Server: nginx
Date: Thu, 23 Sep 2021 06:11:34 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 554
Connection: keep-alive
X-elastic-product: Elasticsearch