# Copyright © 2020 Interplanetary Database Association e.V.,
# Planetmint and IPDB software contributors.
# SPDX-License-Identifier: (Apache-2.0 AND CC-BY-4.0)
# Code is Apache-2.0 and docs are CC-BY-4.0

# NOTE: You must replace example.testnet2.com
# with your node's actual DNS name in TWO PLACES below.

# Frontend API server
worker_processes 4;
user nobody nogroup;
error_log /var/log/nginx/error.log;

events {
  # Each worker handles up to 512 connections. Increase this for heavy
  # workloads.
  worker_connections 64;
  accept_mutex on;
  use epoll;
}

http {
  access_log /var/log/nginx/access.log combined buffer=16k flush=5s;

  # Allow 10 req/sec from the same IP address, and store the counters in a
  # `zone` or shared memory location tagged as 'one'.
  limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;

  # Enable logging when requests are being throttled.
  limit_req_log_level notice;

  # HTTP status code that is returned to the client; 429 is for TooManyRequests,
  # ref. RFC 6585
  limit_req_status 429;

  # Limit requests from the same client, allow `burst` to 20 r/s,
  # `nodelay` or drop connection immediately in case it exceeds this
  # threshold.
  limit_req zone=one burst=20 nodelay;

  # `slowloris` attack mitigation settings.
  client_body_timeout 10s;
  client_header_timeout 10s;

  # Do not expose NGINX data/version number in error response and header
  server_tokens off;

  # To prevent cross-site scripting
  add_header X-XSS-Protection "1; mode=block";

  keepalive_timeout 60s;

  # Frontend server for the external clients; acts as HTTPS termination point.
  server {
    listen 443 ssl;
    server_name "example.testnet2.com";

    ssl_certificate /etc/nginx/ssl/cert.pem;
    ssl_certificate_key /etc/nginx/ssl/cert.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    underscores_in_headers on;

    # Forward websockets directly to backend BDB.
    location /api/v1/streams/valid_transactions {
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      proxy_pass http://localhost:9985;
      proxy_read_timeout 600s;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "upgrade";
    }

    # Forward other URL paths as per business logic/use case to BDB
    location / {
      proxy_ignore_client_abort on;
      proxy_set_header X-Real-IP  $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # max client request body size: average transaction size.
      client_max_body_size 15k;

      # GET requests are forwarded to BDB.
      if ($request_method = GET) {
        proxy_pass http://localhost:9984;
      }

      # POST requests: Enable CORS then forward to BDB.
      if ($request_method = POST) {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
        add_header 'Access-Control-Expose-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';

        proxy_pass http://localhost:9984;
      }

      # OPTIONS requests: Enable CORS and return 204.
      if ($request_method = 'OPTIONS') {
          add_header 'Access-Control-Allow-Origin' '*';
          add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
          add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Content-Range,Range';
          add_header 'Access-Control-Max-Age' 43200;
          add_header 'Content-Type' 'text/plain charset=UTF-8';
          add_header 'Content-Length' 0;
          return 204;
      }

      # Only return this response if request_method is neither POST|GET|OPTIONS
      if ($request_method !~ ^(GET|OPTIONS|POST)$) {
          return 444;
      }
    }
  }

  # Frontend server for the load balancer to respond to health checks.
  server {
    listen 9000;

    location = /health {
      return 200;
    }
  }

  # Frontend server for the external clients; returns a pretty error message
  # when an HTTP request is sent instead of HTTPS.
  server {
      listen 80;
      server_name "example.testnet2.com";

      location / {
          add_header Upgrade "TLS/1.2, HTTP/1.1" always;
          default_type text/plain;
          return 426 'Consider using the HTTPS protocol next time!';
      }
  }
}