{ config, lib, pkgs, this, ... }: let cfg = config.nixfiles.modules.nginx; in { options.nixfiles.modules.nginx = { enable = lib.mkEnableOption "Nginx"; upstreams = lib.mkOption { description = "Defines a group of servers to use as proxy target."; type = lib.types.anything; default = null; }; virtualHosts = lib.mkOption { description = "Attrset of virtual hosts."; type = lib.types.anything; default = null; }; }; config = lib.mkIf cfg.enable { _module.args.libNginx.config = { internalOnly = '' if ($internal != 1) { return 403; } access_log off; ''; noAICrawlers = '' if ($crawler != 0) { return 403; } ''; appendHead = text: '' brotli off; gzip off; zstd off; sub_filter '' '${lib.concatStrings text}'; sub_filter_once on; ''; noProxyBuffering = '' proxy_buffering off; proxy_cache off; ''; }; services = { nginx = { enable = true; enableReload = true; package = pkgs.nginxMainline; statusPage = lib.mkDefault true; recommendedOptimisation = lib.mkDefault true; recommendedProxySettings = lib.mkDefault true; recommendedTlsSettings = lib.mkDefault true; recommendedBrotliSettings = lib.mkDefault true; recommendedGzipSettings = lib.mkDefault true; recommendedZstdSettings = lib.mkDefault true; resolver.addresses = let isIPv6 = addr: builtins.match ".*:.*:.*" addr != null; escapeIPv6 = addr: if isIPv6 addr then "[${addr}]" else addr; resolvers = if config.networking.nameservers != [ ] then config.networking.nameservers else lib.dns.const.quad9.default; in map escapeIPv6 resolvers; commonHttpConfig = lib.concatStrings [ '' access_log syslog:server=unix:/dev/log; map $http_user_agent $crawler { default 0; ${ pkgs.fetchurl { url = "https://raw.githubusercontent.com/ai-robots-txt/ai.robots.txt/5e7c3c432f8bad894363c7289b888328f98963f3/robots.json"; hash = "sha256-purIvhot5wNyQH2fYrwQ8E/WaO/EYdOeqxQM5xLb8zA="; } |> builtins.readFile |> builtins.fromJSON |> lib.mapAttrsToList (n: _: "'${n}' 1;") |> lib.concatLines } } '' (lib.optionalString (lib.hasAttr "wireguard" this) ( with config.nixfiles.modules.wireguard; '' geo $internal { default 0; 127.0.0.1/32 1; ::1/128 1; ${ipv4.subnet} 1; ${ipv6.subnet} 1; } '' )) ]; inherit (cfg) upstreams; virtualHosts = { default = { default = true; rejectSSL = true; locations."/".return = "444"; }; } // (lib.mkIf (cfg.virtualHosts != null) ( lib.mapAttrs ( _: attr: lib.mkMerge [ attr (lib.mkIf config.nixfiles.modules.acme.enable { enableACME = lib.mkDefault true; forceSSL = lib.mkDefault true; }) ] ) cfg.virtualHosts )); sslDhparam = config.security.dhparams.params.nginx.path; }; fail2ban.jails = { nginx-http-auth.enabled = true; nginx-botsearch.enabled = true; }; prometheus.exporters = { nginx = { enable = true; listenAddress = "127.0.0.1"; port = 9113; }; nginxlog = { enable = false; listenAddress = "127.0.0.1"; port = 9117; group = "nginx"; settings.namespaces = [ { source.syslog = { # TODO }; } ]; }; }; }; systemd.services.alloy.reloadTriggers = [ config.environment.etc."alloy/nginx.alloy".source ]; environment.etc."alloy/nginx.alloy".text = with config.services.prometheus.exporters.nginx; '' prometheus.scrape "nginx" { targets = [ { __address__ = "${listenAddress}:${toString port}", instance = "${config.networking.hostName}", }, ] forward_to = [prometheus.relabel.default.receiver] } ''; security.dhparams = { enable = true; params.nginx = { }; }; networking.firewall.allowedTCPPorts = [ 80 443 ]; }; }