Setup behind Nginx reverse proxy

Packages

Install Nginx and Let’s Encrypt Certbot:

apt install nginx certbot

Nginx

/etc/nginx/snippets/ssl/common.conf:

# A universal location overlay for the Let's Encrypt ACME challenge protocol
location /.well-known {
    alias /var/www/html/.well-known;
}

# Enable session resumption to improve https performance
# http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 5m;

# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits
# openssl dhparam -out /etc/nginx/dhparam.pem 2048
ssl_dhparam /etc/nginx/dhparam.pem;

# Enable server-side protection from BEAST attacks
# http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html
ssl_prefer_server_ciphers on;

# Disable SSLv3 (enabled by default since nginx 0.8.19) since it's less secure than TLS
# http://en.wikipedia.org/wiki/Secure_Sockets_Layer
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

# Chrome says "obsolete cipher suite" [system default]
#ssl_ciphers AES:HIGH:!ADH:!MD5;

# Chrome says "obsolete" to both cipher suites [janosch]
#ssl_ciphers TLSv1.2+HIGH+AES256:TLSv1+HIGH+AES256:@STRENGTH:!kECDHe:!aECDSA:!aNULL:!eNULL:!PSK:!SRP:!DSS;
#ssl_ciphers TLSv1.2+HIGH+AES256:TLSv1.2+HIGH+AES128:TLSv1+HIGH+AES256:TLSv1+HIGH+AES128:@STRENGTH:!kECDHe:!aECDSA:!aNULL:!eNULL:!PSK:!SRP:!DSS;

# Ciphers chosen for forward secrecy and compatibility, Chrome says "modern cipher suite"
# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html
#ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';
# Without RC4:
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';

# These are very agressive rules
# https://www.scalescale.com/tips/nginx/hardening-nginx-ssl-tsl-configuration/
#ssl_ciphers 'ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4';

# Communicate with encryption only
#add_header Strict-Transport-Security max-age=15768000;
#add_header Strict-Transport-Security max-age=5;

/etc/nginx/snippets/ssl/kotori.example.org.conf:

# SSL certificate and key file
ssl_certificate     /etc/letsencrypt/live/kotori.example.org/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/kotori.example.org/privkey.pem;

# Redirect all requests to https
if ($server_port = 80) {
    #rewrite ^ https://$host$request_uri;
    rewrite (.*) https://$http_host$1;
}

/etc/nginx/sites-available/kotori.example.org.conf:

server {

    # Your server name
    server_name kotori.example.org;

    # Listen on regular webserver port
    listen 80;

    # Enable SSL
    listen 443 ssl;
    # Best-practice SSL configuration
    include snippets/ssl/common.conf;
    #include snippets/ssl/kotori.example.org.conf;

    # Configure Kotori and friends
    include snippets/kotori-daq.conf;

    # Redirect "/" to Grafana
    location = / {
        rewrite ^ /grafana/ redirect;
    }

    # Log files
    access_log /var/log/nginx/kotori.example.org.access.log combined;
    error_log /var/log/nginx/kotori.example.org.error.log;

    # Performance parameters
    # Relax "414 Request-URI Too Large"
    large_client_header_buffers 6 16k;

}

/etc/nginx/snippets/kotori-daq.conf:

# Serve Grafana
location /grafana/ {
    proxy_set_header   Host $host;

    rewrite  ^/grafana/(.*)  /$1 break;
    proxy_pass http://localhost:3000;


    # Performance parameters

    # Relax "413 Request Entity Too Large"
    client_max_body_size 20M;

    # If upstream is slow
    proxy_send_timeout          5m;
    proxy_read_timeout          5m;

    # If downstream is slow
    #client_header_timeout 3m;
    client_body_timeout 5m;
    send_timeout 5m;
}

# Serve Kotori HTTP API
location /api {
    proxy_set_header   Host $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;

    #rewrite  ^//(.*)  /$1 break;
    proxy_pass http://localhost:24642/api;


    # Performance parameters

    # Relax "413 Request Entity Too Large"
    client_max_body_size 20M;

    # Relax "414 Request-URI Too Large"
    large_client_header_buffers 6 16k;

    # If upstream is slow
    proxy_send_timeout          5m;
    proxy_read_timeout          5m;

    # If downstream is slow
    #client_header_timeout 3m;
    client_body_timeout 5m;
    send_timeout 5m;
}

Grafana

/etc/grafana/grafana.ini:

[server]

# Protocol (http or https)
protocol = http

# The ip address to bind to, empty will bind to all interfaces
http_addr = localhost

# The public facing domain name used to access grafana from a browser
domain = kotori.example.org

# The full public facing url
root_url = %(protocol)s://%(domain)s/grafana/
systemctl restart grafana-server

Let’s Encrypt

ln -sr /etc/nginx/sites-available/weather.hiveeyes.org.conf /etc/nginx/sites-enabled/

openssl dhparam -out /etc/nginx/dhparam.pem 2048

nginx -t
systemctl reload nginx

certbot register --email 'operations@example.org'
certbot certonly --webroot --domains weather.e-habit.at --webroot-path /var/www/html