{ pkgs, lib, config, ... }:
let

  cfg = config.mods.server.nginx;

in with lib; {
  options.mods.server.nginx = {
    enable = mkEnableOption {
      default = false;
      description = "enables nginx reverse proxy";
    };

    ip = mkOption {
      type = types.str;
      default = "10.0.0.3";
    };

    domain = mkOption {
      type = types.str;
      default = "muon.host";
    };

    ports = mkOption {
      type = types.attrsOf (types.ints.u16);
      default = { };
    };
  };

  config = mkIf cfg.enable {
    # ACME won't be able to authenticate your domain
    # if ports 80 & 443 aren't open in your firewall.
    networking.firewall = { allowedTCPPorts = [ 443 80 ]; };
    security.acme.defaults.email = "acme@muon.host";
    security.acme.acceptTerms = true;

    services.nginx = {
      enable = true;

      recommendedGzipSettings = true;
      recommendedOptimisation = true;
      recommendedProxySettings = true;
      recommendedTlsSettings = true;

      # Only allow PFS-enabled ciphers with AES256
      # sslCiphers = "AES256+EECDH:AES256+EDH:!aNULL";

      appendHttpConfig = ''
        # Add HSTS header with preloading to HTTPS requests.
        # Adding this header to HTTP requests is discouraged
        # 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;

        # This might create errors
        # proxy_cookie_path / "/; secure; HttpOnly; SameSite=strict";

        # required when the server wants to use HTTP Authentication
        proxy_pass_header Authorization;

        # This is necessary to pass the correct IP to be hashed
        real_ip_header X-Real-IP;

        # security
        add_header X-XSS-Protection          "1; mode=block" always;
        add_header X-Content-Type-Options    "nosniff" always;
        add_header Referrer-Policy           "no-referrer-when-downgrade" always;
        add_header Content-Security-Policy   "default-src 'self' http: https: ws: wss: data: blob: 'unsafe-inline'; frame-ancestors 'self';" always;
        add_header Permissions-Policy        "interest-cohort=()" always;
        # add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
      '';

      virtualHosts = let
        base = locations: {
          inherit locations;

          forceSSL = true;
          enableACME = true;
        };
        proxy = port:
          base {
            "/" = {
              proxyPass = "http://${cfg.ip}:${toString port}/";
              proxyWebsockets = true;
            };
          };
      in mapAttrs' (name: port:
        nameValuePair ("${name}.${cfg.domain}")
        # (proxy port // { default = true; })) cfg.ports;
        (proxy port)) cfg.ports;
    };
  };
}
