{ me, config, pkgs, lib, util, cloudflare-ips-v4, cloudflare-ips-v6, ... }: let inherit (lib) mergeAttrsList mkIf mkEnableOption mkOption concatMapStrings concatLines splitString ; inherit (config.age) secrets; cfg = config.foundation.www; rnrdUrl = if me.is.renard then "rnrd.eu" else "${me.name}.rnrd.eu"; default-page-index = pkgs.substituteAll { src = ../../../assets/base.html; env.me = util.titleCase me.name; }; default-page-index-w-goat = pkgs.concatText "base.html" [ default-page-index ../../../assets/goat.html ]; default-page = pkgs.linkFarm "www-base" { "index.html" = default-page-index-w-goat; "favicon.png" = ../../../assets/favicon.png; }; certificate = domain: { ${domain} = { domain = "*.${domain}"; extraDomainNames = [ domain ]; dnsProvider = "cloudflare"; credentialFiles = { CLOUDFLARE_DNS_API_TOKEN_FILE = secrets.cloudflare-dns.path; }; }; }; defaultHost = domain: certificate: base: log: { default = true; serverName = domain; forceSSL = true; useACMEHost = certificate; root = base; extraConfig = '' access_log /var/log/nginx/${log}.access.log json_combined; ''; }; in { imports = [ ./tailnet.nix ]; options.foundation.www = { enable = mkEnableOption "www server"; public = mkEnableOption "public access through rnrd.eu url"; defaultPage = mkOption { type = lib.types.package; default = default-page; }; }; config = mkIf cfg.enable { age.secrets = { cloudflare-dns.file = ../../../secrets/cloudflare-dns.age; }; security.acme = { acceptTerms = true; # this sometimes causes issues with tailnet certificates, # but otherwise nginx does not want to launch with how i've configured it. # TODO if tailscale cert generation is failing again, investigate. preliminarySelfsigned = true; defaults = { email = "mel@rnrd.eu"; # our certificates are really only used with Nginx group = config.services.nginx.group; reloadServices = [ "nginx.service" ]; }; # yes, we generate both certificates, even if they are not # used by every machine, but as long as it doesn't cause # any problems... :) certs = mergeAttrsList [ (certificate "rnrd.eu") (certificate "rnrd.fyi") ]; }; services.nginx = { enable = true; recommendedGzipSettings = true; recommendedOptimisation = true; recommendedProxySettings = true; recommendedTlsSettings = true; statusPage = true; commonHttpConfig = let logs = '' log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status": "$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_length":"$request_length",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent",' '"upstream_response_time":"$upstream_response_time",' '"upstream_addr":"$upstream_addr",' '"upstream_status":"$upstream_status",' '"cf_connecting_ip":"$http_cf_connecting_ip"' '}'; access_log /var/log/nginx/access.log json_combined; error_log /var/log/nginx/error.log warn; ''; cloudflareAddresses = builtins.filter (ip: ip != "") ( splitString "\n" '' ${builtins.readFile cloudflare-ips-v4} ${builtins.readFile cloudflare-ips-v6} '' ); realIpLine = ip: "set_real_ip_from ${ip};\n"; cloudflare = '' ${concatMapStrings realIpLine cloudflareAddresses} real_ip_header CF-Connecting-IP; ''; in concatLines [ logs cloudflare ]; virtualHosts = { base = mkIf cfg.public (defaultHost rnrdUrl "rnrd.eu" cfg.defaultPage "base"); }; }; }; }