{
  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 =
          # sh
          ''
            # 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' 'unsafe-eval'; 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;
                extraConfig =
                  # sh
                  ''
                    client_max_body_size 50000M;
                    proxy_request_buffering off;
                    client_body_buffer_size 1024k;
                    proxy_read_timeout   2400s;
                    proxy_send_timeout   2400s;
                    send_timeout         2400s;
                  '';
              };
            };
        in
          mapAttrs' (name: port:
            nameValuePair "${name}.${cfg.domain}"
            # (proxy port // { default = true; })) cfg.ports;
            (proxy port))
          cfg.ports;
      };
    };
  }
