From 53dd7dfb46a35b1cc0d31dc3b14566398af3f5b0 Mon Sep 17 00:00:00 2001
From: Julien Moutinho <julm@sourcephile.fr>
Date: Wed, 11 Mar 2020 23:35:20 +0100
Subject: [PATCH] nginx: add microcaching to gitweb

---
 servers/mermet.nix                          |  3 +-
 servers/mermet/nginx.nix                    | 74 ++++++++++++---------
 servers/mermet/nginx/sourcephile.fr/git.nix | 17 ++++-
 3 files changed, 60 insertions(+), 34 deletions(-)

diff --git a/servers/mermet.nix b/servers/mermet.nix
index e9de9f2..1018f9b 100644
--- a/servers/mermet.nix
+++ b/servers/mermet.nix
@@ -89,10 +89,11 @@ in
       cryptsetup
       direnv
       file
-      gdb
       fio
+      gdb
       git
       gptfdisk
+      #hey
       lm_sensors
       rsync
       smartctl-tbw
diff --git a/servers/mermet/nginx.nix b/servers/mermet/nginx.nix
index 1ab8d6e..33c7abb 100644
--- a/servers/mermet/nginx.nix
+++ b/servers/mermet/nginx.nix
@@ -26,6 +26,16 @@ options = {
       type    = types.str;
       default = "/var/log/nginx";
     };
+    configs = lib.mkOption {
+      type = types.attrsOf types.lines;
+      default = {};
+      description = ''
+        Make some configs available to all virtual hosts.
+        Useful to workaround the reset of add_header:
+        https://blog.g3rt.nl/nginx-add_header-pitfall.html
+      '';
+      #apply = lib.mapAttrs (name: pkgs.writeText "${name}.conf");
+    };
   };
 };
 config = {
@@ -68,6 +78,33 @@ config = {
     #sslCiphers = "EECDH+aRSA+AESGCM:EDH+aRSA:EECDH+aRSA:+AES256:+AES128:+SHA1:!CAMELLIA:!SEED:!3DES:!DES:!RC4:!eNULL";
     sslDhparam = ../../../sec/openssl/dh.pem;
     sslProtocols = "TLSv1.3 TLSv1.2";
+    configs = rec {
+      http_add_headers = ''
+        # Add HSTS header with preloading to HTTPS requests.
+        # Adding this header to HTTP requests is discouraged
+        # DOC: https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server
+        add_header Strict-Transport-Security $hsts_header;
+
+        # Enable CSP for your services.
+        #add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
+
+        # Minimize information leaked to other domains
+        add_header 'Referrer-Policy' 'origin-when-cross-origin';
+
+        # Disable embedding as a frame
+        add_header X-Frame-Options DENY;
+
+        # Prevent injection of code in other mime types (XSS Attacks)
+        add_header X-Content-Type-Options nosniff;
+
+        # Enable XSS protection of the browser.
+        # May be unnecessary when CSP is configured properly (see above)
+        add_header X-XSS-Protection "1; mode=block";
+      '';
+      https_add_headers = ''
+        ${http_add_headers}
+      '';
+    };
     commonHttpConfig = ''
       log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                       '$status $body_bytes_sent "$http_referer" '
@@ -99,29 +136,7 @@ config = {
         security = ''
           #error_page 403 = 404;
 
-          # Add HSTS header with preloading to HTTPS requests.
-          # Adding this header to HTTP requests is discouraged
-          # DOC: https://blog.qualys.com/securitylabs/2016/03/28/the-importance-of-a-proper-http-strict-transport-security-implementation-on-your-web-server
-          map $scheme $hsts_header {
-              https   "max-age=31536000; includeSubdomains; preload";
-          }
-          add_header Strict-Transport-Security $hsts_header;
-
-          # Enable CSP for your services.
-          #add_header Content-Security-Policy "script-src 'self'; object-src 'none'; base-uri 'none';" always;
-
-          # Minimize information leaked to other domains
-          add_header 'Referrer-Policy' 'origin-when-cross-origin';
-
-          # Disable embedding as a frame
-          add_header X-Frame-Options DENY;
-
-          # Prevent injection of code in other mime types (XSS Attacks)
-          add_header X-Content-Type-Options nosniff;
-
-          # Enable XSS protection of the browser.
-          # May be unnecessary when CSP is configured properly (see above)
-          add_header X-XSS-Protection "1; mode=block";
+          ${nginx.configs.http_add_headers}
 
           # This might create errors
           proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";
@@ -144,14 +159,6 @@ config = {
           fastcgi_buffers 256 4k;
           fastcgi_busy_buffers_size 256k;
           fastcgi_cache_key "$request_method $scheme://$http_host$request_uri";
-          fastcgi_cache_path ${nginx.stateDir}/fastcgi_cache
-                             inactive=10m
-                             keys_zone=microcache:2M
-                             levels=1:2
-                             loader_files=100000
-                             loader_sleep=1
-                             loader_threshold=2592000000
-                             max_size=64M;
           fastcgi_connect_timeout 60;
           fastcgi_ignore_client_abort off;
           fastcgi_intercept_errors on;
@@ -183,6 +190,11 @@ config = {
             default 'date-not-found';
             '~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})' $year-$month-$day;
           }
+
+          map $scheme $hsts_header {
+            https  "max-age=31536000; includeSubdomains; preload";
+          }
+
           # User agents that are to be blocked.
           #map $http_user_agent $bad_bot {
           #  default 0;
diff --git a/servers/mermet/nginx/sourcephile.fr/git.nix b/servers/mermet/nginx/sourcephile.fr/git.nix
index b5f30b5..8023e4d 100644
--- a/servers/mermet/nginx/sourcephile.fr/git.nix
+++ b/servers/mermet/nginx/sourcephile.fr/git.nix
@@ -8,6 +8,13 @@ let
 in
 {
   services.nginx = {
+    commonHttpConfig = ''
+      fastcgi_cache_path ${nginx.stateDir}/fastcgi_cache:${domain}:${srv}
+                         keys_zone=${domain}/${srv}:2M
+                         inactive=10m
+                         levels=1:2
+                         max_size=32M;
+    '';
     virtualHosts."${srv}" = {
       serverName = "${srv}.${domain}";
       forceSSL = true;
@@ -20,8 +27,14 @@ in
         "/" = {
           extraConfig = ''
             include ${pkgs.nginx}/conf/fastcgi_params;
+            ${nginx.configs.https_add_headers}
+            add_header X-Cache $upstream_cache_status;
+            fastcgi_cache ${domain}/${srv};
+            fastcgi_cache_valid 200 10s;
+            fastcgi_cache_valid 404 30m;
+            fastcgi_max_temp_file_size 1M;
+            # Used by gitweb's pathinfo feature
             fastcgi_param PATH_INFO $fastcgi_script_name;
-             # NOTE: used by gitweb's pathinfo feature.
             fastcgi_param GITWEB_CONFIG ${gitweb.gitwebConfigFile};
             fastcgi_pass unix:${gitwebSocket};
           '';
@@ -106,7 +119,7 @@ in
       $favicon     =  "/static/git-favicon.png";
       $javascript  =  "/static/gitweb.js";
       $feature{'highlight'}{'default'} = [1];
-      # FIX: gitweb bug: FCGI is not Unicode aware.
+      # Fix a bug in Gitweb: FCGI is not Unicode aware.
       if ($first_request) {
           my $enc = Encode::find_encoding('UTF-8');
           my $org = \&FCGI::Stream::PRINT;
-- 
2.47.2