# Sources for this configuration:
# - https://www.dokuwiki.org/dokuwiki
# - https://www.dokuwiki.org/install
# - https://www.dokuwiki.org/requirements
# - https://www.dokuwiki.org/install:php
# - https://www.dokuwiki.org/security
# - https://www.dokuwiki.org/config:xsendfile
# - https://www.dokuwiki.org/install:nginx
# - https://www.dokuwiki.org/faq:uploadsize
# - https://nixos.wiki/wiki/Phpfpm
# - https://wiki.archlinux.org/title/Nginx#FastCGI
# - https://github.com/NixOS/nixpkgs/blob/84c0cb1471eee15e77ed97e7ae1e8cdae8835c61/nixos/modules/services/web-apps/dokuwiki.nix
# - https://git.hamburg.ccc.de/CCCHH/ansible-infra/src/commit/81c8bfe16b311d5bf4635947fa02dfb65aea7f91/playbooks/files/chaosknoten/configs/wiki/nginx/wiki.hamburg.ccc.de.conf
# - https://www.php.net/manual/en/install.fpm.php
# - https://www.php.net/manual/en/install.fpm.configuration.php

{ config, pkgs, ... }:

let
  # This is also used for user and group names.
  app = "dokuwiki";
  domain = "eh22.easterhegg.eu";
  dataDir = "/srv/www/${domain}";
in
{
  systemd.tmpfiles.rules = [
    "d ${dataDir} 0755 ${app} ${app}"
  ];

  services.phpfpm.pools."${app}" = {
    user = "${app}";
    group = "${app}";
    phpOptions = ''
      short_open_tag = Off
      open_basedir =
      output_buffering = Off
      output_handler =
      zlib.output_compression = Off
      implicit_flush = Off
      allow_call_time_pass_reference = Off
      max_execution_time = 30
      max_input_time = 60
      max_input_vars = 10000
      memory_limit = 128M
      error_reporting = E_ALL & ~E_NOTICE
      display_errors = Off
      display_startup_errors = Off
      log_errors = On
      ; error_log should be handled by NixOS.
      variables_order = "EGPCS"
      register_argc_argv = Off
      file_uploads = On
      upload_max_filesize = 20M
      post_max_size = 20M
      session.use_cookies = 1
      ; Checked the default NixOS PHP extensions and the only one missing from
      ; DokuWikis list of PHP extensions was bz2, so add that.
      ; Checked with NixOS 23.11 on 2024-05-02.
      extension = ${pkgs.phpExtensions.bz2}/lib/php/extensions/bz2.so
    '';
    settings = {
      "listen.owner" = "${config.services.nginx.user}";
      "listen.group" = "${config.services.nginx.group}";
      "pm" = "dynamic";
      "pm.max_children" = 32;
      "pm.start_servers" = 2;
      "pm.min_spare_servers" = 2;
      "pm.max_spare_servers" = 4;
      "pm.max_requests" = 500;
    };
  };

  services.nginx = {
    enable = true;

    virtualHosts."acme-${domain}" = {
      default = true;
      enableACME = true;
      serverName = "${domain}";

      listen = [
        {
          addr = "0.0.0.0";
          port = 31820;
        }
      ];
    };

    virtualHosts."${domain}" = {
      default = true;
      forceSSL = true;
      useACMEHost = "${domain}";

      listen = [
        {
          addr = "0.0.0.0";
          port = 8443;
          ssl = true;
          proxyProtocol = true;
        }
      ];

      root = "${dataDir}";

      locations = {
        "~ /(conf|bin|inc|vendor)/" = {
          extraConfig = "deny all;";
        };

        "~ /install.php" = {
          extraConfig = "deny all;";
        };

        "~ ^/data/" = {
          extraConfig = "internal;";
        };

        "~ ^/lib.*\.(js|css|gif|png|ico|jpg|jpeg)$" = {
          extraConfig = "expires 31d;";
        };

        "/" = {
          index = "doku.php";
          extraConfig = "try_files $uri $uri/ @dokuwiki;";
        };

        "@dokuwiki" = {
          extraConfig = ''
            # Rewrites "doku.php/" out of the URLs if the userwrite setting is
            # set to .htaccess in the DokuWiki config page.
            rewrite ^/_media/(.*) /lib/exe/fetch.php?media=$1 last;
            rewrite ^/_detail/(.*) /lib/exe/detail.php?media=$1 last;
            rewrite ^/_export/([^/]+)/(.*) /doku.php?do=export_$1&id=$2 last;
            rewrite ^/(.*) /doku.php?id=$1&$args last;
          '';
        };

        "~ \\.php$" = {
          extraConfig = ''
            try_files $uri $uri/ /doku.php;
            include ${config.services.nginx.package}/conf/fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_param REDIRECT_STATUS 200;
            fastcgi_pass unix:${config.services.phpfpm.pools."${app}".socket};
          '';
        };
      };

      extraConfig = ''
        # Set maximum file upload size to 20MB (same as upload_max_filesize and
        # post_max_size in the phpOptions).
        client_max_body_size 20M;
        client_body_buffer_size 128k;
      '';
    };
  };

  networking.firewall.allowedTCPPorts = [ 8443 31820 ];
  networking.firewall.allowedUDPPorts = [ 8443 ];

  users.users."${app}" = {
    isSystemUser = true;
    group = "${app}";
  };
  users.groups."${app}" = { };
}